67

グーグルマップビューの自分の場所に矢印を表示して、目的地の場所(北ではなく)を基準にした方向を表示したいと思います。

a)磁力計と加速度計のセンサー値を使用して北を計算しました。Googleマップビューで使用されているコンパスと一致しているので、これが正しいことはわかっています。

b)myLocation.bearingTo(destLocation);を使用して、現在地から目的地までの初期方位を計算しました。

最後のステップがありません。これらの2つの値(aとb)から、宛先の場所を基準にして電話が指している方向を取得するためにどの式を使用しますか?

心を落ち着かせるための助けに感謝します!

4

11 に答える 11

69

わかりました、これを理解しました。これを行おうとしている他の人には、次のものが必要です。

a)見出し:ハードウェアコンパスからの見出し。これは磁北の東の度数です

b)方位:現在地から目的地までの方位。これは真北の東の度数です。

myLocation.bearingTo(destLocation);

c)赤緯:真北と磁北の違い

磁力計+加速度計から返される方位は、真の(磁)北(-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)
于 2010-11-30T17:43:18.453 に答える
19

@Damian-アイデアはとても良く、答えには同意しますが、あなたのコードを使用したとき、私は間違った値を持っていたので、私はこれを自分で書きました(誰かがあなたのコメントで同じことを言いました)。赤緯で見出しを数えるのは良いことだと思いますが、後で私はそのようなものを使用しました:

heading = (bearing - heading) * -1;

ダミアンのコードの代わりに:

heading = myBearing - (myBearing + heading); 

0から360の場合は-180から180に変更します。

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

ここで、arrowViewImageView矢印の画像で、100fパラメータpostRotateはpivXとpivYです)。

私は誰かを助けることを願っています。

于 2013-03-12T15:02:22.920 に答える
15

この場合、コンパスの矢印は、現在地からカーバ神殿目的地)への方向を示しています。

このようにbearingToを簡単に使用できます。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内にすべてのコードを記述する必要があります

キブラコンパスの方向の完全なコードはここにあります

 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>
于 2017-05-29T19:14:39.637 に答える
3

私はこれが少し古いことを知っていますが、ここで完全な答えを見つけられなかったグーグルからの私のような人々のために。これが私のアプリからの抜粋で、カスタムリストビュー内に矢印を配置しています。

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

私はそれが単純化されるかもしれないと確信していますが、それは機能します!このコードは新しいSimpleCursorAdapter.ViewBinder()からのものであるため、LastKnownLocationが使用されました

onLocationChangedには、notifyDataSetChanged();への呼び出しが含まれています。

新しいSimpleCursorAdapter.ViewBinder()からもコードを記述して、画像の回転とリスト行の色を設定します(単一のcolumnIndexにのみ適用されます)...

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

私が磁気センサーのドラマを廃止したのではないかと思われるかもしれませんが、私の場合は面倒なことをする価値はありませんでした。グーグルが私をstackoverflowに連れて行ったとき、誰かがこれが私がいつもするのと同じくらい役に立つと思うことを願っています!

于 2014-11-09T08:54:23.990 に答える
2

私は地図の読み取り/ナビゲーションなどの専門家ではありませんが、確かに「方向」は絶対的であり、相対的または実際には相対的ではなく、それ自体が固定/絶対的であるNまたはSに相対的です。

例:あなたと目的地の間に引かれた架空の線が「絶対」SE(磁気Nに対して135度の方位)に対応するとします。ここで、携帯電話が北西を向いていると仮定します。地平線上の架空のオブジェクトから目的地まで架空の線を引くと、携帯電話は現在地を通過し、180度の角度になります。コンパスの意味での180度は、実際にはSを指しますが、目的地は、携帯電話が指している架空のオブジェクトの「Sによる」ものではありません。さらに、その架空の地点に移動した場合、目的地は引き続き移動した場所。

実際には、180度の線は、電話(およびおそらくあなた)が指している方法に対して、目的地が「あなたの後ろ」にあることを示しています。

ただし、目的地に向けてポインタを描画するために、架空の点から目的地までの線の角度を計算する(現在地を通過する)場合は、次の(絶対)方位を差し引くだけです。架空のオブジェクトの絶対方位からの宛先であり、否定(存在する場合)を無視します。たとえば、NW-SEは315-135 = 180なので、画面の下部にある「後ろ」を示すポインタを描画します。

編集:数学が少し間違っていました...大きい方から小さい方の方位を減算し、360から結果を減算して、画面上にポインターを描画する角度を取得します。

于 2010-11-29T23:41:41.167 に答える
1

同じタイムゾーンにいる場合

GPSをUTMに変換する

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

UTM座標により、シンプルなXY2Dが得られます

両方のUTM位置間の角度を計算します

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

これはあなたが北を見ているかのように方向を与えます

ですから、あなたが関連して回転するものは何でも、北はこの角度を引くだけです

両方のポイントの角度がUTM45度で、北の東が5度の場合、矢印は北の40度を指します。

于 2011-06-30T17:08:59.710 に答える
1

これが私がそれをした方法です:

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 );
于 2011-09-11T16:32:00.150 に答える
1

これは、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);

于 2016-06-13T11:50:19.693 に答える
1

式は、始点から終点までの座標を使用して方位を示します。を参照してください。

次のコードはあなたに方位を与えます(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));

}

これは私にとってはうまくいきます他の人にもうまくいくことを願っています

于 2016-09-29T16:22:07.550 に答える
0

私は今それを理解している最中ですが、数学はあなたとあなたのターゲットが真の磁北に対して地球上のどこにあるかに依存しているようです。例えば:

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

方位角については、Sensor.TYPE_ORIENTATIONを参照してください。

偏角についてはgetDeclination()を参照してください

これは、偏角が負(真北の西)であり、theirBearing>yourBearingであると想定しています。

偏角が正で、yourBearing> theirBearingの別のオプションの場合:

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

私はこれを完全にテストしていませんが、紙の角度で遊んで私はここに来ました。

于 2012-08-17T23:52:58.867 に答える
-1

用語:真北と磁北の違いは、偏角ではなく「変動」として知られています。コンパスが読み取るものと磁気方位の違いは「偏差」と呼ばれ、方位によって異なります。コンパススイングは、デバイスエラーを識別し、デバイスに修正が組み込まれている場合に修正を適用できるようにします。磁気コンパスには、任意の見出しのデバイスエラーを説明する偏差カードがあります。

赤緯:アストロナビゲーションで使用される用語:赤緯は緯度のようなものです。星が天の赤道からどれだけ離れているかを報告します。星の赤緯を見つけるには、星から天の赤道まで「真っ直ぐ下」の1時間の円をたどります。星から時間円に沿った天の赤道までの角度は、星の赤緯です。

于 2012-08-08T12:59:39.023 に答える