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
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 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ö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.
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.
** 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
]
}
Die Verarbeitung auf der Client-Seite ist wie folgt.
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;
}
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 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);
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