سؤال

أرغب في عرض سهم في موقعي على عرض خريطة Google يعرض اتجاهي بالنسبة لموقع الوجهة (بدلاً من الشمال).

أ) قمت بحساب الشمال باستخدام قيم المستشعر من مقياس المغناطيسي ومقياس التسارع. أعلم أن هذا صحيح لأنه يصطف مع البوصلة المستخدمة في عرض خريطة Google.

ب) قمت بحساب المحمل الأولي من موقعي إلى موقع الوجهة باستخدام myLocation.BearingTo (destlocation) ؛

أفتقد الخطوة الأخيرة ؛ من هاتين القيمتين (A & B) ما هي الصيغة التي أستخدمها للحصول على الاتجاه الذي يشير فيه الهاتف إلى موقع الوجهة؟

نقدر أي مساعدة للعقل المدمر!

هل كانت مفيدة؟

المحلول

حسنًا ، لقد اكتشفت هذا. لأي شخص آخر يحاول القيام بذلك تحتاج:

أ) العنوان: تتجه من بوصلة الجهاز. هذا بدرجات شرق مغناطيسي شمال

ب) المحمل: المحمل من موقعك إلى موقع الوجهة. هذا بدرجات شرق حقيقي شمال.

myLocation.bearingTo(destLocation);

ج) الانحراف: الفرق بين الشمال الحقيقي والشمال المغناطيسي

يكون العنوان الذي يتم إرجاعه من مقياس التسارع + مقياس المغنطيسية بدرجات شرقًا من الشمال (المغناطيسي) الشمال (-180 إلى +180) ، لذلك تحتاج إلى الحصول على الفرق بين الشمال الشمالي والمغناطيسي لموقعك. هذا الاختلاف متغير اعتمادًا على مكان وجودك على الأرض. يمكنك الحصول عليها باستخدام فئة Geomagnetic Flass.

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

ثانياً ، تحتاج إلى تعويض الاتجاه الذي يواجهه الهاتف (العنوان) من الوجهة المستهدفة بدلاً من الشمال الحقيقي. هذا هو الجزء الذي علقت فيه. تمنحك قيمة العنوان التي يتم إرجاعها من البوصلة قيمة تصف مكان الشمال المغناطيسي (بالدرجات الشرق من True North) فيما يتعلق بالمكان الذي يشير إليه الهاتف. على سبيل المثال ، إذا كانت القيمة -10 ، فأنت تعلم أن الشمال المغناطيسي هو 10 درجات على يسارك. يمنحك المحمل زاوية وجهتك بالدرجات الشرق من الشمال الحقيقي. لذلك بعد تعويضك عن الانحراف ، يمكنك استخدام الصيغة أدناه للحصول على النتيجة المرجوة:

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 إلى 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 و pivy).

آمل أن أساعد شخص ما.

في هذا السهم على البوصلة ، يظهر الاتجاه من موقعك إلى الكعبة(موقع وجهة)

يمكنك استخدام 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 | 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 نفسها ثابتة / مطلقة.

مثال: لنفترض أن خطًا وهميًا مرسومًا بينك وبين وجهتك يتوافق مع SE "المطلق" (محمل 135 درجة بالنسبة للمغناطيسي N). لنفترض الآن أن هاتفك يشير إلى NW - إذا رسمت خطًا وهميًا من كائن وهمي في الأفق إلى وجهتك ، فسيمر عبر موقعك ويبلغ زاوية 180 درجة. الآن 180 درجة بمعنى البوصلة تشير فعليًا إلى S ، لكن الوجهة ليست "مستحقة" للكائن الوهمي الذي يشير إليه هاتفك ، وعلاوة حيث انتقلت إلى.

في الواقع ، يخبرك خط درجة 180 درجة أن الوجهة هي "خلفك" بالنسبة إلى الطريقة التي يشير بها الهاتف (ويفترض أنك).

ومع ذلك ، بعد ذلك ، إذا كان حساب زاوية خط من النقطة الوهمية إلى وجهتك (مروراً بموقعك) من أجل رسم مؤشر نحو وجهتك هو ما تريد ... ببساطة طرح المحمل (المطلق) الوجهة من تحمل الكائن الخيالي وتجاهل النفي (إذا كان موجودًا). على سبيل المثال ، NW - 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 تحصل على simples xy 2d

احسب الزاوية بين كلا موقعين UTM

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

هذا يعطي الاتجاه كما لو كنت تبحث شمالا

لذا ، كل ما تدويره ذا صلة تفعل الشمال فقط اطرح هذه الزاوية

إذا كان كلا النقطتين يحتويان على زاوية 45 درجة UTM وكنت 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;
}

أرغب في المراهنة على أنه يمكن تبسيطه ولكنه يعمل! تم استخدام Last Swinkinglocation لأن هذا الرمز كان من SimpleCursorAdapter.viewbinder ()

يحتوي OnLocationChanged على دعوة لإعلام dataSteTchanged () ؛

رمز أيضًا من SimpleCursorAdapter.viewBinder () لتعيين دوران الصورة وألوان Listrow (يتم تطبيقه فقط في عقل عمود واحد لك) ...

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 () للانحراف

هذا يفترض أن الانحراف سلبي (غرب الشمال الحقيقي) وحملهم.

إذا كان الانحراف إيجابيًا وحملهم> خيارهم الآخر:

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