All:
I have been investigating integrating a geojson tile service to add streaming 3d buildings from OSM or other sources. Some precedents are below:
https://mapzen.com/tangram
http://vizicities.apps.rawk.es/demo.html#51.503580000000014,-0.01924
http://osmbuildings.org/?lat=52.52111&lon=13.40988&zoom=16
So far, I have developed a script to accept load tiles within a bounding box, or load json tiles dynamically (but not yet unloading) when map zoom level is 16. Both approaches use either Mapzen and/or OSM Buildings API.
Is there any recommendations on the best way to accomplish a streaming 3d geojson tiling service? Has something like this been accomplished with Cesium?
Any feedback is greatly appreciated.
Thanks
Current approach example are outlined below:
//--- helper functions to get tiles numbers with lat/lon
function lon2tilex(lon, zoom) {return Math.round((lon + 180) / 360 * Math.pow(2, zoom));}
function lat2tiley(lat, zoom) {var lata = lat * Math.PI / 180;return Math.round((1 - Math.log(Math.tan(lata) + (1 / Math.cos(lata))) / Math.PI) / 2 * Math.pow(2, zoom));}
//--- get tiles within a bounding box
function returnTiles(min_lon, min_lat, max_lon, max_lat) {
var zoom = 16; // required for building API sources
var tiles = ;
var txmin = lon2tilex(min_lon, zoom);
var txmax = lon2tilex(max_lon, zoom);
var tymin = lat2tiley(max_lat, zoom);
var tymax = lat2tiley(min_lat, zoom);
for (var tx = txmin; tx <= txmax; tx++) {
for (var ty = tymin; ty <= tymax; ty++) {
tiles.push([tx, ty, zoom]);
}
}
return tiles;
}
//--- recursive function to load from a list of tiles (eg. generated by a bounding box formulation)
var tilesLoaded = {}
var tileCount = 0;
function loadTileData(k) {
var data = “dataSource” + String(k);
tilesLoaded[data] = new Cesium.GeoJsonDataSource();
cesiumWidget.dataSources.add(tilesLoaded[data]);
// 3D building APIs
// http://data.osmbuildings.org/0.2/rkc8ywdl/tile/
// http://vector.mapzen.com/osm/buildings/
tilesLoaded[data].loadUrl(‘http://vector.mapzen.com/osm/buildings/’ + tilesLoad[k][2] + ‘/’ + tilesLoad[k][0] + ‘/’ + tilesLoad[k][1] + ‘.json’).then(function() {
var entities = tilesLoaded[data].entities.entities;
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
var name = entity.name;
entity.polygon.material = Cesium.ColorMaterialProperty.fromColor(new Cesium.Color(1.0, 1.0, 1.0, 0));
entity.polygon.outlineColor = new Cesium.ConstantProperty(new Cesium.Color(1, 1, 1, 0.48));
entity.polygon.outlineWidth = new Cesium.ConstantProperty(0.5);
if (entity.properties.height != undefined) {
entity.polygon.extrudedHeight = new Cesium.ConstantProperty(entity.properties.height);
}
else if (entity.properties.levels != undefined) {
entity.polygon.extrudedHeight = new Cesium.ConstantProperty(entity.properties.levels * 5);
}
else {
// randomly extrude if height=0
var max = 3 * 5
var min = 1 * 5;
entity.polygon.extrudedHeight = new Cesium.ConstantProperty(Math.random() * (max - min) + min);
}
entity.building = true;
}
if (k < tilesLoad.length) {
loadTileData(k + 1);
}
else {
console.log(‘all done loading’);
}
});
}
loadTileData(0);
//--- or function to load tiles directly from x, y and zoom
function loadTile(x, y, z) {
var data = “dataSource” + String(tileCount);
tileCount = tileCount + 1;
tilesLoaded[data] = new Cesium.GeoJsonDataSource();
cesiumWidget.dataSources.add(tilesLoaded[data]);
tilesLoaded[data].loadUrl(‘http://data.osmbuildings.org/0.2/rkc8ywdl/tile/’ + z + ‘/’ + x + ‘/’ + y + ‘.json’).then(function() {
// 3D building APIs
// http://data.osmbuildings.org/0.2/rkc8ywdl/tile/
// http://vector.mapzen.com/osm/buildings/
var entities = tilesLoaded[data].entities.entities;
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
var name = entity.name;
entity.polygon.material = Cesium.ColorMaterialProperty.fromColor(new Cesium.Color(1.0, 1.0, 1.0, 0));
entity.polygon.outlineColor = new Cesium.ConstantProperty(new Cesium.Color(1, 1, 1, 0.48));
entity.polygon.outlineWidth = new Cesium.ConstantProperty(0.5);
if (entity.properties.height != undefined) {
entity.polygon.extrudedHeight = new Cesium.ConstantProperty(entity.properties.height);
}
else if (entity.properties.levels != undefined) {
entity.polygon.extrudedHeight = new Cesium.ConstantProperty(entity.properties.levels * 5);
}
else {
// randomly extrude if height=0
var max = 5 * 5
var min = 1 * 5;
entity.polygon.extrudedHeight = new Cesium.ConstantProperty(Math.random() * (max - min) + min);
}
entity.building = true;
}
});
}
//--- example imagery provider calling loadTiles when zoom=16
Cesium.<XYZ>ImageryProvider.prototype.requestImage = function (x, y, level) {
var url = this._url.replace('{s}', this.getCDNSubdomain(x, y)).replace('{z}', level).replace('{x}', x).replace('{y}', y);
if (level==16){
loadTile(x,y,level);
// need to dynamically unload the feature tiles?
}
return Cesium.ImageryProvider.loadImage(this, url);
};