https://github.com/bhaskarblur/arcore-navigation-with-lat-long
This repository developed in Native Android - Java demonstrates how to place objects & draw routes between them in ARCore scene using Latitude & Longitude
https://github.com/bhaskarblur/arcore-navigation-with-lat-long
anchor android android-studio arcore-android gps hacktoberfest hacktoberfest-accepted hacktoberfest2023 indoor-navigation indoor-positioning java latitude-and-longitude navigation
Last synced: 15 days ago
JSON representation
This repository developed in Native Android - Java demonstrates how to place objects & draw routes between them in ARCore scene using Latitude & Longitude
- Host: GitHub
- URL: https://github.com/bhaskarblur/arcore-navigation-with-lat-long
- Owner: bhaskarblur
- License: mit
- Created: 2023-05-28T05:52:05.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-10-28T14:02:43.000Z (6 months ago)
- Last Synced: 2025-03-25T10:51:09.511Z (about 1 month ago)
- Topics: anchor, android, android-studio, arcore-android, gps, hacktoberfest, hacktoberfest-accepted, hacktoberfest2023, indoor-navigation, indoor-positioning, java, latitude-and-longitude, navigation
- Language: Java
- Homepage:
- Size: 58.9 MB
- Stars: 11
- Watchers: 1
- Forks: 5
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ARCore Navigation Anchors using LatLng in AR World - Android
This repository developed in Native Android - Java demonstrates how to place objects & draw routes between them in ARCore scene using Latitude & Longitude. The code doesn't require any use of Google Geospatial API or any such library.Developed by: Bhaskar Kaura (https://www.linkedin.com/in/bhaskar-kaura-300b09272/)
[app](app)
## How does this work?
This app uses ARCore with Sceneform to support AR & render objects in AR World. The current location of user is continuously calculated
and also the yaw(azimuth) aka the rotation of the device around it's -z axis which is respective to north. Now, we have our current
Latitude, Longitude & our rotation so we assume that we are an origin point on graph (0,0) and we added a Latitude & Longitude of a coordinate into the graph say it's (3,3). So, we convert this (3,3) via a CoordinateHelper class which converts LatLng into local coordinates using our current location, yaw and the target Location. Now we got the local coordinates, we set this as a LocalPosition
to our AnchorNode in AR World.## Accuracy?
This solution is pretty accurate as it doesnt rely on any external system and just requires user location & yaw. But, keep in mind that if the location LatLng & yaw of user is incorrect or inaccurate, then this may affect the resulted coordinates.## Examples

Anchor placed in AR World using LatLng

