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
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 [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
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.
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.
** 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
]
}
Le traitement côté client est le suivant.
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;
}
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);
}
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);
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é! ~~