Calcular brújula teniendo / rumbo a la ubicación en Android

Quiero mostrar una flecha en mi ubicación en una vista de mapa de Google que muestra mi dirección en relación con una ubicación de destino (en lugar de norte).

a) He calculado al norte usando los valores del sensor del magnetómetro y el acelerómetro. Sé que esto es correcto porque se alinea con la brújula utilizada en la vista de Google Map.

b) He calculado el rumbo inicial desde mi ubicación hasta la ubicación de destino utilizando myLocation.bearingTo (destLocation);

Me estoy perdiendo el último paso; a partir de estos dos valores (ayb) ¿qué fórmula utilizo para obtener la dirección en la que el teléfono apunta en relación con la ubicación de destino?

¡Aprecia cualquier ayuda para una mente confundida!

Ok, me di cuenta de esto. Para cualquier otra persona que intente hacer esto, necesita:

a) encabezado: su partida desde la brújula de hardware. Esto está en grados al este del norte magnético

b) rodamiento: el rodamiento desde su ubicación hasta la ubicación de destino. Esto está en grados al este del verdadero norte.

myLocation.bearingTo(destLocation); 

c) declinación: la diferencia entre el norte verdadero y el norte magnético

El encabezado que se devuelve desde el magnetómetro + accelermómetro está en grados al este del norte verdadero (magnético) (-180 a +180), por lo que debe obtener la diferencia entre el norte y el norte magnético para su ubicación. Esta diferencia es variable dependiendo de dónde te encuentres en la tierra. Puede obtener usando la clase GeomagneticField.

 GeomagneticField geoField; private final LocationListener locationListener = new LocationListener() { public void onLocationChanged(Location location) { geoField = new GeomagneticField( Double.valueOf(location.getLatitude()).floatValue(), Double.valueOf(location.getLongitude()).floatValue(), Double.valueOf(location.getAltitude()).floatValue(), System.currentTimeMillis() ); ... } } 

Armado con estos calcula el ángulo de la flecha para dibujar en su mapa para mostrar dónde se encuentra en relación con su objeto de destino en lugar de hacia el norte verdadero.

Primero ajusta tu encabezado con la declinación:

 heading += geoField.getDeclination(); 

En segundo lugar, debe compensar la dirección en la que se encuentra el teléfono (rumbo) desde el destino de destino en lugar de hacia el norte verdadero. Esta es la parte en la que me quedé atascado. El valor del título devuelto por la brújula le proporciona un valor que describe dónde se encuentra el norte magnético (en grados al este del norte verdadero) en relación con hacia dónde apunta el teléfono. Entonces, por ejemplo, si el valor es -10, usted sabe que el norte magnético está a 10 grados a su izquierda. El rumbo le da el ángulo de su destino en grados al este del norte verdadero. Entonces, después de compensar la declinación, puede usar la fórmula siguiente para obtener el resultado deseado:

 heading = myBearing - (myBearing + heading); 

A continuación, querrás convertir grados al este del norte verdadero (-180 a +180) en grados normales (0 a 360):

 Math.round(-heading / 360 + 180) 

@Damian: la idea es muy buena y estoy de acuerdo con la respuesta, pero cuando usé el código tuve valores incorrectos, así que escribí esto por mi cuenta (alguien dijo lo mismo en sus comentarios). El conteo del rumbo con la declinación es bueno, creo, pero luego usé algo así:

 heading = (bearing - heading) * -1; 

en lugar del código de Damian:

 heading = myBearing - (myBearing + heading); 

y cambiando -180 a 180 de 0 a 360:

  private float normalizeDegree(float value){ if(value >= 0.0f && value <= 180.0f){ return value; }else{ return 180 + (180 + value); } 

y luego, cuando quieras rotar tu flecha, puedes usar un código como este:

  private void rotateArrow(float angle){ Matrix matrix = new Matrix(); arrowView.setScaleType(ScaleType.MATRIX); matrix.postRotate(angle, 100f, 100f); arrowView.setImageMatrix(matrix); } 

donde arrowView es ImageView con imagen de flecha y los parámetros postRotate en postRotate son pivX y pivY).

Espero ayudar a alguien

No soy un experto en lectura de mapas / navegación, etc., pero seguramente las “direcciones” son absolutas y no relativas, o en realidad, son relativas a N o S, que a su vez son fijas / absolutas.

