Вопрос

Я хочу отобразить стрелку в моем месте на представлении карты Google, который отображает мое направление относительно места назначения (вместо севера).

а) Я рассчитал север, используя значения датчика от магнитометра и акселерометра. Я знаю, что это правильно, потому что он направляется с компасом, используемым на видео Google Map.

б) я рассчитал начальный подшипник из моего местоположения в место назначения, используя mylocation.pearingto (destlocation);

Я скучаю по последнему шагу; Из этих двух значений (A & B), какую формулу я использую, чтобы получить направление, в котором телефон указывает относительно места назначения?

Цените любую помощь для придвоенного ума!

Это было полезно?

Решение

Хорошо, я понял это. Для тех, кто пытается сделать это, вам нужно:

а) заголовок: ваша направляющаяся из аппаратного компаса. Это в градусах к востоку от магнитный север

б) Подшипник: подшипник из вашего местоположения до места назначения. Это в градусах к востоку от истинный север.

myLocation.bearingTo(destLocation);

в) склонение: разница между истинным севером и магнитным севером

Заголовок, который возвращается из магнитометра + акселерометр, находится в градусах к востоку от истинного (магнитного) северного (от -180 до +180), поэтому вам необходимо получить разницу между севером и магнитным севером для вашего местоположения. Эта разница переменная в зависимости от того, где вы находитесь на Земле. Вы можете получить с помощью класса 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()
      );
      ...
   }
}

Вооружившись этим, вы рассчитываете угол стрелки, чтобы нарисовать на своей карте, чтобы показать, где вы столкнетесь с объектом назначения, а не к истинному северу.

Сначала отрегулируйте свой заголовок с отказом:

heading += geoField.getDeclination();

Во-вторых, вам нужно компенсировать направление, в котором находится телефон (заголовок) от целевого назначения, а не истинный север. Это то часть, на которой я застрял. Значение заголовка, возвращенное из компаса, дает вам значение, которое описывает, где магнитный север (в градусах к востоку от истинного севера) в отношении того, где указывается телефон. Так, например, если значение равно -10, вы знаете, что магнитный север на 10 градусов на ваш левый. Подшипник дает вам угол пункта назначения в градусах к востоку от истинного севера. Поэтому после того, как вы компенсировали склонение, вы можете использовать формулу ниже, чтобы получить желаемый результат:

heading = myBearing - (myBearing + heading); 

Затем вы будете хотеть преобразовать из градусов к востоку от настоящего Севера (-180 до +180) в нормальные градусы (от 0 до 360):

Math.round(-heading / 360 + 180)

Другие советы

@Damian - Идея очень хорошая, и я согласен с ответом, но когда я использовал ваш код, у меня были неправильные ценности, поэтому я написал это самостоятельно (кто-то сказал то же самое в ваших комментариях). Подсчитывание заголовки с склонением хорошее, я думаю, но позже я использовал что-то подобное:

heading = (bearing - heading) * -1;

вместо кода Дамиана:

heading = myBearing - (myBearing + heading); 

и изменение от -180 на 180 на от 0 до 360:

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

А затем, когда вы хотите повернуть свою стрелку, вы можете использовать код, как это:

      private void rotateArrow(float angle){

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

куда arrowView является ImageView со стрелкой и параметрами 100F в postRotate это Pivx и ypy).

Я надеюсь, что я кому-то помогу.

В этом стрелка на компасе показывает направление от вашего местоположения до Кааба(Место назначения)

Вы можете просто использовать Bearingto таким образом.

  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 даст вам диапазон от -180 до 180, что немного путает. Нам нужно будет преобразовать это значение в диапазон от 0 до 360, чтобы получить правильное вращение.

Это таблица того, что мы действительно хотим, сравнивая с тем, что дает нам Bearingto

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

поэтому мы должны добавить этот код после 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;
}

Вам нужно реализовывать SensoreVentListener и его функции (OnsensorChanged, OnacurracyChaBGE) и напишите весь код внутри OnsensorChanged

Полный код здесь для направления Cibla Compass

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

XML-код здесь

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

Я не эксперт в чтении карт / навигации и т. Д., Но, конечно же, «направления» абсолютные и не относительные или в действительности, они относительно N или S, которые сами являются фиксированными / абсолютными.

