緯度経度を表示

解決


ゆうた  2012-01-25 01:10:54  No: 147468

VB.NETで、
緯度:DDMMSS.SSSS
経度:DDDMMSS.SSSS
のDouble型数値があります。
これを例えば
136°40'10.123
と表示するため、DDとMMとSS.SSSSに分離する方法を
探しています。
一旦String型にしてRightを使おうかと考えましたが、
地球上の位置によっては負の値もとり得るので、
どうしようか考えています。
お勧めの関数などご存知のかたいらっしゃいますか。


魔界の仮面弁士  2012-01-25 03:15:55  No: 147469

> 緯度:DDMMSS.SSSS
> 経度:DDDMMSS.SSSS
> のDouble型数値があります。
> これを例えば
> 136°40'10.123
> と表示するため、

小数部は 3 桁でしょうか? 4 桁でしょうか?

Decimal 型とは異なり、Double 型は小数点以下の桁数を保持しないため、
10.1230 と 10.123 を区別することはできません。

> DDとMMとSS.SSSSに分離する方法を
桁数固定で良いなら、書式指定して文字列化してから切り出せば良いと思います。
または、割り算して商と余りを求めるとか。

Dim dbl As Double = 1355010.123R

MsgBox((dbl \ 10000).ToString("+0°;-0°") & _
       CStr(Math.Abs(dbl \ 10000)) & "'" & _
       Math.Abs(dbl Mod 100.0R).ToString("F3"))

If dbl = 0.0R Then
    MsgBox("赤道直下")
Else
    MsgBox(String.Format("{0}経 {1}°{2}'{3:F3}", _
                    If(dbl > 0, "東", "西"), _
                    dbl \ 10000, _
                    (dbl \ 100) Mod 100, _
                    dbl Mod 100.0R))
End If


ゆうた  2012-01-25 07:14:06  No: 147470

魔界の仮面弁士さん、ありがとうございます。
小数部は4桁です。
もともとNMEAセンテンスで得られた数値が小数点以下4桁まで
のデータでしたが、
構文解析の過程で結果がDouble型にキャストされたものです。

やはり有効桁が明らかであるならば、一旦
String型に直してから加工するほうがよさそうですね。
ご提案いただいた方法はかねてからイメージしていた対処に
近いものなので、これがベストとして検討します。
たまに○○関数を知らないばかりに長々としたコードを
書いてることが多いもので(汗

というより、もうできちゃってますよね・・・しかも境界条件
分岐まで考慮されてるし・・・

駄目だ、怠けてしまいます、
もっと工夫してもっといいコードに改良します!


魔界の仮面弁士  2012-01-25 20:04:50  No: 147471

> というより、もうできちゃってますよね・・・しかも境界条件
> 分岐まで考慮されてるし・・・
先のコードは、まだ完成していなかったりします(西経値を入力してみてください)。

個々の演算子やメソッドが、どういう働きをしているのかを調べながら、
正しい結果になるように手を加えてみてください。


ゆうた  2012-01-31 22:10:19  No: 147472

質問の趣旨と異なるかと思いますが、
生データddmm.mmmmmから処理する関数を作りました。
経度も同じ手順でできるはずです。
魔界の仮面弁士の提示いただいた文字列処理で作り直したら
違うものになってしまいました。

切捨て関数であるToRoundDown関数はネットにあったものを拝借しました。

' ddmm.mmmmm型の緯度データをdd°mm’ss.sssss’’に変換
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 Dim minusFlag As Boolean
 Dim dmmLatDbl As Double
 Dim dmmLatDec As Decimal
 Dim dmsLatStr As String
 Dim deg As Decimal
 Dim min As Decimal
 Dim sec As Decimal
 Dim minInt As Integer

 dmmLatDbl = 4344.77894
 If (dmmLatDbl < 0) Then ' 負の場合はフラグで処理
  minusFlag = True
  dmmLatDbl = Math.Abs(dmmLatDbl)
 Else
  minusFlag = False
 End If

 dmmLatDec = CDec(dmmLatDbl) ' Double型をDecimal型に変換
 dmmLatDec = dmmLatDec

 If (dmmLatDec <> 0.0) Then
  deg = Math.Truncate(dmmLatDec / 100.0)          ' 度をdegに
  min = ToRoundDown(dmmLatDec - (deg * 100.0), 5) ' 分をminに
  minInt = Fix(min)                               ' 分の整数部
  sec = (min - Math.Truncate(min)) * 60  ' minの小数点以下をsecに

  dmsLatStr = Convert.ToString(deg)
  dmsLatStr = dmsLatStr & "°"
  dmsLatStr = dmsLatStr & Convert.ToString(minInt)
  dmsLatStr = dmsLatStr & "’"
  dmsLatStr = dmsLatStr & Convert.ToString(sec)
  dmsLatStr = dmsLatStr & "’’"

  If (minusFlag = False) Then
   dmsLatStr = "N " & dmsLatStr
  Else
   dmsLatStr = "S " & dmsLatStr
  End If
 MessageBox.Show(dmsLatStr)
 Else
  dmsLatStr = Convert.ToString(0.0)
  MessageBox.Show(dmsLatStr)
 End If
End Sub
''' ------------------------------------------------------------------------
    ''' <summary>
    '''     指定した精度の数値に切り捨てします。</summary>
    ''' <param name="dValue">
    '''     丸め対象の倍精度浮動小数点数。</param>
    ''' <param name="iDigits">
    '''     戻り値の有効桁数の精度。</param>
    ''' <returns>
    '''     iDigits に等しい精度の数値に切り捨てられた数値。</returns>
''' ------------------------------------------------------------------------
Public Shared Function ToRoundDown(ByVal dValue As Double, ByVal iDigits As Integer) As Double
 Dim dCoef As Double = System.Math.Pow(10, iDigits)

 If dValue > 0 Then
  Return System.Math.Floor(dValue * dCoef) / dCoef
 Else
  Return System.Math.Ceiling(dValue * dCoef) / dCoef
 End If
End Function


※返信する前に利用規約をご確認ください。




  


  このエントリーをはてなブックマークに追加