Ejemplo: Supongamos que una línea imaginaria trazada entre usted y su destino se corresponde con SE ‘absoluta’ (un rumbo de 135 grados con respecto al N magnético). Ahora suponga que su teléfono apunta hacia NO: si dibuja una línea imaginaria desde un objeto imaginario en el horizonte hasta su destino, pasará por su ubicación y tendrá un ángulo de 180 grados. Ahora, 180 grados en el sentido de una brújula en realidad se refiere a S, pero el destino no es ‘debido a S’ del objeto imaginario al que apunta su teléfono y, además, si viajó a ese punto imaginario, su destino seguirá siendo SE de a donde te mudaste

En realidad, la línea de 180 grados en realidad te dice que el destino está “detrás de ti” en relación con la forma en que el teléfono (y presumiblemente tú) están apuntando.

Dicho esto, sin embargo, si lo que desea es calcular el ángulo de una línea desde el punto imaginario hasta su destino (pasando por su ubicación) para dibujar un puntero hacia su destino … simplemente reste la orientación (absoluta) de el destino desde el rumbo absoluto del objeto imaginario e ignorar una negación (si está presente). por ejemplo, NW – SE es 315 – 135 = 180, por lo tanto, dibuje el puntero para señalar en la parte inferior de la pantalla, indicando “detrás de usted”.

EDITAR: Tengo las Matemáticas ligeramente equivocadas … restar el más pequeño de los rodamientos del más grande y luego restar el resultado de 360 ​​para obtener el ángulo en el que dibujar el puntero en la pantalla.

En esta, una flecha en la brújula muestra la dirección desde su ubicación hasta Kaaba ( ubicación de destino )

puede usar de manera simple bearingTo de esta manera. El hecho de llevarlo le dará el ángulo directo desde su ubicación hasta la ubicación de destino

  Location userLoc=new Location("service Provider"); //get longitudeM Latitude and altitude of current location with gps class and set in userLoc userLoc.setLongitude(longitude); userLoc.setLatitude(latitude); userLoc.setAltitude(altitude); Location destinationLoc = new Location("service Provider"); destinationLoc.setLatitude(21.422487); //kaaba latitude setting destinationLoc.setLongitude(39.826206); //kaaba longitude setting float bearTo=userLoc.bearingTo(destinationLoc); 

bearingTo le dará un rango de -180 a 180, lo que confundirá un poco las cosas. Tendremos que convertir este valor en un rango de 0 a 360 para obtener la rotación correcta.

Esta es una tabla de lo que realmente queremos, en comparación con lo que bearingTo nos da

 +-----------+--------------+ | bearingTo | Real bearing | +-----------+--------------+ | 0 | 0 | +-----------+--------------+ | 90 | 90 | +-----------+--------------+ | 180 | 180 | +-----------+--------------+ | -90 | 270 | +-----------+--------------+ | -135 | 225 | +-----------+--------------+ | -180 | 180 | +-----------+--------------+ 

entonces tenemos que agregar este código después de bearTo

 // If the bearTo is smaller than 0, add 360 to get the rotation clockwise. if (bearTo < 0) { bearTo = bearTo + 360; //bearTo = -100 + 360 = 260; } 

necesita implementar SensorEventListener y sus funciones (onSensorChanged, onAcurracyChabge) y escribir todo el código en onSensorChanged

