私は自分の拡張現実エンジンを開発しようとしています。
インターネットで検索すると、これが便利であることがわかりました チュートリアル 。それを読むと、重要なことは、ユーザーの場所、ポイントの場所、および北の間に関係していることがわかります。
次の写真はそのチュートリアルからのものです。
その後、ベータ版を入手するためのObjective-Cメソッドを作成しました。
+ (float) calculateBetaFrom:(CLLocationCoordinate2D)user to:(CLLocationCoordinate2D)destination
{
double beta = 0;
double a, b = 0;
a = destination.latitude - user.latitude;
b = destination.longitude - user.longitude;
beta = atan2(a, b) * 180.0 / M_PI;
if (beta < 0.0)
beta += 360.0;
else if (beta > 360.0)
beta -= 360;
return beta;
}
しかし、私がそれを試してみると、それはあまりうまくいきません。
そこで、iPhone AR Toolkitをチェックして、どのように機能するかを確認しました(このツールキットを使用してきましたが、私にとってはとても大きいです)。
そして、 ARGeoCoordinate.m には、ベータ版を入手する方法の別の実装があります。
- (float)angleFromCoordinate:(CLLocationCoordinate2D)first toCoordinate:(CLLocationCoordinate2D)second {
float longitudinalDifference = second.longitude - first.longitude;
float latitudinalDifference = second.latitude - first.latitude;
float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);
if (longitudinalDifference > 0)
return possibleAzimuth;
else if (longitudinalDifference < 0)
return possibleAzimuth + M_PI;
else if (latitudinalDifference < 0)
return M_PI;
return 0.0f;
}
次の式を使用します。
float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);
この式に(M_PI * .5f)があるのはなぜですか?わかりません。
そして検索を続けると、別の page 2つの場所の距離と方位を計算する方法について話していることがわかりました。このページには別の実装があります。
/**
* Returns the (initial) bearing from this point to the supplied point, in degrees
* see http://williams.best.vwh.net/avform.htm#Crs
*
* @param {LatLon} point: Latitude/longitude of destination point
* @returns {Number} Initial bearing in degrees from North
*/
LatLon.prototype.bearingTo = function(point) {
var lat1 = this._lat.toRad(), lat2 = point._lat.toRad();
var dLon = (point._lon-this._lon).toRad();
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) -
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
var brng = Math.atan2(y, x);
return (brng.toDeg()+360) % 360;
}
どちらが正しいですか?
方位を計算
//Source
JSONObject source = step.getJSONObject("start_location");
double lat1 = Double.parseDouble(source.getString("lat"));
double lng1 = Double.parseDouble(source.getString("lng"));
// destination
JSONObject destination = step.getJSONObject("end_location");
double lat2 = Double.parseDouble(destination.getString("lat"));
double lng2 = Double.parseDouble(destination.getString("lng"));
double dLon = (lng2-lng1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
double brng = Math.toDegrees((Math.atan2(y, x)));
brng = (360 - ((brng + 360) % 360));
度をラジアンに変換
Radians = Degrees * PI / 180
ラジアンを度に変換
Degrees = Radians * 180 / PI
私はこの質問が古いことを知っていますが、ここにもっと簡単な解決策があります:
フロートベアリング= loc1.bearingTo(loc2);
公式では
float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);
用語 (M_PI * .5f)
は90°であるπ/ 2を意味します。つまり、上の図に関しては、最初に述べたのと同じ式であるということです。
β=アークタン(a/b)= 90°-アークタン(b/a)。
したがって、a
が経度の違いを参照し、b
が緯度の違いを参照する場合、両方の式は類似しています。最後の式は、私の式の最初の部分を使用して同じように計算します。
正確な結果を得るためにこれを試してください:
private static double degreeToRadians(double latLong) {
return (Math.PI * latLong / 180.0);
}
private static double radiansToDegree(double latLong) {
return (latLong * 180.0 / Math.PI);
}
public static double getBearing() {
//Source
JSONObject source = step.getJSONObject("start_location");
double lat1 = Double.parseDouble(source.getString("lat"));
double lng1 = Double.parseDouble(source.getString("lng"));
// destination
JSONObject destination = step.getJSONObject("end_location");
double lat2 = Double.parseDouble(destination.getString("lat"));
double lng2 = Double.parseDouble(destination.getString("lng"));
double fLat = degreeToRadians(lat1);
double fLong = degreeToRadians(lng1);
double tLat = degreeToRadians(lat2);
double tLong = degreeToRadians(lng2);
double dLon = (tLong - fLong);
double degree = radiansToDegree(Math.atan2(sin(dLon) * cos(tLat),
cos(fLat) * sin(tLat) - sin(fLat) * cos(tLat) * cos(dLon)));
if (degree >= 0) {
return degree;
} else {
return 360 + degree;
}
}
http://www.sunearthtools.com/tools/distance.php でベアリングの結果をテストできます。
図のa
は経度の差、b
は緯度の差であるため、作成した方法では、それらの方向が間違っています。
a = destination.latitude - user.latitude; // should be b
b = destination.longitude - user.longitude; // should be a
それらを切り替えて、何が起こるかを確認してください。
残りの質問に対する回答については、Palundの回答を参照してください。
here is the code for calculating bearing angle between two points(startPoint, endPoint):
public float CalculateBearingAngle(double startLatitude,double startLongitude, double endLatitude, double endLongitude){
double Phi1 = Math.toRadians(startLatitude);
double Phi2 = Math.toRadians(endLatitude);
double DeltaLambda = Math.toRadians(endLongitude - startLongitude);
double Theta = atan2((sin(DeltaLambda)*cos(Phi2)) , (cos(Phi1)*sin(Phi2) - sin(Phi1)*cos(Phi2)*cos(DeltaLambda)));
return (float)Math.toDegrees(Theta);
}
call for function:
float angle = CalculateBearingAngle(startLatitude, startLongitude, endLatitude, endLongitude);
import static Java.lang.Math.atan2;
import static Java.lang.Math.cos;
import static Java.lang.Math.sin;
Mixare拡張現実エンジンで使用されているコードを確認したい場合は、githubにあり、iPhoneバージョンもあります:github.com/mixare
/ * Kirit vaghelaの回答が変更されました。Math.sinはラジアン値を与えるため、次数の値を取得するには、Math.sin()またはMath.cos()内でMath.toRadians(value)を渡す必要があります* /
double lat1 = 39.099912;
double lat2 = 38.627089;
double lng1 = -94.581213;
double lng2 = -90.200203;
double dLon = (lng2-lng1);
double x = Math.sin(Math.toRadians(dLon)) * Math.cos(Math.toRadians(lat2));
double y = Math.cos(Math.toRadians(lat1))*Math.sin(Math.toRadians(lat2)) - Math.sin(Math.toRadians(lat1))*Math.cos(Math.toRadians(lat2))*Math.cos(Math.toRadians(dLon));
double bearing = Math.toDegrees((Math.atan2(x, y)));
System.out.println("BearingAngle : "+bearing);