読者です 読者をやめる 読者になる 読者になる

機械音痴な情報系

そしてエンジニアに…。

【Java】GPSのNMEAフォーマットの情報から経度・緯度を抽出する

public class test1 { public static void main(String[] args) { String gprmc = "$GPRMC,085120.307,A,3542.4488,N,13945.3994,E,000.0,240.3,181211,,,A6A"; String gpgga = "$GPGGA,085120.307,3541.1493,N,13945.3994,E,1,08,1.0,6.9,M,35.9,M,,00005E"; String gpgsa = "$GPGSA,A,3,29,26,05,10,02,27,08,15,,,,,1.8,1.0,1.53E"; String gpgsv = "$GPGSV,3,1,12,26,72,352,28,05,65,066,37,15,50,268,35,27,33,189,377F"; String gpvtg = "$GPVTG,240.3,T,,M,000.0,N,000.0,K,A*08";

String regex = "^\\$GPRMC,..........,A,"; 
Pattern p = Pattern.compile(regex);

check(p, gprmc);
check(p, gpgga);
check(p, gpgsa);
check(p, gpgsv);
check(p, gpvtg);

}

private static void check(Pattern p, String target){ Matcher m=p.matcher(target); int i; double longitude, latitude, longdp, latdp; BigDecimal bd;

if (m.find()){
  String[] strs = target.split(",");
  System.out.println("○ " + target);

  for(i=0; i< strs.length; i++){
  //System.out.println(String.format("%d個目の文字列 : %s",i+1,strs[i]));
    if(i == 3){
      longitude = Double.valueOf(strs[i]);  // 文字列を数値に変換
      //System.out.println(String.format("計算前の値:%f", longitude));

      longitude = longitude/100;  // 整数値を取り出す
      //System.out.println(String.format("÷100:%f", longitude));

      longdp=longitude%1*100/60;  // 小数点以下を取り出し計算
      //System.out.println(String.format("小数点以下を取り出して、計算:%f", long2));

      longitude = Math.floor(longitude); // 取り出した整数値の小数点以下を切り捨て
      longitude = longitude+longdp; // 合計値を計算
      //System.out.println(String.format("合計値:%f", longitude));

      bd = new BigDecimal(longitude);  // 計算した合計値をBigDecimal型に変換

      longitude = bd.setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue(); // 小数点第5位で四捨五入
      System.out.println(String.format("経度:東経 %2.4f", longitude));    // 小数点第4位まで表示 
    }
    if(i == 5){ 
      latitude = Double.valueOf(strs[i]);
      //System.out.println(String.format("計算前の値:%f", latitude));

      latitude = latitude/100; 
      //System.out.println(String.format("÷100:%f", latitude));

      latdp = latitude%1*100/60; 
      //System.out.println(String.format("小数点以下を取り出して、計算:%f", lat2));

      latitude = Math.floor(latitude); 
      latitude = latitude+latdp;
      //System.out.println(String.format("合計値:%f", latitude));

      bd = new BigDecimal(latitude);

      latitude = bd.setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
      System.out.println(String.format("緯度:北緯 %3.4f", latitude))
    }
  }
}else{
  System.out.println("× " + target);
}

} } ||<

  • 実行結果

    || ○ $GPRMC,085120.307,A,3542.4488,N,13945.3994,E,000.0,240.3,181211,,,A6A 経度:東経 35.7075 緯度:北緯 139.7567 × $GPGGA,085120.307,3541.1493,N,13945.3994,E,1,08,1.0,6.9,M,35.9,M,,00005E × $GPGSA,A,3,29,26,05,10,02,27,08,15,,,,,1.8,1.0,1.53E × $GPGSV,3,1,12,26,72,352,28,05,65,066,37,15,50,268,35,27,33,189,377F × $GPVTG,240.3,T,,M,000.0,N,000.0,K,A*08 ||< 因みにGPRMCのステータスがA(有効)ではなく、V(警告)だった場合は、○が×になり、経度も緯度も表示されません。

  • 経度・緯度の計算方法
    例えばGPRMCに

  3542.4488

と表示されているとします。この時下6桁が実際に経度に変換した時に小数点以下を表します。 つまり35の部分が経度の整数部分になります。つまりこんな感じ。

  35      42.4488   ↑       ↑   整数になる  小数になる

「整数になる部分」はそのまま扱えばいいので、小数点以下の部分を計算していきます。これは÷60をするだけなので、

  42.4488/60=0.70748

最後に「整数になる部分」と、「小数になる部分」を足して、

  35.70748

となります。今回はGPSで経度・緯度を取得する対象が日本だけなので、デフォルトで「東経」、「北緯」と書いてあります。また、アプリケーションの仕様の関係から小数点第5位を四捨五入して4位までを表示しています。

小数点以下を取得する方法。値を1で割ったあまりを求める方法が簡単。 実数からの小数部の取得 【OKWave】

文字列を分割し取り出す。 部分文字列の取り出し ( Javaサンプル集 )

BigDecimalクラスを使用して四捨五入をする方法。 Java 四捨五入

絶対もっとスマートな書き方ありそう\(^o^)/ コメントアウトしてるところはデバッグするときに使用したものです。 今回はとりあえず文字列を設定して行ったけど、実際にはTerminalから情報を取得して行いたい。 ターミナルの結果をファイルに出力して、ファイルを読み込む方法くらいしか思い浮かばないなぁ…。

Eclipseではインデント4文字だったのに、コピペしたら8文字になってしまったので、ブログの横幅短いし手動で2文字に直した。なんで8文字になったんだろ…。