Pregunta

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

a) he calculado norte utilizando los valores de los sensores desde el magnetómetro y acelerómetro. Sé que esto es correcto, ya que se alinee con la brújula utilizada en la vista de mapa de Google.

b) he calculado el cojinete inicial desde mi ubicación para la ubicación de destino mediante el uso de myLocation.bearingTo (destLocation);

Me falta el último paso; a partir de estos dos valores (A y B) ¿Qué fórmula que utilizo para obtener la dirección en la que el teléfono está apuntando con respecto a la ubicación de destino?

agradecería cualquier ayuda para una mente podrido!

¿Fue útil?

Solución

Ok cuenta de esto. Para cualquier otra persona tratando de hacer esto necesita:

a) Denominación: el rumbo de la brújula de hardware. Esto es en grados al este de magnética norte

b) del cojinete: cojinete de su ubicación en el lugar de destino. Esto es en grados al este de true norte.

myLocation.bearingTo(destLocation);

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

El título que se devuelve desde el magnetómetro + accelermometer está en grados al este del norte verdadero (magnética) (-180 a +180) por lo que necesita para obtener la diferencia entre el norte y el norte magnético para su ubicación. Esta diferencia es variable dependiendo de dónde se encuentre en la tierra. Se puede obtener mediante el uso de 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 que calcular el ángulo de la flecha para dibujar en el mapa para mostrar dónde se enfrentan en relación con el objeto de destino en lugar de norte verdadero.

En primer lugar ajustar el rumbo con la declinación:

heading += geoField.getDeclination();

En segundo lugar, es necesario para compensar la dirección en la cual el teléfono se enfrenta (rúbrica) del punto de destino en lugar de norte verdadero. Esta es la parte que me quedé atrapado en. El valor del rumbo de regresar de la brújula le da un valor que indica dónde está el norte magnético (en grados al este del norte verdadero) en relación con la que el teléfono está apuntando. Así, por ejemplo, si el valor es de -10 sabe que el norte magnético es de 10 grados a la izquierda. El rodamiento le da el ángulo de su destino en grados al este del norte verdadero. Así que después de haber compensado la declinación puede utilizar la siguiente fórmula para obtener el resultado deseado:

heading = myBearing - (myBearing + heading); 

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

Math.round(-heading / 360 + 180)

Otros consejos

@Damian - La idea es muy buena y estoy de acuerdo con la respuesta, pero cuando utilicé su código tuve valores erróneos, por lo que escribí esto en mi propia (alguien dijo lo mismo en sus comentarios). encabezamiento de conteo con la declinación es buena, creo, pero más tarde he usado algo así:

heading = (bearing - heading) * -1;

en lugar del código de Damian:

heading = myBearing - (myBearing + heading); 

y el cambio de -180º a 180º durante 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 se quiere girar la flecha puede utilizar código como el siguiente:

      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 la imagen flecha y 100F parámetros en postRotate es PivX y pivY).

espero ayudar a alguien.

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

Puede utilizar sencilla bearingTo en este way.bearing que le dará el ángulo directo desde su ubicación a 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, el cual va a confundir las cosas un poco. Vamos a necesitar para 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 nos da bearingTo

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

así que tenemos que añadir 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;
}

lo que necesita implementa el SensorEventListener y sus funciones (onSensorChanged, onAcurracyChabge) y escribir todo el código dentro de onSensorChanged

Código completo está aquí para Dirección de Qibla brújula

 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;
}

código XML es aquí

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/flag_pakistan">
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/heading"
    android:textColor="@color/colorAccent"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="100dp"
    android:layout_marginTop="20dp"
    android:text="Heading: 0.0" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/heading"
android:scaleType="centerInside"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true">

<ImageView
    android:id="@+id/imageCompass"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:scaleType="centerInside"
    android:layout_centerVertical="true"
    android:layout_centerHorizontal="true"
    android:src="@drawable/images_compass"/>

<ImageView
    android:id="@+id/needle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_centerHorizontal="true"
    android:scaleType="centerInside"
    android:src="@drawable/arrow2"/>
</RelativeLayout>
</RelativeLayout>

No soy un experto en la lectura de mapas / navegación y así sucesivamente, pero sin duda 'direcciones' son absolutos y no relativos o en la realidad, son relativos a N o S que a su vez se fijan / absoluta.