Route lines draw between different LatLng in AR World
## With this app you will be able to:
- Get current **user location & yaw**
- Convert entered **Latitude & Longitude** into local coordinates
- Place **anchor & object on LatLng** using coordinate converter in AR Scene
- **Draw routes between different LatLng** using coordinate converter in AR Scene## Getting Started
### Setup all the required dependencies
```
implementation ('es.situm:situm-sdk:2.85.3@aar') {
transitive = true
}
implementation 'com.google.android.gms:play-services-maps:18.1.0'
implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.17.1'
implementation 'com.github.appoly:ARCore-Location:1.2'
implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'de.javagl:obj:0.2.1'
implementation 'com.google.ar:core:1.31.0'
implementation 'com.google.ar.sceneform:core:1.17.1'
```### Setup Google Cloud Console Account & enable ArCore in it & make an API Key
### Add the required permissions and metadata of ArCore Api in Manifest file
### Enable ViewBinding in buildfeatures in Build Gradle file## Get user location
Using the code below, retrieve & update the current user location```
private LatLng currentLatLng =
new LatLng(0, 0);
private LocationManager locationManager;locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0L, (float) 0, new LocationListener() {
@Override
public void onLocationChanged(@NonNull Location location) {// this location LatLng can be highly inaccurate if being used in indoor location
// or places where it's hard to navigate, it is suggested to use special
// navigation systems like indoor navigation system for accurate results.// this inaccurate latlng can affect the coordinates of poi anchors, for testing
// try with a fixed current latlng on which you are currently placed.currentLatLng = new LatLng(location.getLatitude(), location.getLatitude());
binding.instrText.setText("Place your camera slightly next to your foot and tap on the
floor shadow to begin!");}
});
```## Get user yaw or the rotation
Using the code below, retrieve the device yaw or the azimuth```
private float I[] = null; //for magnetic rotational data
private float accels[] = new float[3];
private float mags[] = new float[3];
private float[] values = new float[3];
private float yaw;
private float pitch;
private float roll;
private SensorManager sensorManager;
private Sensor sensor;
//sensor manager & sensor required to calculate yaw
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);
```Inside OnResume() :
```
Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (accelerometer != null) {
sensorManager.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
}
Sensor magneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
if (magneticField != null) {
sensorManager.registerListener(this, magneticField,
SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
}
```Now, implement the SensorEventListener in activity class and add these functions
```
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
switch (sensorEvent.sensor.getType())
{
case Sensor.TYPE_MAGNETIC_FIELD:
mags = sensorEvent.values.clone();
break;
case Sensor.TYPE_ACCELEROMETER:
accels = sensorEvent.values.clone();
break;
}if (mags != null && accels != null) {
Rot = new float[9];
I= new float[9];
SensorManager.getRotationMatrix(Rot, I, accels, mags);// Correct if screen is in Landscape
float[] outR = new float[9];
SensorManager.remapCoordinateSystem(Rot, SensorManager.AXIS_X,SensorManager.AXIS_Z, outR);
SensorManager.getOrientation(outR, values);// here we calculated the final yaw(azimuth), roll & pitch of the device.
// multiplied by a global standard value to get accurate results// this is the yaw or the azimuth we need
yaw = values[0] * 57.2957795f;
pitch =values[1] * 57.2957795f;
roll = values[2] * 57.2957795f;//retrigger the loop when things are repopulated
mags = null;
accels = null;
}
}```
## Convert the Latitude & Longitude in Local Coordinates
This code will help you to convert your desired LatLng into local coordinates to place model on it. It uses
CoordinatesHelper class to do conversion. **Make sure you call this code inside OnTapPlane Listener.**```
// instantiating our cordinates helper class with our current coordinate
CoordinatesHelper cartesianHelper=new CoordinatesHelper(currentLatLng);
cartesianHelper.setCenter_(currentLatLng);// converting the LatLng coordinates of poi to local coordinates to get place in AR
Coordinate coordinate1 =
cartesianHelper.GetLocalCoordinates(new LatLng(
"Latitude", "Longitude"), yaw);
```## Place POI on the converted Local Coordinate
Below, we used onTapPlane to get information about our environment and set a node inside it. You can instantly place object
without tapping the plane by using OnUpdateListener of ArFragment ArFrame. **It is suggested to place first anchor on foot of user
or beneath the camera for best results**```
arFragment.setOnTapArPlaneListener(new BaseArFragment.OnTapArPlaneListener() {
@Override
public void onTapPlane(HitResult hitResult, Plane plane, MotionEvent motionEvent) {
if(!poiPlaced) {
// calling it here as we want to calculate coordinates only when tapped
convertCoordinates("Latitude", "Longitude");
Anchor anchor= hitResult.createAnchor();
AnchorNode anchorNode = new AnchorNode(anchor);// passing the coordinates of target from the list of coordinates,
// in your case you can set your own lat long and convert it into local coordinates,
// passing the anchorNode as the reference node to place other anchors in world.
// make sure you point the ar camera on your foot and then tap on ar shadow to place anchor
PlacePOIinRealWorld(coordinate1, anchorNode);}
}
});
```
```
private void PlacePOIinRealWorld(CartesianCoordinate coordinate, AnchorNode reference) {// prepare renderable model for POI
ModelRenderable.builder().
setSource(
ARActivity.this,
RenderableSource
.builder()
.setSource(ARActivity.this, Uri.parse(
poi_uri)
, RenderableSource.SourceType.GLTF2)
.setScale(.3f)
.build())
.setRegistryId(poi_uri)
.build()
.thenAccept(modelRenderable -> addPOIinScene( modelRenderable,reference, coordinate ))
.exceptionally(throwable -> {
Toast.makeText(ARActivity.this, "error:"+throwable.getCause(), Toast.LENGTH_SHORT).show();
return null;
});poiPlaced=true;
binding.instrText.setVisibility(View.GONE);
}private void addPOIinScene(ModelRenderable modelRenderable, AnchorNode reference, CartesianCoordinate targetCoordinate_) {
AnchorNode anchorNode1=new AnchorNode(null);
anchorNode1.setRenderable(modelRenderable);
arFragment.getArSceneView().getScene().addChild(anchorNode1);CartesianCoordinate Singlecoordinate= targetCoordinate_;
//set the position of your POI model based on the coordinates calculated by
// the coordinate convertor
anchorNode1.setLocalPosition(new Vector3(
(float) (reference.getLocalPosition().x+ Singlecoordinate.getX()),
reference.getLocalPosition().y+.15f,
(float) (reference.getLocalPosition().z-Singlecoordinate.getY())
));//set rotation if needed (optional)
anchorNode1.setLocalRotation(Quaternion.axisAngle(new Vector3(0f, -1f, 0f), 30f));Toast.makeText(ARActivity.this, "POI added in scene.", Toast.LENGTH_SHORT).show();
poiPlaced= true;
}```
## Draw routes between different LatLng with the converted Local Coordinate
Below, we used onTapPlane to get information about our environment and set a node inside it. You can instantly place object
without tapping the plane by using OnUpdateListener of ArFragment ArFrame. **It is suggested to place first anchor on foot of user
or beneath the camera for best results**```
arFragment.setOnTapArPlaneListener(new BaseArFragment.OnTapArPlaneListener() {
@Override
public void onTapPlane(HitResult hitResult, Plane plane, MotionEvent motionEvent) {
if(!routePlaced) {
// calling it here as we want to calculate coordinates only when tapped
addDatainPOIList();
Anchor anchor= hitResult.createAnchor();
AnchorNode anchorNode = new AnchorNode(anchor);DrawLinesBetweenPOIs(anchorNode, false);
for(int i=0; i getApplicationContext().getAssets().open("arrow_texture.png"))
.setSampler(sampler)
.build().thenAccept(texture -> {
MaterialFactory.makeTransparentWithTexture(getApplicationContext(), texture) //new Color(0, 255, 244))
.thenAccept(
material -> {ModelRenderable model = ShapeFactory.makeCube(
new Vector3(.3f, .006f, difference.length()),
Vector3.zero(), material);AnchorNode node = new AnchorNode();
node.setParent(anchorNode);
node.setRenderable(model);
node.setWorldPosition(Vector3.add(point1, point2).scaled(.5f));
node.setWorldRotation(rotationFromAToB);}
).exceptionally(new Function() {
@Override
public Void apply(Throwable throwable) {
Toast.makeText(ARActivity.this, "Error: "+
throwable.getMessage().toString(), Toast.LENGTH_SHORT).show();
return null;
}
});
});}
Log.d("position:",anchorNode.getLocalPosition().toString());
lastAnchorNode = anchorNode;}
}
```## All done, you're ready to go!
Thank you for viewing my repository, i hope it helped you achieve your desired results## Let's Connect
You can find me here:
Linkedin: [Link](https://www.linkedin.com/in/bhaskar-kaura-300b09272/)
Instagram: [Link](https://www.instagram.com/bhaskar_blur/)
Twitter: [Link](https://twitter.com/Bhaskar_blur)## Support information
For any question or bug report, please send an email to [[email protected]](mailto:[email protected])