7

緯度または経度を2倍に変換する式が

((Degree) + (Minute) / 60 + (Second) / 3600) * ((South || West) ? -1 : 1)

それでは、ダブルから度、分、秒を解析するための式は何ですか?

緯度と経度を解析するための2つの別々の方法があることは理にかなっていますが、doubleからの度、分、秒を解析する方法がわかりません。

ParseLatitude(double value)
{
    //value is South if negative, else is North.
}

ParseLongitude(double value)
{
    //value is West if negative, else is East.
}

座標例:

緯度:43.81234123

経度:-119.8374747

前後に変換する最後のコード。答えてくれたPeterとJamesにもう一度感謝します。これはSilverlightで使用されており、Math.Truncate(double)は使用できないため、をDecimalに変換する必要がありました):

public class Coordinate
{
    public double Degrees { get; set; }
    public double Minutes { get; set; }
    public double Seconds { get; set; }
    public CoordinatesPosition Position { get; set; }

    public Coordinate() { }
    public Coordinate(double value, CoordinatesPosition position)
    {
        //sanity
        if (value < 0 && position == CoordinatesPosition.N)
            position = CoordinatesPosition.S;
        //sanity
        if (value < 0 && position == CoordinatesPosition.E)
            position = CoordinatesPosition.W;
        //sanity
        if (value > 0 && position == CoordinatesPosition.S)
            position = CoordinatesPosition.N;
        //sanity
        if (value > 0 && position == CoordinatesPosition.W)
            position = CoordinatesPosition.E;

        var decimalValue = Convert.ToDecimal(value);

        decimalValue = Math.Abs(decimalValue);

        var degrees = Decimal.Truncate(decimalValue);
        decimalValue = (decimalValue - degrees) * 60;

        var minutes = Decimal.Truncate(decimalValue);
        var seconds = (decimalValue - minutes) * 60;

        Degrees = Convert.ToDouble(degrees);
        Minutes = Convert.ToDouble(minutes);
        Seconds = Convert.ToDouble(seconds);
        Position = position;
    }
    public Coordinate(double degrees, double minutes, double seconds, CoordinatesPosition position)
    {
        Degrees = degrees;
        Minutes = minutes;
        Seconds = seconds;
        Position = position;
    }
    public double ToDouble()
    {
        var result = (Degrees) + (Minutes) / 60 + (Seconds) / 3600;
        return Position == CoordinatesPosition.W || Position == CoordinatesPosition.S ? -result : result;
    }
    public override string ToString()
    {
        return Degrees + "º " + Minutes + "' " + Seconds + "'' " + Position;
    }
}

public enum CoordinatesPosition
{
    N, E, S, W
}

ユニットテスト(nUnit)

[TestFixture]
public class CoordinateTests
{
    [Test]
    public void ShouldConvertDoubleToCoordinateAndBackToDouble()
    {
        const double baseLatitude = 43.81234123;
        const double baseLongitude = -119.8374747;

        var latCoordN = new Coordinate(baseLatitude, CoordinatesPosition.N);
        var latCoordS = new Coordinate(baseLatitude, CoordinatesPosition.S);
        var lonCoordE = new Coordinate(baseLongitude, CoordinatesPosition.E);
        var lonCoordW = new Coordinate(baseLongitude, CoordinatesPosition.W);

        var convertedLatitudeS = latCoordS.ToDouble();
        var convertedLatitudeN = latCoordN.ToDouble();
        var convertedLongitudeW = lonCoordW.ToDouble();
        var convertedLongitudeE = lonCoordE.ToDouble();

        Assert.AreEqual(convertedLatitudeS, convertedLatitudeN);
        Assert.AreEqual(baseLatitude, convertedLatitudeN);
        Assert.AreEqual(convertedLongitudeE, convertedLongitudeW);
        Assert.AreEqual(baseLongitude, convertedLongitudeE);
    }
}
4

5 に答える 5

9
ParseLatitude(double Value)
{
    var direction = Value < 0 ? Direction.South : Direction.North;

    Value = Math.Abs(Value);

    var degrees = Math.Truncate(Value);

    Value = (Value - degrees) * 60;       //not Value = (Value - degrees) / 60;

    var minutes = Math.Truncate(Value);
    var seconds = (Value - minutes) * 60; //not Value = (Value - degrees) / 60;
    //...
}

ParseLongitude(double Value)
{
    var direction = Value < 0 ? Direction.West : Direction.East;

    Value = Math.Abs(Value);

    var degrees = Math.Truncate(Value);

    Value = (Value - degrees) * 60;       //not Value = (Value - degrees) / 60;

    var minutes = Math.Truncate(Value);
    var seconds = (Value - minutes) * 60; //not Value = (Value - degrees) / 60;
    //...
}

編集

最近の賛成票があったので、私はこれに戻りました。これがDRY-erバージョンでValue、最も一般的なコーディング規則を反映するようにパラメーターの名前が変更されています。パラメーターは小文字で始まります。

ParseLatitude(double value)
{
    var direction = value < 0 ? Direction.South : Direction.North;
    return ParseLatituteOrLongitude(value, direction);
}

ParseLongitude(double value)
{
    var direction = value < 0 ? Direction.West : Direction.East;
    return ParseLatituteOrLongitude(value, direction);
}

