我想在我的位置显示在Google Map View上的箭头,该箭头相对于目的地位置(而不是北)显示了我的方向。

a)我使用磁力计和加速度计的传感器值计算了北。我知道这是正确的,因为它与Google Map View上使用的指南针保持一致。

b)我使用mylocation.bearingto(destlocation)计算了从我的位置到目标位置的初始轴承;

我错过了最后一步;从这两个值(A&B)中,我使用什么公式来获取手机指向目标位置的方向?

感谢您的帮助!

有帮助吗?

解决方案

好的,我想出了这一点。对于其他任何尝试这样做的人,您都需要:

a)标题:您从硬件指南针走向。这是位于 磁的

b)轴承:从您的位置到目的地位置的轴承。这是位于 真的 北。

myLocation.bearingTo(destLocation);

c)偏斜:真实北部和磁性北部的差异

从磁力计 +加速度计返回的标题位于True(磁)北部(-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()
      );
      ...
   }
}

用这些武装,您计算出箭头的角度,以在地图上绘制箭头,以显示与目标对象相对于目标对象而不是true North所面对的位置。

首先通过偏斜调整标题:

heading += geoField.getDeclination();

其次,您需要抵消手机从目标目的地而不是true North朝向(标题)的方向。这是我被困的部分。从指南针返回的标题值为您提供了与手机指向的位置相关的磁性北部所在位置(位于True North的程度)的值。因此,例如,如果值为-10,则知道磁性北方的左侧为10度。轴承使您在True North以东的程度上为您提供目的地的角度。因此,在赔偿偏差之后,您可以使用以下公式获得所需的结果:

heading = myBearing - (myBearing + heading); 

然后,您将需要从True North(-180至+180)以东的学位转换为正常学位(0至360):

Math.round(-heading / 360 + 180)

其他提示

@Damian-这个想法非常好,我同意答案,但是当我使用您的代码时,我的价值观错误,所以我自己写了这一点(有人在您的评论中说了同样的话)。我认为,计数偏差的前进是好的,但是后来我使用了类似的东西:

heading = (bearing - heading) * -1;

而不是达米安的代码:

heading = myBearing - (myBearing + heading); 

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

在哪里 arrowViewImageView 带有箭头图片和100F参数 postRotate 是Pivx和Pivy)。

我希望我会帮助某人。

在此中,指南针上的箭头显示了从您的位置到 Kaaba(目的地位置)

您可以以这种方式简单地使用轴承。bearing将为您提供从位置到目的地位置的直接角度

  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,以获取正确的旋转。

这是我们真正想要的表格,与Beyingto给我们的东西相比

+-----------+--------------+
| 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中写入所有代码

完整的代码在这里用于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;
}

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相对于固定 /绝对是n或s。

示例:假设您和目的地之间绘制的假想线与“绝对” SE相对应(相对于磁N的轴承为135度)。现在假设您的手机指向NW-如果您从地平线上的虚构对象到目的地绘制一个虚线,它将穿过您的位置并具有180度的角度。现在,从指南针的意义上讲,现在180度是指s,但目的地不是您手机指向的虚构对象的“应得的”您搬到哪里。

实际上,相对于手机(可能是您)指向的方式,180度线实际上告诉您目的地“在您后面”。

话虽如此,但是,如果计算从想象点到目的地(通过位置)以便向目的地画出指针的线的角度是您想要的...来自虚构对象的绝对轴承的目的地,忽略否定(如果存在)。例如,西北 - SE IS IS 315-135 = 180,因此将指向指向屏幕底部的指针绘制指示“在您后面”的底部。

编辑: 我的数学略有错误...从较大的轴承中减去较小的轴承,然后从360减去结果,以获取在屏幕上绘制指针的角度。

如果您在同一时区

将GPS转换为UTM

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

utm坐标为您提供一个简单的XY 2D

计算两个UTM位置之间的角度

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

这给出了方向,好像您在向北看

因此,无论您旋转什么相关的北部都会减去这个角度

如果两个点具有UTM45º度角,并且在北部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 );

我知道这有点古老,但是为了我像我这样的人,从这里找不到完整答案。以下是我的应用程序中的一些摘录,这些提取物将箭头放入自定义ListView中。

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

我愿意打赌它可以简化,但可以使用!由于此代码来自new SimpleCursorAdapter.viewbinder(),因此使用了LastnoningLocation。

OnlocationChanged包含一个通知DataSetchanged();

也从新的SimpleCursorAdapter.viewbinder()设置图像旋转和listrow颜色(仅在单个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); 
}

如果您想知道我已经取消了磁性传感器的戏剧,那就不值得麻烦了。我希望有人发现这就像我通常的时机一样有用,当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导航中使用的术语:偏差就像纬度。它报告了恒星距离天体赤道有多远。为了找到一颗星星的偏斜,沿着一个小时的圆圈从恒星到天体赤道“笔直”。沿小时圆的恒星到天体赤道的角度是恒星的偏斜。

我现在正在弄清楚它,但似乎数学取决于您和您的目标相对于真实和磁性北部的地球上的位置。例如:

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

有关方位角,请参见Sensor.Type_orientation。

请参阅GetDeclination()以获取拒绝

这假设偏斜是负面的(在True North的西部)和他们的繁重>您的bear弱。

如果拒绝是积极的,那么您的态度>他们的其他选择:

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