[PYTHON] Versuchen Sie, die Eisenbahndaten der nationalen Landnummern in 3D anzuzeigen

Lassen Sie uns die Eisenbahnstrecken, die aus den Eisenbahndaten der nationalen Landnummerninformationen erhalten werden können, in 3D anzeigen.

Demo http://needtec.sakura.ne.jp/threemap/railroad3d_example.html

** Clientseitige Quelle ** https://github.com/mima3/threemap

** Serverseitige Quelle ** https://github.com/mima3/kokudo

路線2.png

Serverseitige Verarbeitung

Die serverseitige Verarbeitung gibt die gespeicherten nationalen Eisenbahndaten für numerische Landinformationen unter den angeforderten Bedingungen zurück. Zu diesem Zeitpunkt werden Höhendaten hinzugefügt.

Importieren Sie Eisenbahndaten aus nationalen numerischen Landinformationen in Spatialite

Importieren Sie Eisenbahninformationen von nationalen numerischen Landinformationen in Spatialite.

Die Funktionsweise von Spatialit ist wie folgt. https://github.com/mima3/kokudo/blob/master/kokudo_db.py

Führen Sie den folgenden Befehl aus, um die Formdatei der Eisenbahndaten der nationalen Landnummerninformationen in die Datenbank zu importieren.

python import_railroad_section.py C:\tool\spatialite\mod_spatialite-4.2.0-win-x86\mod_spatialite.dll test.sqlite original_data\N02-13\N02-13_RailroadSection.shp

Ermöglichen Sie das Abrufen von GeoJson über HTTP.

Ermöglicht das Abrufen von Geojson für eine bestimmte Route aus einer Datenbank, die über HTTP mit Bottle erstellt wurde.

** Beispiel anrufen ** http://needtec.sakura.ne.jp/kokudo/json/get_railroad_section?operationCompany=%E6%9D%B1%E4%BA%AC%E6%80%A5%E8%A1%8C%E9%9B%BB%E9%89%84

In diesem Beispiel werden alle Strecken der Tokyo Express Railway erfasst.

Ermitteln Sie die Höhe mithilfe der Kartenhöhen-API des Geographical Institute

Die Eisenbahndaten der nationalen Landnummerninformationen haben Längen- und Breitengrad, jedoch keine Höhe. Es macht keinen Sinn, es in 3D anzuzeigen.

Daher werden wir es ermöglichen, die Höhe aus dem Längen- und Breitengrad zu erhalten. Verwenden Sie dazu die Kartenhöhen-API des Geographical Institute.

http://portal.cyberjapan.jp/help/development/api.html

** Anwendungsbeispiel: ** http://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=140.08531&lat=36.103543&outtype=JSON

Ergebnis

{"elevation":25.3,"hsrc":"5m\uff08\u30ec\u30fc\u30b6\uff09"}

Es ist jedoch sinnlos, diese API jedes Mal auszuführen. Stellen Sie daher sicher, dass Sie den Inhalt zwischenspeichern, sobald er in der Datenbank gelesen wurde.

py:https://github.com/mima3/kokudo/blob/master/gsi_api.py


# -*- coding: utf-8 -*-
import urllib
import urllib2
from peewee import *
from playhouse.sqlite_ext import SqliteExtDatabase
import json


database_proxy = Proxy()  # Create a proxy for our db.


def get_elevation_by_api(long, lat):
    """
Erfassung des Höhenwertes
    http://portal.cyberjapan.jp/help/development/api.html
    """
    url = ('http://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=%f&lat=%f&outtype=JSON' % (long, lat))
    req = urllib2.Request(url)
    opener = urllib2.build_opener()
    conn = opener.open(req)
    cont = conn.read()
    ret = json.loads(cont)
    return ret


def str_isfloat(str):
    try:
        float(str)
        return True
    except ValueError:
        return False


class ElevationCache(Model):
    """
Höhen-Cache-Tabelle
    """
    lat = FloatField(index=True)
    long = FloatField(index=True)
    hsrc = TextField(index=True)
    elevation = FloatField(null=True)


    class Meta:
        database = database_proxy

def connect(path):
    db = SqliteExtDatabase(path)
    database_proxy.initialize(db)


def setup(path):
    connect(path)
    database_proxy.create_tables([ElevationCache], True)


def get_elevation(long, lat):
    try:
        ret = ElevationCache.get((ElevationCache.long==long) & (ElevationCache.lat==lat))
        return {'elevation': ret.elevation, 'hsrc': ret.hsrc}

    except ElevationCache.DoesNotExist:
        ret = get_elevation_by_api(long, lat)
        elevation = ret['elevation']
        if not str_isfloat(elevation):
            elevation = None
        ElevationCache.create(
            long = long,
            lat = lat,
            elevation = elevation,
            hsrc = ret['hsrc']
        )
        return ret