Ejemplo: Supongamos que una línea imaginaria trazada entre usted y sus corresponde destino con 'absoluta' SE (un cojinete de 135 grados con respecto a N magnética). Supongamos ahora que el teléfono está apuntando NW - si se traza una línea imaginaria desde un objeto imaginario en el horizonte a su destino, que pasará a través de su ubicación y tienen 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 'por S' del objeto imaginario su teléfono está apuntando a y, por otra parte, si usted viajó a ese punto imaginario, su destino aún sería SE de la que ha trasladado a.

En realidad, la línea de 180 grados en realidad le indica el destino es 'atrás' con respecto a la forma en que el teléfono (y es de suponer que) está apuntando.

Una vez dicho esto, sin embargo, si el cálculo del ángulo de una línea imaginaria desde el punto de su destino (que pasa a través de su ubicación) con el fin de elaborar un puntero hacia su destino es lo que quiere ... sólo hay que restar la (absoluta ) de cojinete del destino desde el cojinete absoluta del objeto imaginario e ignorar una negación (si está presente). por ejemplo, NW - SE es 315 -. 135 = 180 por lo que dibujar el puntero a punto en la parte inferior de la pantalla indicando 'atrás'

EDIT: Tengo las matemáticas un poco mal ... restar el menor de los cojinetes de la más grande después restar el resultado de 360 ??a conseguir el ángulo en el que dibujar el puntero en la pantalla.

Si se encuentra en la misma zona horaria

Convertir GPS a UTM

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

coordenadas UTM conseguir que un Simples X Y 2D

Calcular el ángulo entre ambos lugares UTM

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

Esto le da a la dirección como si estuviera mirando al norte

Así que cualquier cosa que gira relacionados do Norte simplemente restar este ángulo

Si los dos puntos tiene un ángulo de 45º grado UTM y que son 5º al este del norte, su flecha apuntará a 40º del norte

Así es como lo he hecho:

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 la gente como yo de Google que no encontraron una respuesta completa aquí. Aquí están 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! LastKnownLocation se utilizó ya que este código fue de nuevo SimpleCursorAdapter.ViewBinder ()

onLocationChanged contiene una llamada a notifyDataSetChanged ();

Código también de nuevo SimpleCursorAdapter.ViewBinder () para rotación de imagen y listrow colores establecidos (sólo se aplica en una sola columnIndex que conste) ...

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 el caso de que se esté preguntando lo hice con la dramas sensor magnético, no valía la pena la molestia en mi caso. Espero que alguien encuentra esto tan útil como suelo hacer cuando Google me lleva a stackoverflow!

Este es el código de cálculo de ángulo de marcació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);

Terminología: La diferencia entre el norte verdadero y el norte magnético se conoce como "variación" No declinación. La diferencia entre lo que su brújula lee y el rumbo magnético se conoce como "desviación" y varía con la rúbrica. Una brújula identifica errores de oscilación del dispositivo y permite correcciones que deben aplicarse si el dispositivo ha construido en la corrección. Una brújula magnética tendrá una tarjeta de desviación que describe el error de dispositivo en cualquier partida.

Declinación: plazo A utilizado en la navegación Astro: La declinación es como latitud. En ella se informa en qué medida es una estrella desde el ecuador celeste. Para encontrar la declinación de una estrella seguir un círculo horario "abajo recta" de la estrella para el ecuador celeste. El ángulo de la estrella al ecuador celeste a lo largo del círculo horario es de declinación de la estrella.

Estoy en el proceso de averiguarlo ahora, pero parece como si la matemática depende de donde usted y su objetivo está en la tierra con respecto al 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 de azimut.

Ver getDeclination () para la declinación

Esto supone declinación es negativo (al oeste del norte verdadero) y theirBearing> yourBearing.

Si la declinación es positiva y yourBearing> theirBearing otra opción:

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

No he probado esta totalmente pero jugando con los ángulos en el papel me tiene aquí.

esta es la mejor manera de detectar el cojinete de localización de objetos 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 cojinete utilizando las coordenadas del punto de inicio hasta el punto final ver

El siguiente código le dará el cojinete (á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 funciona para mí la esperanza de que va a funcionar otros, así

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top