トップ地図ユーティリティ > GPSLog変換

GPSLog変換

前ページ

はじめに

自作地図アプリは8年前にWindows C#で開発したものをAndroidスマホに移植したものであり、 GPSログは8年間の蓄積があり、途中で何回かファイル形式を少し変更している。

過去のGPSログ表示プログラムの簡単化とパフォーマンス向上のために、全てのログを最新フォーマットに変換しておく。

元のGPSログファイル名には日付情報のみを含むが、過去ログ表示用ログファイルの名前には、日付の他に境界ボックス座標値も含める。

地図アプリ起動後、初めて、過去ログを表示するときに、ファイル名一覧を読み込む。

class GPSLog

現在の地図アプリにおける class GPSLog は以下の通りである。

public class GPSLog {
    final static int E7 = 10000000;
    static List listLogs;    // 今日のGPSログ

    LocalDateTime ldt;
    int ilon, ilat, ialt;
    float speed, accuracy = -1;

    public GPSLog(String loc) {
        String[] v = loc.split(",");
        ilon = (int)Math.round(Double.parseDouble(v[1]) * E7);
        ilat = (int)Math.round(Double.parseDouble(v[2]) * E7);
        ialt = (int)Math.round(Double.parseDouble(v[3]));
        speed = Float.parseFloat(v[4]);
        ldt = LocalDateTime.now();      // 2022.5.11
    }

    // 時:分:秒, lon, lat, alt, speed, accuracy,
    //19:52:17,139.5044180,35.5452761,96.4,0.0,9.9
    public GPSLog(int date, String line) {
        String[] v = line.split("[,:]");
        int year = date / 10000;
        int month = (date % 10000) / 100;
        int day = date % 100;
        ldt = LocalDateTime.of(year, month, day,        // 2021/1/1 10:20:30.000
                Integer.parseInt(v[0]), Integer.parseInt(v[1]), Integer.parseInt(v[2]));
        ilon = (int)Math.round(Double.parseDouble(v[3]) * E7);
        ilat = (int)Math.round(Double.parseDouble(v[4]) * E7);
        ialt = (int)Math.round(Double.parseDouble(v[5]));
        if (v.length >= 8) {
            speed    = Float.parseFloat(v[6]);
            accuracy = Float.parseFloat(v[7]);
        }
    }

    public static void LoadGPSLog() {
        LocalDateTime now = LocalDateTime.now();
        int date = now.getYear()*10000 + now.getMonthValue()*100 + now.getDayOfMonth();
        listLogs = LoadGPSLog(date);
    }