//This must be a private method because it requires the caller to ensure
//that the direction parameter is correct.
ParseLatitudeOrLongitude(double value, Direction direction)
{
    value = Math.Abs(value);

    var degrees = Math.Truncate(value);

    value = (value - degrees) * 60;       //not Value = (Value - degrees) / 60;

    var minutes = Math.Truncate(value);
    var seconds = (value - minutes) * 60; //not Value = (Value - degrees) / 60;
    //...
}
于 2010-12-21T23:46:52.680 に答える
2
#include <math.h>

void ParseLatitude(double Value, bool &north, double &deg, double &min, double &sec)
{
  if ( Value < 0 )
  {
    ParseLatitude( -Value, north, deg, min, sec );
    north = false;
  }
  else
  {
    north = true;
    deg = floor(Value);
    Value = 60*(Value - deg);
    min = floor(Value);
    Value = 60*(Value - min);
    sec = Value;
  }
}

// ParseLongitude is similar
于 2010-12-21T23:46:29.613 に答える
1

私はこれをたくさん行うクラスをC#で作成しました。おそらくそれは便利です、そうでなければあなたは実装をチェックすることができます:

http://code.google.com/p/exif-utils/source/browse/trunk/ExifUtils/ExifUtils/GpsCoordinate.cs

于 2010-12-21T23:40:42.620 に答える
1

度、分、秒(基数60の算術)を解析することに加えて、緯度の場合は「北/南」、経度の場合は「東/西」に変換される倍精度浮動小数点数の符号を処理することもできます。

北半球で正の緯度を識別し、南半球で負の緯度を識別することはかなり標準的です。ここ西半球では、正の経度をグリニッジ子午線の西の度を意味し、逆に負の経度をその子午線の東の度を意味することも一般的です。ただし、これに適した規則は逆で、グリニッジ子午線の東の度数を負と見なします。クライアントに相談するか、アプリケーションの設計を分析して、この変換に適用される選択肢を決定することをお勧めします。

また、±180での経度の不連続性は、計算の結果として生じる可能性のある座標の変換に注意を払う必要があることにも注意してください。変換が180度子午線でのラップアラウンドを処理することを意図していない場合は、そのような入力に対して例外がスローされる可能性があります。もちろん、設計上の決定はどちらの方法でも文書化する必要があります。

確かに、±90°の範囲外の緯度は入力のエラーです。

追加: 緯度と経度の解析における上記の違い、個別のParseLatitudeおよびParseLongitudeルーチンで処理するのが最適な問題を考えると、共通のユーティリティを使用して、2倍から度/分/秒への変換を行うことができます。

ここでのターゲット言語がわからないので、プレーンバニラCで何かを書きました。

#include <math.h>

void double2DegMinSec(double angle, int *Sign, int *Deg, int *Min, double *Sec)
{ /* extract radix 60 Degrees/Minutes/Seconds from "angle" */

    Sign = 1;  

    if (angle < 0.0)  /* reduce to case of nonnegative angle */  
    {  
         Sign = -Sign;  
         angle = -angle;  
    }  

    *Deg = floor(angle);  
    angle -= *Deg;  
    angle *= 60.0;  
    *Min = floor(angle);  
    angle -= *Min;  
    angle *= 60.0;  
    *Sec = angle;  

    return;  
}  

おそらく、ParseLatitudeとParseLongitudeは、角度の符号の適切な地理的表示への変換を管理する必要がありますが、変換にその符号チェックを実行できるようにする引数Signを含めました(ただし、変換が非負の角度)。

関数double2DegMinSecにreturnタイプのvoidを持たせました。したがって、結果は、int型へのポインタ型とdouble型へのポインタ型の正式な引数を介して返されます(秒の場合、小数部分がある可能性があります)。

Cで変換を呼び出すと、次のようになります。

double longitude = -119.8374747;
int Sign, Degrees, Minutes;
double Seconds;

double2DegMinSec(longitude, &Sign, &Degrees, &Minutes, &Seconds);  

C ++では、ポインターの代わりに参照による呼び出しを使用して、呼び出し構文を少しわかりやすくします。

于 2010-12-22T00:03:08.873 に答える
0

乗算するだけで、気付かないうちに変換エラーが発生するので、地図上のポイントをマッピングするときに気づきました。次のような勾配やその他の変数を考慮する必要があります。

public static void GeoToMercator(double xIn, double yIn, out double xOut, out double yOut)
    {
        double xArg = xIn / 100000, yArg = yIn / 100000;
        xArg = 6371000.0 * Math.PI / 180 * xArg;
        yArg = 6371000.0 * Math.Log(Math.Tan(Math.PI / 4 + Math.PI / 180 * yArg * 0.5));
        xOut = xArg / 10000;
        yOut = yArg / 10000;
    }

メルカトルの値を二重表現として使用していると思います。メルカトル図法の値を正しい経度/緯度の値に戻すには、逆を使用します。

public static void MercatorToGeo(double xIn, double yIn, out double xOut, out double yOut)
    {
        double xArg = xIn, yArg = yIn;
        xArg = 180 / Math.PI * xArg / 6371000.0;
        yArg = 180 / Math.PI * (Math.Atan(Math.Exp(yArg / 6371000.0)) - Math.PI / 4) / 0.5;
        xOut = xArg * 10;
        yOut = yArg * 10;
    }

これは私にとってトリックでした。

于 2011-04-07T11:13:24.610 に答える