فئة cllocation لحساب الدالة w/ haversine
-
30-09-2019 - |
سؤال
أحاول أن أكتب فئة لـ Cllocation لإعادة المحمل إلى Cllocation آخر.
أعتقد أنني أفعل شيئًا خاطئًا في هذه الصيغة (لا يعتبر النسب الدعوتي القوية). المحمل الذي تم إرجاعه هو دائما خارج.
لقد كنت أبحث في هذا السؤال وحاولت تطبيق التغييرات التي تم قبولها كإجابة صحيحة وصفحة الويب التي تشير إليها:
http://www.movable-type.co.uk/scripts/latlong.html
شكرا على أي مؤشرات. لقد حاولت دمج ردود الفعل من هذا السؤال الآخر وما زلت لا أحصل على شيء ما.
شكرًا
ها هي فئتي -
----- Cllocation+Bearing.H
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
@interface CLLocation (Bearing)
-(double) bearingToLocation:(CLLocation *) destinationLocation;
-(NSString *) compassOrdinalToLocation:(CLLocation *) nwEndPoint;
@end
--------- Cllocation+Bearing.M
#import "CLLocation+Bearing.h"
double DegreesToRadians(double degrees) {return degrees * M_PI / 180;};
double RadiansToDegrees(double radians) {return radians * 180/M_PI;};
@implementation CLLocation (Bearing)
-(double) bearingToLocation:(CLLocation *) destinationLocation {
double lat1 = DegreesToRadians(self.coordinate.latitude);
double lon1 = DegreesToRadians(self.coordinate.longitude);
double lat2 = DegreesToRadians(destinationLocation.coordinate.latitude);
double lon2 = DegreesToRadians(destinationLocation.coordinate.longitude);
double dLon = lon2 - lon1;
double y = sin(dLon) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
double radiansBearing = atan2(y, x);
return RadiansToDegrees(radiansBearing);
}
المحلول
الرمز الخاص بك يبدو جيدا بالنسبة لي. لا حرج في حساب حساب. لا تحدد المدى الذي تبعده عن نتائجك ، ولكن قد تحاول تعديل محولات Radian/Degrees الخاصة بك إلى هذا:
double DegreesToRadians(double degrees) {return degrees * M_PI / 180.0;};
double RadiansToDegrees(double radians) {return radians * 180.0/M_PI;};
إذا كنت تحصل على محامل سلبية ، أضف 2*M_PI
إلى النتيجة النهائية في Radiansbearing (أو 360 إذا قمت بذلك بعد التحويل إلى درجات). ATAN2 يعيد النتيجة في النطاق -M_PI
إلى M_PI
(-180 إلى 180 درجة) ، لذلك قد ترغب في تحويلها إلى محامل البوصلة ، باستخدام شيء مثل الكود التالي
if(radiansBearing < 0.0)
radiansBearing += 2*M_PI;
نصائح أخرى
هذا هو النقل في فئة سريعة في البداية:
import Foundation
import CoreLocation
public extension CLLocation{
func DegreesToRadians(_ degrees: Double ) -> Double {
return degrees * M_PI / 180
}
func RadiansToDegrees(_ radians: Double) -> Double {
return radians * 180 / M_PI
}
func bearingToLocationRadian(_ destinationLocation:CLLocation) -> Double {
let lat1 = DegreesToRadians(self.coordinate.latitude)
let lon1 = DegreesToRadians(self.coordinate.longitude)
let lat2 = DegreesToRadians(destinationLocation.coordinate.latitude);
let lon2 = DegreesToRadians(destinationLocation.coordinate.longitude);
let dLon = lon2 - lon1
let y = sin(dLon) * cos(lat2);
let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
let radiansBearing = atan2(y, x)
return radiansBearing
}
func bearingToLocationDegrees(destinationLocation:CLLocation) -> Double{
return RadiansToDegrees(bearingToLocationRadian(destinationLocation))
}
}
هنا تطبيق آخر
public func bearingBetweenTwoPoints(#lat1 : Double, #lon1 : Double, #lat2 : Double, #lon2: Double) -> Double {
func DegreesToRadians (value:Double) -> Double {
return value * M_PI / 180.0
}
func RadiansToDegrees (value:Double) -> Double {
return value * 180.0 / M_PI
}
let y = sin(lon2-lon1) * cos(lat2)
let x = (cos(lat1) * sin(lat2)) - (sin(lat1) * cos(lat2) * cos(lat2-lon1))
let degrees = RadiansToDegrees(atan2(y,x))
let ret = (degrees + 360) % 360
return ret;
}
العمل سريع 3 و 4
جربت الكثير من الإصدارات وهذا الإليك أخيرًا يعطي القيم الصحيحة!
extension CLLocation {
func getRadiansFrom(degrees: Double ) -> Double {
return degrees * .pi / 180
}
func getDegreesFrom(radians: Double) -> Double {
return radians * 180 / .pi
}
func bearingRadianTo(location: CLLocation) -> Double {
let lat1 = self.getRadiansFrom(degrees: self.coordinate.latitude)
let lon1 = self.getRadiansFrom(degrees: self.coordinate.longitude)
let lat2 = self.getRadiansFrom(degrees: location.coordinate.latitude)
let lon2 = self.getRadiansFrom(degrees: location.coordinate.longitude)
let dLon = lon2 - lon1
let y = sin(dLon) * cos(lat2)
let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon)
var radiansBearing = atan2(y, x)
if radiansBearing < 0.0 {
radiansBearing += 2 * .pi
}
return radiansBearing
}
func bearingDegreesTo(location: CLLocation) -> Double {
return self.getDegreesFrom(radians: self.bearingRadianTo(location: location))
}
}
الاستخدام:
let degrees = location1.bearingDegreesTo(location: location2)
هذا آخر cllocation يمكن استخدام التمديد في سريع 3 و سريع 4
public extension CLLocation {
func degreesToRadians(degrees: Double) -> Double {
return degrees * .pi / 180.0
}
func radiansToDegrees(radians: Double) -> Double {
return radians * 180.0 / .pi
}
func getBearingBetweenTwoPoints(point1: CLLocation, point2: CLLocation) -> Double {
let lat1 = degreesToRadians(degrees: point1.coordinate.latitude)
let lon1 = degreesToRadians(degrees: point1.coordinate.longitude)
let lat2 = degreesToRadians(degrees: point2.coordinate.latitude)
let lon2 = degreesToRadians(degrees: point2.coordinate.longitude)
let dLon = lon2 - lon1
let y = sin(dLon) * cos(lat2)
let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon)
let radiansBearing = atan2(y, x)
return radiansToDegrees(radians: radiansBearing)
}
}
أنا استخدم قانون جيب التمام في سويفت. إنه يعمل بشكل أسرع من هافرين ونتيجةه متشابهة للغاية. تباين 1 متر على مسافات ضخمة.
لماذا أستخدم قانون جيب التمام:
- ركض بسرعة (لأنه لا توجد وظائف SQRT)
- دقيق بما فيه الكفاية ما لم تفعل بعض علم الفلك
- مثالي لمهمة الخلفية
func calculateDistance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> Double {
let π = M_PI
let degToRad: Double = π/180
let earthRadius: Double = 6372797.560856
// Law of Cosines formula
// d = r . arc cos (sin 𝜑A sin 𝜑B + cos 𝜑A cos 𝜑B cos(𝜆B - 𝜆A) )
let 𝜑A = from.latitude * degToRad
let 𝜑B = to.latitude * degToRad
let 𝜆A = from.longitude * degToRad
let 𝜆B = to.longitude * degToRad
let angularDistance = acos(sin(𝜑A) * sin(𝜑B) + cos(𝜑A) * cos(𝜑B) * cos(𝜆B - 𝜆A) )
let distance = earthRadius * angularDistance
return distance
}