    // ファイル読み込み
    public static List LoadGPSLog(int date) {
        List listLogs = new ArrayList<>();
        String file = String.format(Locale.JAPAN, "%sgpslogs/%d.csv", Map.DIR, date);
        int lastLon = 0, lastLat = 0;
        //Log.d("GPSLog", file);
        if (new File(file).exists()) {
            try {
                Path path = Paths.get(file);
                List lines = Files.readAllLines(path);
                for (String line : lines) {
                    GPSLog log = new GPSLog(date, line);
                    if (log.ilon != lastLon || log.ilat != lastLat) {
                        lastLon = log.ilon;
                        lastLat = log.ilat;
                        listLogs.add(log);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return listLogs;
    }
}

初期のデータ(2015.3.14~)は以下の通りである。

448098102,139.504442,35.545372,94.106010

先頭の 448098102 は 2001年1月1日からの通算秒である。Speed および Accuracy はない。

すぐに(2015.4.1~2021.11.30)、時刻のフォーマットを現在の形に変更した。ファイル名は p20150401.csv の形である。

17:45:48,139.504262,35.545331,91.9

したがって、最初の半月分は無視してもよいだろう。

2022.1.27 からスマホの地図アプリで現在のフォーマットとした。2021.12.1 から 2022.1.26 の2か月弱はGPSログはとっていない。 ファイル名は 20220127.csv の形とした。


Speed は徒歩か車かの区別に利用している。単位は「m/秒」である。Windows時代にはこの値を取得、保存していなかった。 この値がある方が表示プログラムの負担が減るので、補うことにする。

Windowsのときは極座標で直接、徒歩か車かを判定していたが、今回は、次のプログラムで、2点間の極座標から2点間の距離(単位:m)を求めて、 その値を2点間の時刻差(単位:秒)で割って、速度(m/秒単位)とする。

    double deg2rad(double deg) { return (deg/180.0)*Math.PI; }

    double calculateDistance(double lonA, double latA, double lonB, double latB) {
        double latAvg = deg2rad(latA + ((latB - latA) / 2));
        double latDifference = deg2rad(latA - latB);
        double lonDifference = deg2rad(lonA - lonB);
        double curRadiusTemp = 1 - 0.00669438 * Math.pow(Math.sin(latAvg), 2);
        double meridianCurvatureRadius = 6335439.327/Math.sqrt(Math.pow(curRadiusTemp,3));
        double primeVerticalCircleCurvatureRadius = 6378137 / Math.sqrt(curRadiusTemp);
        double distance2 = Math.pow(meridianCurvatureRadius*latDifference,2) +
                Math.pow(primeVerticalCircleCurvatureRadius*Math.cos(latAvg)*lonDifference,2);
        return Math.sqrt(distance2);
    }

GPSLogIndex & GPSLog

class GPSLogIndex を追加した。class GPSLog を少し修正した。

class GPSLogIndex {
    final static double E7 = 10000000.0;
    static GPSLogIndex[] indexes;         // 地図アプリ起動時に読込む

    int date;       // ex. 20231009
    int minLon, minLat, maxLon, maxLat;
    Rect rect;
    String filename;

    public GPSLogIndex (int date, int minLon, int minLat, int maxLon, int maxLat) {
        this.date = date;
        this.minLon = minLon;
        this.minLat = minLat;
        this.maxLon = maxLon;
        this.maxLat = maxLat;
        rect = new Rect(minLon, minLat, maxLon, maxLat);
    }

    public GPSLogIndex (String filename) {
        String[] v = filename.split("[_\\.]");

        this.filename = filename;
        this.date = Integer.parseInt(v[0]);
        this.minLon = Integer.parseInt(v[1]);
        this.minLat = Integer.parseInt(v[2]);
        this.maxLon = Integer.parseInt(v[3]);
        this.maxLat = Integer.parseInt(v[4]);

        rect = new Rect(minLon, minLat, maxLon, maxLat);
    }


    static void loadGPSLogIndex() {
        File directory = new File(Map.DIR + "p_gpslogs");
        String[] files = directory.list();
        Arrays.sort(files); // 日付が古い順
        System.out.printf("GPSログ・ファイル数: %d\n", files.length);
        indexes = new GPSLogIndex[files.length];
        for (int n = 0; n < indexes.length; n++) {
            String filename = files[indexes.length-1-n];    // 新しい順
            //String[] v = filename.split("[_\\.]");
            indexes[n] = new GPSLogIndex(filename);
        }

    }
}

class GPSLog {
    final static int E7 = 10000000;
    static List<GPSLog> listLogs;    // 今日のGPSログ

    LocalDateTime ldt;
    int ilon, ilat, ialt;
    float speed, accuracy = -1;

    public GPSLog(String loc) {
        String[] v = loc.split(",");
        ilon = (int)Math.round(Double.parseDouble(v[1]) * E7);
        ilat = (int)Math.round(Double.parseDouble(v[2]) * E7);
        ialt = (int)Math.round(Double.parseDouble(v[3]));
        speed = Float.parseFloat(v[4]);
        ldt = LocalDateTime.now();      // 2022.5.11
    }

    //19:52:17,139.5944180,35.5952761,96.4,0.0,9.9
    public GPSLog(int date, String line) {
        String[] v = line.split("[,:]");
        int year = date / 10000;
        int month = (date % 10000) / 100;
        int day = date % 100;
        ldt = LocalDateTime.of(year, month, day,        // 2021/1/1 10:20:30.000
                Integer.parseInt(v[0]), Integer.parseInt(v[1]), Integer.parseInt(v[2]));
        ilon = (int)Math.round(Double.parseDouble(v[3]) * E7);
        ilat = (int)Math.round(Double.parseDouble(v[4]) * E7);
        ialt = (int)Math.round(Double.parseDouble(v[5]));
        if (v.length >= 8) {
            speed    = Float.parseFloat(v[6]);
            accuracy = Float.parseFloat(v[7]);
        }
    }

    // その日のファイル読み込み
    public static void LoadGPSLog() {
        LocalDateTime now = LocalDateTime.now();
        int date = now.getYear()*10000 + now.getMonthValue()*100 + now.getDayOfMonth();
        listLogs = LoadGPSLog(date);
    }

    // 変換ファイル読み込み
    public static List<GPSLog> LoadGPSLog(String filename) {
        List<GPSLog> listLogs = new ArrayList<>();
        String file = Map.DIR + "p_gpslogs/" + filename;
        int lastLon = 0, lastLat = 0;
        Log.d("GPSLog", file);
        if (new File(file).exists()) {
            try {
                Path path = Paths.get(file);
                List<String> lines = Files.readAllLines(path);
                for (String line : lines) {
                    GPSLog log = new GPSLog(line);
                    if (log.ilon != lastLon || log.ilat != lastLat) {
                        lastLon = log.ilon;
                        lastLat = log.ilat;
                        listLogs.add(log);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Log.d("GPSLog no", file);
        }
        return listLogs;
    }

    // 元ファイルの読み込み
    public static List<GPSLog> LoadGPSLog(int date) {
        List<GPSLog> listLogs = new ArrayList<>();
        String file = String.format(Locale.JAPAN, "%sgpslogs/%d.csv", Map.DIR, date);
        int lastLon = 0, lastLat = 0;
        Log.d("GPSLog", file);
        if (new File(file).exists()) {
            try {
                Path path = Paths.get(file);
                List<String> lines = Files.readAllLines(path);
                for (String line : lines) {
                    GPSLog log = new GPSLog(date, line);
                    if (log.ilon != lastLon || log.ilat != lastLat) {
                        lastLon = log.ilon;
                        lastLat = log.ilat;
                        listLogs.add(log);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Log.d("GPSLog no", file);
        }
        return listLogs;
    }
}

GPSログ表示プログラム(class Map)

とりあえず以下のプログラムでGPSLog履歴が表示できるようになった。 この後、少しずつ改良したい。

    void drawHistories(Canvas canvas, int days) {
        int k = 0;
        Rect rectScreen = getRect();
        System.out.printf("%d %d %d %d\n",
                rectScreen.left, rectScreen.top, rectScreen.right, rectScreen.bottom);
        for (int n = 0; n < GPSLogIndex.indexes.length; n++) {
            GPSLogIndex idx = GPSLogIndex.indexes[n];    // 新しい順
            if (idx.rect.intersect(rectScreen)) {
                if (k++ >= days) break;
                System.out.printf("%d/%d %s\n", k, n, idx.filename);
                drawHistory(canvas, idx.filename, 0xff000000);
            }
        }
    }

    void drawHistory(Canvas canvas, String filename, int color) {
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(1.5f*Map.Scale);
        List<GPSLog> logs = GPSLog.LoadGPSLog(filename);
        if (logs.size() == 0) return;
        float xB = getX(logs.get(0).ilon);
        float yB = getY(logs.get(0).ilat);
        LocalDateTime tB = logs.get(0).ldt;
        for (int n = 1; n < logs.size(); n++) {
            GPSLog log = logs.get(n);
            float xE = getX(log.ilon);
            float yE = getY(log.ilat);
            LocalDateTime tE = log.ldt;
            if (ChronoUnit.MINUTES.between(tB,tE) < 5) {    // 2023.9.20
                paint.setColor(color);
                //System.out.printf("(%f %f) (%f %f)\n", xB, yB, xE, yE);
                canvas.drawLine(xB, yB, xE, yE, paint);
            }
            xB = xE;
            yB = yE;
            tB = tE;
        }
    }

リファレンス

[1]