class GsiConvertError(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)


def convert_geojson(json):
    for feature in json['features']:
        if feature['geometry']['type'] == 'LineString':
            prop = {}
            start = feature['geometry']['coordinates'][0]
            end = feature['geometry']['coordinates'][len(feature['geometry']['coordinates'])-1]
            start_elevation = get_elevation(start[0], start[1])
            end_elevation = get_elevation(end[0], end[1])
            feature['properties']['start_elevation'] = start_elevation['elevation']
            feature['properties']['end_elevation'] = end_elevation['elevation']
        else:
            raise GsiConvertError('unexpected feature type')
    return json

if __name__ == '__main__':
    setup('elevation_cache.sqlite')
    #print get_elevation_by_api(133, 39)
    #print get_elevation_by_api(139.766084, 35.681382)

    print get_elevation(133, 39)
    print get_elevation(139.766084, 35.681382)
    with open('get_railroad_section.geojson' , 'rb') as f:
        cont = f.read()
        print convert_geojson(json.loads(cont))

Die Funktion get_elevation ermittelt die Höhe aus Längen- und Breitengrad. Wenn der Wert zu diesem Zeitpunkt bereits in der Datenbank gespeichert ist, wird er zurückgegeben. Wenn er nicht gespeichert ist, wird die Höhen-API ausgeführt, und das Ergebnis wird in der Datenbank gespeichert und zurückgegeben.

Die Funktion convert_geojson gibt dem GeoJson von LineString eine Höhe. Ruft die Höhe für den Start- und Endpunkt der Linie ab und speichert die Ergebnisse in den Eigenschaften als start_elevation, end_elevation.

Holen Sie sich GeoJSON von Eisenbahndaten mit Höhendaten.

** Anwendungsbeispiel ** http://needtec.sakura.ne.jp/kokudo/json/get_railroad_section?operationCompany=%E6%9D%B1%E4%BA%AC%E6%80%A5%E8%A1%8C%E9%9B%BB%E9%89%84&embed_elevation=True

Die Höhe kann durch Hinzufügen von embedded_elevation ermittelt werden.

** Akquisitionsergebnis **

{
  "type": "FeatureCollection", 
  "features": [
    {
      "geometry": {
        "type": "LineString", 
        "coordinates": [[139.48677, 35.55760999999999], [139.4865599999999, 35.55839]]
      }, 
      "type": "Feature", 
      "properties": {
        "operationCompany": "\u6771\u4eac\u6025\u884c\u96fb\u9244",
        "end_elevation": 36.7, 
        "serviceProviderType": "4", 
        "railwayLineName": "\u3053\u3069\u3082\u306e\u56fd\u7dda",
        "railwayType": "12", 
        "start_elevation": 35.4
      }
    },//Abkürzung
  ]
} 

Clientseitige Verarbeitung

Die Verarbeitung auf der Client-Seite ist wie folgt.

    1. Fügen Sie die z-Achse des erfassten GeoJSON hinzu. Zu diesem Zeitpunkt sind der Startpunkt und der Endpunkt die in den Eigenschaften angegebene Höhe, und die anderen Punkte sind das Verhältnis unter Berücksichtigung des Startpunkts und des Endpunkts.
  1. Linien, die kombiniert werden können, werden kombiniert
    1. Zeichnen von Routen mit Tube Geometry in three.js

Fügen Sie die z-Achse des erfassten GeoJSON hinzu

Fügen Sie für alle Koordinaten eine Höhe auf der Z-Achse hinzu, indem Sie start_elevation und end_elevation in den unten gezeigten Eigenschaften verwenden.

    function expendElevation(features) {
      for (var i = 0; i < features.length; ++i) {
        var feature = features[i];
        var end_elevation = feature.properties.end_elevation;
        var start_elevation = feature.properties.start_elevation;
        var per_elevation = (end_elevation - start_elevation) / feature.geometry.coordinates.length;
        for (var j = 0; j < feature.geometry.coordinates.length; ++j) {
            feature.geometry.coordinates[j].push(start_elevation + (j * per_elevation));
        }
      }
      return features;
    }

Linien, die kombiniert werden können, werden kombiniert

