[PYTHON] Essayez d'afficher les données ferroviaires des informations numériques des terres nationales en 3D

Présentons les itinéraires ferroviaires qui peuvent être obtenus à partir des données ferroviaires des informations numériques des terres nationales en 3D.

** démo ** http://needtec.sakura.ne.jp/threemap/railroad3d_example.html

** Source côté client ** https://github.com/mima3/threemap

** Source côté serveur ** https://github.com/mima3/kokudo

路線2.png

Traitement côté serveur

Le traitement côté serveur renvoie les données ferroviaires nationales d'informations numériques terrestres stockées dans les conditions requises. À ce moment, les données d'altitude sont ajoutées.

Importez des données ferroviaires dans Spatialite à partir d'informations numériques sur les terres nationales

Importez [Informations ferroviaires](http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N02-v2_2.html «Informations ferroviaires») des informations numériques foncières nationales dans Spatialite.

Le fonctionnement de spatialite est le suivant. https://github.com/mima3/kokudo/blob/master/kokudo_db.py

Pour importer le fichier de forme des données ferroviaires des informations numériques des terres nationales dans la base de données, exécutez la commande suivante.

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

Autorisez GeoJson à être récupéré via HTTP.

Vous permet d'obtenir Geojson pour une route spécifiée à partir d'une base de données créée via HTTP à l'aide de Bottle.

** Exemple d'appel ** 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

Dans cet exemple, toutes les routes du Tokyo Express Railway sont acquises.

Trouvez l'élévation à l'aide de l'API d'élévation de la carte du Geographical Institute

Les données ferroviaires des informations numériques terrestres nationales ont la longitude et la latitude, mais pas l'altitude. Il ne sert à rien de l'afficher en 3D.

Par conséquent, nous allons permettre d'obtenir l'altitude à partir de la longitude et de la latitude. Pour ce faire, utilisez l'API d'élévation Geographical Survey Map.

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

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

résultat

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

Cependant, il est inutile d'exécuter cette API à chaque fois, alors assurez-vous de mettre en cache le contenu une fois lu dans la base de données.

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):
    """
Acquisition de la valeur d'altitude
    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):
    """
