Search code examples
javaandroidgeometryandroid-gps

How to calculate angle beetween current direction and GPS point


I have 2 points (Android Location objects): current location and target location. Also I have a direction (in degrees) of my device.

enter image description here

I wanna calculate an angle between target location and direction. How to do it properly?

I receiving location from FusedLocationProvider (if it's matter). Now i just use

float requiredAngle = Math.abs(location.getBearing() - 180 - target.bearingTo(location));

float angleBetween = Math.abs(requiredAngle - location.getBearing()); and it's returns incorrect angle.

I think I should caclate the difference between true north and magnetic north and add device direction. Then use currentPosition.bearingTo(target), and subtract device direction from bearing.


Solution

  • This angle called relative bearing.

    Register listeners to Sensor.TYPE_ROTATION_VECTOR, Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_MAGNETIC_FIELD. Like:

    sensorManager.registerListener(listener, sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR), SensorManager.SENSOR_DELAY_NORMAL);
    

    Then make a listener for this:

    private float[] gravity;
    private float[] geomagnetic;
    private float[] R = new float[9];
    private float[] I = new float[9];    
    
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            gravity = sensor.values(); // Just save the values
        }
    
        if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            geomagnetic = sensor.values();
        }
    
        if (SensorManager.getRotationMatrix(R, I, gravity, geomagnetic)) { // If something is wrong (like device is in free fall)
            float orientation[] = new float[3];
            SensorManager.getOrientation(R, orientation);
            // Now you have values from -PI to PI
            float heading;
            if (R[0] > 0) { // R[0] is heading
                heading = R[0] * 180 / PI;
            } else { // -PI, eq. from South to West to North
                heading = (Math.abs(R[0]) * 180 / PI) * 2;
            }
    
            float relativeBearing = location.bearingTo(target) - heading;
            if (relativeBearing < 0) {
                relativeBearing = 360 + relativeBearing;
            }
        }
    }
    

    Documentation: https://developer.android.com/reference/android/hardware/SensorManager#getRotationMatrix(float[],%20float[],%20float[],%20float[]) https://developer.android.com/reference/android/hardware/SensorManager#getOrientation(float[],%20float[])