Wenn beispielsweise der Startpunkt eines Features und der Endpunkt eines anderen Features gleich sind, werden sie kombiniert und als eine Linie betrachtet.

    function compressionLine(features) {
      var before = features.length;
      for (var i = 0; i < features.length; ++i) {
        for (var j = features.length -1; i < j; --j) {
          var f1Start = features[i].geometry.coordinates[0];
          var f1End = features[i].geometry.coordinates[features[i].geometry.coordinates.length-1];

          var f2Start = features[j].geometry.coordinates[0];
          var f2End = features[j].geometry.coordinates[features[j].geometry.coordinates.length-1];

          //Wenn der Startpunkt von f1 mit dem Endpunkt von f2 übereinstimmt, steht f2 vor f1.
          if (f1Start[0] == f2End[0] && f1Start[1] == f2End[1]) {
            features[i].geometry.coordinates = features[j].geometry.coordinates.concat(features[i].geometry.coordinates);
            features.splice(j, 1);
            break;
          }
          //Wenn der Endpunkt von f1 mit dem Startpunkt von f2 übereinstimmt, gibt es f2 nach f1
          if (f1End[0] == f2Start[0] && f1End[1] == f2Start[1]) {
            features[i].geometry.coordinates = features[i].geometry.coordinates.concat(features[j].geometry.coordinates);
            features.splice(j, 1);
            break;
          }
        }
      }
      if (features.length == before) {
        return features;
      }
      return compressionLine(features);
    }

Zeichnen einer Route mithilfe der Rohrgeometrie

Zeichnen Sie eine Route mit TubeGeometry. Bestimmen Sie die Position der Netzposition mit den Koordinaten des Startpunkts als Versatz. Geben Sie für andere Punkte beim Hinzufügen als TubeGeometry-Pfad relative Koordinaten zum Startpunkt an.

    function createRailroad(geodata) {
      console.log(geodata.length);
      geodata = expendElevation(geodata);
      geodata = compressionLine(geodata);
      console.log(geodata.length);
      var scaleElevation = 100;
      for (var i = 0 ; i < geodata.length ; i++) {
        var lineList = [];
        var geoFeature = geodata[i];
        var baseX;
        var baseY;
        for (var j = 0; j < geoFeature.geometry.coordinates.length; ++j) {
          var pt = reverseProjection([
            geoFeature.geometry.coordinates[j][0],
            geoFeature.geometry.coordinates[j][1]
          ]);
          if (j ==0) {
            baseX = pt[0];
            baseY = pt[1];
            lineList.push(new THREE.Vector3(0, 0, geoFeature.geometry.coordinates[j][2] / scaleElevation));
          } else {
            lineList.push(new THREE.Vector3(pt[0] - baseX, pt[1] - baseY, geoFeature.geometry.coordinates[j][2] /scaleElevation));
          }
        }
        var spline = new THREE.SplineCurve3(lineList);
        var tubeGeo = new THREE.TubeGeometry(spline, 32, 0.03, 8, false);
        var mesh = new THREE.Mesh(
          tubeGeo,
          new THREE.MeshLambertMaterial( { 
            color: 0xff0000,
            transparent: true,
            opacity: 0.9
          })
        );
        mesh.position.set(baseX, baseY, 0.1);
        scene.add(mesh);
      }
    }

Zu diesem Zeitpunkt verwendet die umgekehrte Projektion, die zum Abrufen der Koordinaten aus dem Längen- und Breitengrad verwendet wird, die Projektion von d3.geo.path () wie folgt.

Inhalt der Rückprojektion


    //Da es verkehrt herum ist, ist es stickig
    var reverseProjection = function(x, y) {
      pt = projection(x, y);
      pt[1] *= -1;
      return pt;
    };

    //Erstellen Sie eine Funktion zum Konvertieren von GeoJSON-Daten in einen Pfad
    var path = d3.geo.path().projection(reverseProjection);

Zusammenfassung

Geojson kann dynamisch erstellt werden, indem die Eisenbahndaten der nationalen Landnummerninformationen in Spatialite gespeichert werden.

Wenn Sie die Höhen-API des Geografischen Instituts verwenden, können Sie die Höhe von Breiten- und Längengrad abrufen. Zu diesem Zeitpunkt ist es besser, das Ergebnis zwischenzuspeichern.

Wenn Sie three.js verwenden, können Sie problemlos 3D-Ausdrücke ausführen. Wenn Sie zu diesem Zeitpunkt die d3-Projektion verwenden, können Sie Längen- und Breitengrade problemlos konvertieren.

Mit diesen können Sie die Eisenbahnlinie in 3D ausdrücken. ~~ Aber die U-Bahn und die Shinkansen können dieses Programm nicht verarbeiten, es ist nicht gut, es kann nicht benutzt werden! ~~

Recommended Posts