Table de cache d'altitude
    """
    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))

La fonction get_elevation trouve l'altitude à partir de la longitude et de la latitude. À ce stade, si la valeur est déjà stockée dans la base de données, elle est renvoyée, si elle n'est pas stockée, l'API d'élévation est exécutée et le résultat est stocké dans la base de données et renvoyé.

La fonction convert_geojson donne au GeoJson de LineString une élévation. Obtient l'élévation des points de début et de fin de la ligne et stocke les résultats dans les propriétés sous la forme start_elevation, end_elevation.

Obtenez GeoJSON des données ferroviaires avec des données d'altitude.

** Exemple d'utilisation ** 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

L'altitude peut être obtenue en ajoutant embed_elevation.

** Résultat d'acquisition **

{
  "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
      }
    },//Abréviation
  ]
} 

Traitement côté client

Le traitement côté client est le suivant.

    1. Ajoutez l'axe z du GeoJSON acquis. À ce stade, le point de départ et le point d'arrivée sont l'altitude spécifiée dans les propriétés, et les autres points sont le rapport en tenant compte du point de départ et du point final.
  1. Les lignes qui peuvent être combinées sont combinées
    1. Dessinez des itinéraires à l'aide de TubeGeometry dans three.js

Ajouter l'axe z du GeoJSON acquis

Ajoutez l'élévation sur l'axe z pour toutes les coordonnées à l'aide de start_elevation et end_elevation dans les propriétés comme indiqué ci-dessous.

    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;
    }

Les lignes qui peuvent être combinées sont combinées

Par exemple, si le point de départ d'une entité et le point final d'une autre entité sont égaux, ils sont combinés et considérés comme une seule ligne.

    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];

          //Si le point de départ de f1 coïncide avec le point final de f2, alors f2 précède 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;
          }
          //Si le point final de f1 coïncide avec le point de départ de f2, il y a f2 après 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);
    }

Dessin d'un routage à l'aide de la géométrie du tube

Dessinez un itinéraire à l'aide de TubeGeometry. Déterminez la position de mesh.position avec les coordonnées du point de départ comme décalage. Pour les autres points, lorsque vous les ajoutez en tant que chemin TubeGeometry, donnez-leur des coordonnées relatives au point de départ.

    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);
      }
    }

À ce stade, reverseProjection utilisée pour obtenir les coordonnées à partir de la longitude et de la latitude utilise la projection de d3.geo.path () comme suit.

Contenu de la projection inverse


    //Puisqu'il est à l'envers, c'est étouffant
    var reverseProjection = function(x, y) {
      pt = projection(x, y);
      pt[1] *= -1;
      return pt;
    };

    //Créer une fonction pour convertir les données geoJSON en chemin
    var path = d3.geo.path().projection(reverseProjection);

Résumé

Geojson peut être créé dynamiquement en stockant les données ferroviaires des informations numériques sur les terres nationales dans spatialite.

Si vous utilisez l'API d'élévation de l'Institut géographique, vous pouvez obtenir l'élévation à partir de la latitude et de la longitude. À ce stade, il est préférable de mettre en cache le résultat.

Si vous utilisez three.js, vous pouvez facilement effectuer une expression 3D et, à ce stade, si vous utilisez la projection d3, vous pouvez facilement convertir la longitude et la latitude.

En les utilisant, vous pouvez exprimer la voie ferrée en 3D. ~~ Mais le métro et Shinkansen ne peuvent pas gérer ce programme, ce n'est pas bon, il ne peut pas être utilisé! ~~

Recommended Posts

Essayez d'afficher les données ferroviaires des informations numériques des terres nationales en 3D
Essayez d'importer dans la base de données en manipulant ShapeFile d'informations numériques sur les terres nationales avec Python
Essayez d'afficher la séquence de Fibonacci dans différentes langues comme pratique d'algorithme
Affichage des données d'informations de position en Python --Essayez de tracer avec la bibliothèque d'affichage de carte (folium) -
Essayez de déchiffrer les données de connexion stockées dans Firefox
Essayez d'extraire les caractéristiques des données de capteur avec CNN
Essayez de mettre des données dans MongoDB
Essayez Cython dans les plus brefs délais
Essayez de modéliser le rendement cumulatif du roulement dans le trading à terme
Essayez d'imaginer les données d'élévation du National Land Research Institute avec Python
Essayez d'obtenir l'état de la surface de la route en utilisant de grandes données de gestion de la surface de la route
J'ai essayé d'afficher la valeur d'altitude du DTM dans un graphique
Connectez-vous à la console Raspberry PI et affichez les informations IP et SD locales
L'histoire de la lecture des données HSPICE en Python
Essayez de simuler le mouvement du système solaire
Je veux afficher la progression en Python!
Comment afficher la date de modification d'un fichier en langage C jusqu'à nanosecondes
Essayez de créer une table d'enregistrement de bataille avec matplotlib à partir des données de "Schedule-kun"
[Django] Essayons de clarifier la partie de Django qui était en quelque sorte à travers le test
[First data science ⑥] J'ai essayé de visualiser le prix du marché des restaurants à Tokyo
Résumé des outils nécessaires pour analyser les données en Python
Comment obtenir le nombre de chiffres en Python
Essayez de résoudre les problèmes / problèmes du "programmeur matriciel" (Chapitre 1)
Essayez d'estimer le nombre de likes sur Twitter
À propos de l'inefficacité du transfert de données dans luigi on-memory
Ne pas être conscient du contenu des données en python
Essayez d'obtenir le contenu de Word avec Golang
J'ai essayé de visualiser les informations spacha de VTuber
Utilisons les données ouvertes de "Mamebus" en Python
Pour faire l'équivalent de Ruby ObjectSpace._id2ref en Python
Python Open CV a essayé d'afficher l'image sous forme de texte.
J'ai essayé d'afficher les données du groupe de points DB de la préfecture de Shizuoka avec Vue + Leaflet
Modification du style par défaut (CSS) des cadres de données pandas générés par affichage dans Google Colab
Comment afficher le maillage régional du Government Statistics Office (eStat) dans un navigateur Web
[Super facile! ] Comment afficher le contenu des dictionnaires et des listes incluant le japonais en Python
Comment calculer la somme ou la moyenne des données csv de séries chronologiques en un instant
Comment représenter la distribution de la composition bactérienne à partir des données d'analyse Qiime2 dans un diagramme de moustaches
Essayez d'obtenir la liste des fonctions du paquet Python> os
J'ai essayé d'obtenir les informations de localisation du bus Odakyu
Essayez d'évaluer les performances du modèle d'apprentissage automatique / de régression
Essayez d'afficher diverses informations utiles pour le débogage avec python
Facilitez la compréhension de l'affichage des exceptions du module Python
Différentes façons de calculer la similitude entre les données avec python
Je veux obtenir des informations sur le fonctionnement de Yahoo Route
Essayez d'améliorer la précision de l'estimation du nombre de Twitter
Essayez de résoudre les problèmes / problèmes du "programmeur matriciel" (fonction du chapitre 0)
[Homologie] Comptez le nombre de trous dans les données avec Python
Essayez d'automatiser le fonctionnement des périphériques réseau avec Python
Afficher les horaires du système de localisation des bus Morioka dans Pythonista
L'histoire de la copie de données de S3 vers TeamDrive de Google
Comment obtenir un aperçu de vos données dans Pandas
Django a changé pour enregistrer beaucoup de données à la fois
La méthode minimale à retenir lors de l'agrégation de données avec Pandas
J'ai envoyé les données de Raspberry Pi à GCP (gratuit)