Пример: Предположим, что воображаемая линия, нарисованная между вами, и вашим пунктом назначения, соответствует «абсолютному» SE (подшипник 135 градусов относительно магнитного n). Теперь предположим, что ваш телефон указывает NW - если вы нарисуете воображаемую строку из воображаемого объекта на горизонте до пункта назначения, он пройдет через ваше местоположение и имеет угол на 180 градусов. Сейчас на 180 градусов в смысле компаса фактически относится к S, но пункт назначения не «обусловлен» воображаемого объекта, ваш телефон указывает на и, кроме того, если вы путешествовали на этот воображаемый момент, ваш пункт назначения все равно будет где вы переехали.

В действительности, линия на 180 градусов на самом деле говорит вам, что пункт назначения находится «позади вас» по сравнению с тем, как наказывает телефон (и, по -видимому, вы).

Сказав это, однако, при расчете угла линии от воображаемой точки до пункта назначения (проходящего через ваше место), чтобы нарисовать указатель к пункту назначения - это то, что вы хотите ... просто вычтите (абсолютный) подшипник пункт назначения от абсолютного подшипника воображаемого объекта и игнорирует отрицание (если присутствует). Например, северо -запад - SE 315 - 135 = 180, так что нарисуйте указатель в точку в нижней части экрана, указывающего «позади вас».

РЕДАКТИРОВАТЬ: Я получил математику немного неправильно ... вычтите меньший из подшипников из более крупных, а затем вычтите результат из 360, чтобы получить угол, чтобы нарисовать указатель на экране.

Если вы находитесь на одном и том же часовом поясе

Преобразовать GPS в UTM

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

UTM координаты получают вам STRPLES XY 2D

Рассчитайте угол между оба локация UTM

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

Это дает направление, как будто вы смотрели на север

Так что все, что вы вращаете, связанный с севером, просто вычтите этот угол

Если обе точки имеют угол UTM 45º градуса, и вы находитесь в 5º к востоку от севера, ваша стрелка будет указывать на 40º на север

Вот как я это сделал:

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

Я знаю, что это немного старым, но ради людей, как я из Google, который не нашел полного ответа здесь. Вот несколько экстрактов из моего приложения, которые помещают стрелки внутри пользовательского списка ....

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

Я готов поспорить, что это может быть упрощено, но это работает! Lastknownlocation использовался, поскольку этот код был из нового SimpleCursorAdapter.ViewBinder ()

onLocationChangedChanged содержит вызов для уведомленияDataSethetheted ();

Код также от New SimpleCursorAdapter.viewbinder () для установки вращения изображения и цветов Listrow (применяется только в одном столбце -Index you) ...

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

Если вам интересно, что я покончил с магнитными датчиками, не стоил хлопот в моем случае. Я надеюсь, что кто -то найдет это таким же полезным, как я обычно делаю, когда Google приводит меня к Stackoverflow!

Вот код для расчета угла подшипника между двумя точками:

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

Призыв к функции:

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

Терминология: разница между истинным севером и магнитным севером известна как «вариация», а не склонение. Разница между тем, что читает ваш компас и магнитным заголовком, известна как «отклонение» и изменяется в зависимости от заголовка. Свинг компаса идентифицирует ошибки устройства и позволяет применять исправления, если устройство имеет встроенное коррекцию. Магнитный компас будет иметь карту отклонения, которая описывает ошибку устройства на любом заголовке.

Склонение: термин, используемый в Astro Navigation: склонение похоже на широту. Он сообщает, как далеко находится звезда от небесного экватора. Чтобы найти склонение звезды, следуйте по часу кругу «прямо вниз» от звезды к небесному экватору. Угол от звезды до небесного экватора вдоль часового круга - это склонение звезды.

Я сейчас нахожусь в процессе выяснения этого, но кажется, что математика зависит от того, где вы и ваша цель находятся на земле относительно истинного и магнитного севера. Например:

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

См. Sensor.type_orientation для азимута.

См. GetDeclination () для склонения

Это предполагает, что склонение негативно (к западу от истинного севера) и их ихлетнее обслуживание.

Если склонение является положительным, а ваше носиль

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

Я не проверил это полностью, но играя с углами на бумаге, получил меня здесь.

Это лучший способ обнаружить подшипник из объекта местоположения на карте Google: ->

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

Формула даст подшипник с использованием координат начальной точки до конечной точки видеть

Следующий код даст вам подшипник (угол между 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));

}

Это работает для меня, надеюсь, что это будет работать и другие

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top