Versuchen Sie, die Eisenbahndaten der nationalen Landnummern in 3D anzuzeigen
Versuchen Sie, in die Datenbank zu importieren, indem Sie ShapeFile mit numerischen Informationen zum nationalen Land mit Python bearbeiten
Versuchen Sie, die Fibonacci-Sequenz im Namen der Algorithmuspraxis in verschiedenen Sprachen anzuzeigen
Anzeige von Positionsinformationsdaten in Python - Versuchen Sie, mit der Kartenanzeigebibliothek (Folium) zu zeichnen -
Versuchen Sie, die in Firefox gespeicherten Anmeldedaten zu entschlüsseln
Versuchen Sie, Merkmale von Sensordaten mit CNN zu extrahieren
Versuchen Sie, Daten in MongoDB abzulegen
Probieren Sie Cython in kürzester Zeit aus
Versuchen Sie, die kumulierte Rendite des Rollovers im Futures-Handel zu modellieren
Versuchen Sie, die Höhendaten des National Land Research Institute mit Python abzubilden
Versuchen Sie, den Zustand der Straßenoberfläche mithilfe von Big Data des Straßenoberflächenmanagements zu ermitteln
Ich habe versucht, den Höhenwert von DTM in einem Diagramm anzuzeigen
Stellen Sie eine Verbindung zur Raspberry PI-Konsole her und zeigen Sie lokale IP- und SD-Informationen an
Die Geschichte des Lesens von HSPICE-Daten in Python
Versuchen Sie, die Bewegung des Sonnensystems zu simulieren
Ich möchte den Fortschritt in Python anzeigen!
So zeigen Sie das Änderungsdatum einer Datei in C-Sprache bis zu Nanosekunden an
Versuchen Sie, mit matplotlib aus den Daten von "Schedule-kun" eine Kampfaufzeichnungstabelle zu erstellen.
[Django] Lassen Sie uns versuchen, den Teil von Django zu klären, der im Test irgendwie durch war
[Erste Datenwissenschaft ⑥] Ich habe versucht, den Marktpreis von Restaurants in Tokio zu visualisieren
Zusammenfassung der Tools, die zum Analysieren von Daten in Python benötigt werden
So ermitteln Sie die Anzahl der Stellen in Python
Versuchen Sie, die Probleme des "Matrix-Programmierers" zu lösen (Kapitel 1).
Versuchen Sie, die Anzahl der Likes auf Twitter zu schätzen
Über die Ineffizienz der Datenübertragung im luigi on-memory
Den Inhalt der Daten in Python nicht kennen
Versuchen Sie, den Inhalt von Word mit Golang zu erhalten
Ich habe versucht, die Spacha-Informationen von VTuber zu visualisieren
Verwenden wir die offenen Daten von "Mamebus" in Python
Um das Äquivalent von Rubys ObjectSpace._id2ref in Python zu tun
Python Open CV hat versucht, das Bild im Text anzuzeigen.
Ich habe versucht, die Punktgruppendaten-DB der Präfektur Shizuoka mit Vue + Leaflet anzuzeigen
Der Standardstil (CSS) von Pandas-Datenrahmen, die von der Anzeige in Google Colab ausgegeben werden, wurde geändert
Anzeigen des regionalen Netzes des Government Statistics Office (eStat) in einem Webbrowser
[Super einfach! ] So zeigen Sie den Inhalt von Wörterbüchern und Listen einschließlich Japanisch in Python an
So berechnen Sie die Summe oder den Durchschnitt von Zeitreihen-CSV-Daten in einem Augenblick
Darstellung der Verteilung der Bakterienzusammensetzung aus Qiime2-Analysedaten in einem Box-Whisker-Diagramm
Versuchen Sie, die Funktionsliste des Python> os-Pakets abzurufen
Ich habe versucht, die Standortinformationen des Odakyu-Busses zu erhalten
Versuchen Sie, die Leistung des Modells für maschinelles Lernen / Regression zu bewerten
Versuchen Sie, verschiedene Informationen anzuzeigen, die für das Debuggen mit Python nützlich sind
Erleichtern Sie die Anzeige von Python-Modulausnahmen
Verschiedene Methoden zur Berechnung der Ähnlichkeit zwischen Daten mit Python
Ich möchte Betriebsinformationen über die Yahoo-Route erhalten
Versuchen Sie, die Genauigkeit der Twitter-ähnlichen Zahlenschätzung zu verbessern
Versuchen Sie, die Probleme / Probleme des "Matrix-Programmierers" zu lösen (Kapitel 0-Funktion)
[Homologie] Zählen Sie mit Python die Anzahl der Löcher in den Daten
Versuchen Sie, den Betrieb von Netzwerkgeräten mit Python zu automatisieren
Zeigen Sie den Fahrplan des Morioka-Busortungssystems in Pythonista an
Die Geschichte des Kopierens von Daten von S3 auf Googles TeamDrive
So erhalten Sie einen Überblick über Ihre Daten in Pandas
Django Geändert, um viele Daten gleichzeitig zu speichern
Die minimale Methode, die beim Aggregieren von Daten mit Pandas zu beachten ist
Ich habe die Daten von Raspberry Pi an GCP gesendet (kostenlos)