Question

Je souhaite afficher une flèche à mon emplacement sur une vue Google Map qui affiche ma direction par rapport à un emplacement de destination (au lieu du nord).

a) J'ai calculé le nord en utilisant les valeurs des capteurs du magnétomètre et de l'accéléromètre.Je sais que c'est correct car cela correspond à la boussole utilisée sur la vue Google Map.

b) J'ai calculé le relèvement initial de mon emplacement à l'emplacement de destination en utilisant myLocation.bearingTo(destLocation);

Il me manque la dernière étape ;à partir de ces deux valeurs (a et b), quelle formule dois-je utiliser pour obtenir la direction dans laquelle le téléphone pointe par rapport à l'emplacement de destination ?

Appréciez toute aide pour un esprit confus !

Était-ce utile?

La solution

Ok je me suis dit cela. Pour quelqu'un d'autre d'essayer de faire ce dont vous avez besoin:

a) rubrique: votre cap de la boussole du matériel. Ceci est en degrés est de magnétique Nord

b) portant: le roulement de votre emplacement à l'emplacement de destination. Ceci est en degrés à l'est de true Nord.

myLocation.bearingTo(destLocation);

c) la déclinaison: la différence entre le nord géographique et le nord magnétique

La rubrique qui est renvoyée par le magnétomètre + accelermometer est en degrés est de vrai (magnétique) au nord (-180 à 180) de sorte que vous devez obtenir la différence entre le nord et le nord magnétique pour votre emplacement. Cette différence est variable selon l'endroit où vous êtes sur la terre. Vous pouvez obtenir en utilisant la classe 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()
      );
      ...
   }
}

Armé de ces vous calculer l'angle de la flèche pour dessiner sur votre carte pour montrer où vous faites face par rapport à votre objet de destination plutôt que le vrai nord.

Tout d'abord régler votre cap avec le Déclinaison:

heading += geoField.getDeclination();

En second lieu, vous devez compenser la direction dans laquelle le téléphone est face à (cap) de la destination cible plutôt que le vrai nord. Ceci est la partie que je suis coincé sur. La valeur du cap retour de la boussole vous donne une valeur qui décrit où le nord magnétique est (en degrés à l'est du nord vrai) par rapport à l'endroit où le téléphone pointe. Ainsi, par exemple si la valeur est comprise entre -10 vous savez que le nord magnétique est de 10 degrés à gauche. Le palier vous donne l'angle de votre destination en degrés à l'est du nord vrai. Donc, après avoir dédommagé pour la Déclinaison vous pouvez utiliser la formule ci-dessous pour obtenir le résultat souhaité:

heading = myBearing - (myBearing + heading); 

Vous voulez ensuite convertir les degrés est du nord vrai (-180 à 180) en degrés normaux (0 à 360):

Math.round(-heading / 360 + 180)

Autres conseils

@Damian - L'idée est très bonne et je suis d'accord avec la réponse, mais quand je votre code j'avais mauvaises valeurs, donc je l'ai écrit sur mon propre (quelqu'un a dit la même chose dans vos commentaires). tête de comptage avec le Déclinaison est bon, je pense, mais plus tard je quelque chose comme ça:

heading = (bearing - heading) * -1;

au lieu du code de Damian:

heading = myBearing - (myBearing + heading); 

et la modification de -180 à 180 de 0 à 360:

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

et puis quand vous voulez faire pivoter votre flèche, vous pouvez utiliser le code comme ceci:

      private void rotateArrow(float angle){

            Matrix matrix = new Matrix();
            arrowView.setScaleType(ScaleType.MATRIX);
            matrix.postRotate(angle, 100f, 100f);
            arrowView.setImageMatrix(matrix);
      }

arrowView est ImageView avec l'image de la flèche et 100f paramètres dans postRotate est pivX et pivY).

J'espère que je vais aider quelqu'un.

Dans cette une flèche sur la boussole indique la direction de votre emplacement Kaaba ( Emplacement de destination )

vous pouvez simplement utiliser bearingTo dans ce way.bearing pour vous donner l'angle direct de votre emplacement à l'emplacement de destination

  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 vous donnera une gamme -180 à 180, ce qui confondre les choses un peu. Nous aurons besoin de convertir cette valeur dans une plage de 0 à 360 pour obtenir la rotation correcte.

Ceci est une table de ce que nous voulons vraiment, en comparant à ce que bearingTo nous donne

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

donc nous devons ajouter ce code après 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;
}

vous devez Implémente la SensorEventListener et ses fonctions (onSensorChanged, onAcurracyChabge) et écrire tout le code à l'intérieur onSensorChanged

Code complet est ici pour la Direction de la boussole 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;
}

code xml est ici

<?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>

Je ne suis pas un expert en lecture de cartes/navigation, etc., mais les « directions » sont sûrement absolues et non relatives ou en réalité, elles sont relatives à N ou S qui sont elles-mêmes fixes/absolues.