El código completo está aquí para la dirección de la brújula Qibla

  public class QiblaDirectionCompass extends Service implements SensorEventListener{ public static ImageView image,arrow; // record the compass picture angle turned private float currentDegree = 0f; private float currentDegreeNeedle = 0f; Context context; Location userLoc=new Location("service Provider"); // device sensor manager private static SensorManager mSensorManager ; private Sensor sensor; public static TextView tvHeading; public QiblaDirectionCompass(Context context, ImageView compass, ImageView needle,TextView heading, double longi,double lati,double alti ) { image = compass; arrow = needle; // TextView that will tell the user what degree is he heading tvHeading = heading; userLoc.setLongitude(longi); userLoc.setLatitude(lati); userLoc.setAltitude(alti); mSensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE); sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); if(sensor!=null) { // for the system's orientation sensor registered listeners mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);//SensorManager.SENSOR_DELAY_Fastest }else{ Toast.makeText(context,"Not Supported", Toast.LENGTH_SHORT).show(); } // initialize your android device sensor capabilities this.context =context; @Override public void onCreate() { // TODO Auto-generated method stub Toast.makeText(context, "Started", Toast.LENGTH_SHORT).show(); mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME); //SensorManager.SENSOR_DELAY_Fastest super.onCreate(); } @Override public void onDestroy() { mSensorManager.unregisterListener(this); Toast.makeText(context, "Destroy", Toast.LENGTH_SHORT).show(); super.onDestroy(); } @Override public void onSensorChanged(SensorEvent sensorEvent) { Location destinationLoc = new Location("service Provider"); destinationLoc.setLatitude(21.422487); //kaaba latitude setting destinationLoc.setLongitude(39.826206); //kaaba longitude setting float bearTo=userLoc.bearingTo(destinationLoc); //bearTo = The angle from true north to the destination location from the point we're your currently standing.(asal image k N se destination taak angle ) //head = The angle that you've rotated your phone from true north. (jaise image lagi hai wo true north per hai ab phone jitne rotate yani jitna image ka n change hai us ka angle hai ye) GeomagneticField geoField = new GeomagneticField( Double.valueOf( userLoc.getLatitude() ).floatValue(), Double .valueOf( userLoc.getLongitude() ).floatValue(), Double.valueOf( userLoc.getAltitude() ).floatValue(), System.currentTimeMillis() ); head -= geoField.getDeclination(); // converts magnetic north into true north if (bearTo < 0) { bearTo = bearTo + 360; //bearTo = -100 + 360 = 260; } //This is where we choose to point it float direction = bearTo - head; // If the direction is smaller than 0, add 360 to get the rotation clockwise. if (direction < 0) { direction = direction + 360; } tvHeading.setText("Heading: " + Float.toString(degree) + " degrees" ); RotateAnimation raQibla = new RotateAnimation(currentDegreeNeedle, direction, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); raQibla.setDuration(210); raQibla.setFillAfter(true); arrow.startAnimation(raQibla); currentDegreeNeedle = direction; // create a rotation animation (reverse turn degree degrees) RotateAnimation ra = new RotateAnimation(currentDegree, -degree, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); // how long the animation will take place ra.setDuration(210); // set the animation after the end of the reservation status ra.setFillAfter(true); // Start the animation image.startAnimation(ra); currentDegree = -degree; } @Override public void onAccuracyChanged(Sensor sensor, int i) { } @Nullable @Override public IBinder onBind(Intent intent) { return null; } 

El código xml está aquí

         

Si estás en la misma zona horaria

Convierte el GPS a UTM

http://www.ibm.com/developerworks/java/library/j-coordconvert/ http://stackoverflow.com/questions/176137/java-convert-lat-lon-to-utm

Las coordenadas UTM te dan un simple XY 2D

Calcule el ángulo entre ambas ubicaciones de UTM

http://forums.groundspeak.com/GC/index.php?showtopic=146917

Esto te da la dirección como si estuvieras mirando hacia el norte

Entonces, sea lo que sea que gires, hazlo al norte simplemente resta este ángulo

Si ambos puntos tienen un ángulo UTM de 45º grados y estás a 5º al este del norte, tu flecha apuntará a 40º al norte

Así es como lo hice:

 Canvas g = new Canvas( compass ); Paint p = new Paint( Paint.ANTI_ALIAS_FLAG ); float rotation = display.getOrientation() * 90; g.translate( -box.left, -box.top ); g.rotate( -bearing - rotation, box.exactCenterX(), box.exactCenterY() ); drawCompass( g, p ); drawNeedle( g, p ); 

Sé que esto es un poco viejo, pero por el bien de gente como yo de Google, que no encontró una respuesta completa aquí. Aquí hay algunos extractos de mi aplicación que ponen las flechas dentro de una vista de lista personalizada …

 Location loc; //Will hold lastknown location Location wptLoc = new Location(""); // Waypoint location float dist = -1; float bearing = 0; float heading = 0; float arrow_rotation = 0; LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE); loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); if(loc == null) { //No recent GPS fix Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setAltitudeRequired(false); criteria.setBearingRequired(true); criteria.setCostAllowed(true); criteria.setSpeedRequired(false); loc = lm.getLastKnownLocation(lm.getBestProvider(criteria, true)); } if(loc != null) { wptLoc.setLongitude(cursor.getFloat(2)); //Cursor is from SimpleCursorAdapter wptLoc.setLatitude(cursor.getFloat(3)); dist = loc.distanceTo(wptLoc); bearing = loc.bearingTo(wptLoc); // -180 to 180 heading = loc.getBearing(); // 0 to 360 // *** Code to calculate where the arrow should point *** arrow_rotation = (360+((bearing + 360) % 360)-heading) % 360; } 

Estoy dispuesto a apostar que podría simplificarse pero funciona! Se utilizó LastKnownLocation ya que este código era del nuevo SimpleCursorAdapter.ViewBinder ()

onLocationChanged contiene una llamada a notifyDataSetChanged ();

código también desde el nuevo SimpleCursorAdapter.ViewBinder () para establecer la rotación de la imagen y los colores listrow (solo se aplica en una sola columna).

 LinearLayout ll = ((LinearLayout)view.getParent()); ll.setBackgroundColor(bc); int childcount = ll.getChildCount(); for (int i=0; i < childcount; i++){ View v = ll.getChildAt(i); if(v instanceof TextView) ((TextView)v).setTextColor(fc); if(v instanceof ImageView) { ImageView img = (ImageView)v; img.setImageResource(R.drawable.ic_arrow); Matrix matrix = new Matrix(); img.setScaleType(ScaleType.MATRIX); matrix.postRotate(arrow_rotation, img.getWidth()/2, img.getHeight()/2); img.setImageMatrix(matrix); } 

En caso de que te estés preguntando si eliminé los dtwigs del sensor magnético, no valía la pena la molestia en mi caso. Espero que alguien lo encuentre tan útil como suelo hacer cuando google me lleva a stackoverflow.

Terminología: la diferencia entre TRUE north y Magnetic North se conoce como “variación”, no como declinación. La diferencia entre lo que lee la brújula y el rumbo magnético se conoce como “desviación” y varía con el rumbo. Una swing de brújula identifica los errores del dispositivo y permite que se apliquen correcciones si el dispositivo tiene corrección incorporada. Una brújula magnética tendrá una tarjeta de desviación que describe el error del dispositivo en cualquier rumbo.

Declinación: un término usado en la navegación Astro: la declinación es como la latitud. Informa qué tan lejos está una estrella del ecuador celeste. Para encontrar la declinación de una estrella, siga un círculo de horas “recto hacia abajo” desde la estrella hasta el ecuador celeste. El ángulo desde la estrella hasta el ecuador celeste a lo largo del círculo de la hora es la declinación de la estrella.

Estoy en el proceso de descifrarlo ahora, pero parece que las matemáticas dependen de dónde usted y su objective se encuentren en la tierra en relación con el Norte verdadero y magnético. Por ejemplo:

 float thetaMeThem = 0.0; if (myLocation.bearingTo(targetLocation) > myLocation.getBearing()){ thetaMeThem = myLocation.bearingTo(targetLocation) - azimuth + declination;} 

Ver Sensor.TYPE_ORIENTATION para acimut.

Ver getDeclination () para declinación

Esto supone que la declinación es negativa (al oeste del norte verdadero) y sus raíces.

Si la declinación es positiva y si estás interesado en otra opción, haz lo siguiente:

 float thetaMeThem = 0.0; if (myLocation.bearingTo(targetLocation) < myLocation.getBearing()){ thetaMeThem = azimuth - (myLocation.bearingTo(targetLocation) - declination);} 

No lo he probado completamente, pero jugar con los angularjs en el papel me ha traído aquí.

Esta es la mejor manera de detectar el Rumbo desde el Objeto de ubicación en Google Map: ->

  float targetBearing=90; Location endingLocation=new Location("ending point"); Location startingLocation=new Location("starting point"); startingLocation.setLatitude(mGoogleMap.getCameraPosition().target.latitude); startingLocation.setLongitude(mGoogleMap.getCameraPosition().target.longitude); endingLocation.setLatitude(mLatLng.latitude); endingLocation.setLongitude(mLatLng.longitude); targetBearing = startingLocation.bearingTo(endingLocation); 

La fórmula dará el rumbo utilizando las coordenadas del punto de inicio hasta el punto final.

El siguiente código le dará la orientación (ángulo entre 0-360)

 private double bearing(Location startPoint, Location endPoint) { double longitude1 = startPoint.getLongitude(); double latitude1 = Math.toRadians(startPoint.getLatitude()); double longitude2 = endPoint.getLongitude(); double latitude2 = Math.toRadians(endPoint.getLatitude()); double longDiff = Math.toRadians(longitude2 - longitude1); double y = Math.sin(longDiff) * Math.cos(latitude2); double x = Math.cos(latitude1) * Math.sin(latitude2) - Math.sin(latitude1) * Math.cos(latitude2) * Math.cos(longDiff); return Math.toDegrees(Math.atan2(y, x)); 

}

Esto es trabajos para mí espero que funcione a cualquiera que encuentre el mismo

Aquí está el código para calcular el ángulo de orientación entre dos puntos:

 public float CalculateBearingAngle(double lat1,double lon1, double lat2, double lon2){ double Phi1 = Math.toRadians(lat1); double Phi2 = Math.toRadians(lat2); double DeltaLambda = Math.toRadians(lon2 - lon1); double Theta = atan2((sin(DeltaLambda)*cos(Phi2)), (cos(Phi1)*sin(Phi2) - sin(Phi1)*cos(Phi2)*cos(DeltaLambda))); return (float)Math.toDegrees(Theta); } 

Llamada para la función:

 float angle = CalculateBearingAngle(lat1, lon1, lat2, lon2);