Exemple:Supposons qu'une ligne imaginaire tracée entre vous et votre destination corresponde au SE « absolu » (un relèvement de 135 degrés par rapport au N magnétique).Supposons maintenant que votre téléphone pointe vers le nord-ouest : si vous tracez une ligne imaginaire partant d'un objet imaginaire à l'horizon jusqu'à votre destination, elle passera par votre emplacement et aura un angle de 180 degrés.Maintenant, 180 degrés dans le sens d'une boussole font en fait référence au S mais la destination n'est pas « due au S » de l'objet imaginaire vers lequel pointe votre téléphone et, de plus, si vous vous rendiez à ce point imaginaire, votre destination serait toujours au SE de où vous avez déménagé.

En réalité, la ligne à 180 degrés vous indique en fait que la destination est « derrière vous » par rapport à la direction vers laquelle le téléphone (et probablement vous) pointe.

Cela dit, cependant, si vous voulez calculer l'angle d'une ligne depuis le point imaginaire jusqu'à votre destination (passant par votre emplacement) afin de dessiner un pointeur vers votre destination... soustrayez simplement l'orientation (absolue) de la destination du relèvement absolu de l'objet imaginaire et ignorer une négation (si présente).par exemple, NW - SE est 315 - 135 = 180, alors dessinez le pointeur pour pointer en bas de l'écran indiquant « derrière vous ».

MODIFIER: Je me suis légèrement trompé dans les calculs... soustrayez le plus petit des roulements du plus grand, puis soustrayez le résultat de 360 ​​pour obtenir l'angle dans lequel dessiner le pointeur sur l'écran.

Si vous êtes sur le même fuseau horaire

Convertir GPS UTM

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

coordonnées UTM vous obtenez un SIMPLES X Y 2D

Calculer l'angle entre les deux emplacements UTM

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

Cela donne la direction comme si vous étiez à la recherche du Nord

Alors tout ce que vous faites pivoter liés ne North soustraient que cet angle

Si les deux points ont un angle UTM 45º degrés et vous êtes 5º est du nord, votre flèche pointera vers 40º du nord

Voici comment je l'ai fait:

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

Je sais que c'est un peu vieux, mais pour le bien de gens comme moi de Google qui n'ont pas trouvé une réponse complète ici. Voici quelques extraits de mon application qui mettent les flèches dans un listview personnalisé ....

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

Je prêt à parier qu'il pourrait être simplifié, mais ça marche! LastKnownLocation a été utilisé puisque ce code est de nouveau SimpleCursorAdapter.ViewBinder ()

OnLocationChanged contient un appel à notifyDataSetChanged ();

Code aussi de nouveaux SimpleCursorAdapter.ViewBinder () pour définir les couleurs de rotation et listrow l'image (uniquement appliquées dans un esprit unique columnIndex vous) ...

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

Si vous vous demandez je l'ai fait disparaître les drames de capteurs magnétiques, ne vaut pas les tracas dans mon cas. J'espère que quelqu'un trouve cela aussi utile que je fais habituellement lorsque Google me amène à stackoverflow!

Voici le code pour le calcul de l'angle d'appui entre deux points:

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

Appel de la fonction:

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

Terminologie: La différence entre le nord et le nord magnétique est connu comme « variation » pas Déclinaison. La différence entre ce que votre boussole lit et le cap magnétique est connu comme « déviation » et varie selon la position. Une balançoire boussole identifie les erreurs de l'appareil et permet des corrections à appliquer si l'appareil est construit en correction. Un compas magnétique aura une carte d'écart qui décrit l'erreur de l'appareil sur toute position.

Déclinaison: Terme utilisé dans la navigation Astro: Déclinaison est, comme la latitude. Il rend compte à quel point une étoile est de l'équateur céleste. Pour trouver la déclinaison d'une étoile suivre un cercle heure « vers le bas » de l'étoile à l'équateur céleste. L'angle de l'étoile à l'équateur céleste le long du cercle de l'heure est la déclination de l'étoile.

Je suis en train de le découvrir maintenant, mais il semble que le calcul dépend de l'endroit où vous et votre cible sont sur la terre par rapport au Nord vrai et magnétique. Par exemple:

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

Voir Sensor.TYPE_ORIENTATION pour l'azimut.

Voir getDeclination () pour Déclinaison

Cela suppose Déclinaison est négatif (à l'ouest du nord vrai) et theirBearing> yourBearing.

Si Déclinaison est positif et yourBearing> theirBearing une autre option:

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

Je n'ai pas testé complètement mais en jouant avec les angles sur papier m'a fait ici.

Ceci est la meilleure façon de détecter Bearing de Lieu objet sur 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 formule donnera le roulement à l'aide des coordonnées du point de départ au point de fin

scroll top