Skip to content
Permalink
Browse files

improved the way GeoJSON file is used, added some code for sectorizing

  • Loading branch information...
kilsedar
kilsedar committed Jul 21, 2017
1 parent 18047e1 commit 9b5dcc9a58b4b810171eca4134b4d2480ed3d1dc
Showing with 137 additions and 31 deletions.
  1. +2 −0 .gitignore
  2. +10 −5 example/index.js
  3. +94 −18 src/OSMBuildingLayer.js
  4. +13 −2 src/OSMLayer.js
  5. +18 −6 src/shapes/BuildingShape.js
@@ -3,6 +3,8 @@ node_modules
.idea
src/OSMLayer_0.js
src/OSMBuildingLayer_0.js
src/OSMBuildingLayer_1.js
src/GeoJSONParserTriangulation_0.js
src/GeoJSONParserTriangulation_1.js
out
example/data/*
@@ -18,32 +18,37 @@ define(['libraries/WebWorldWind/src/WorldWind', 'src/OSMBuildingLayer'],
{layer: new WorldWind.ViewControlsLayer(worldWindow), enabled: true},
{layer: new WorldWind.AtmosphereLayer(), enabled: true}
];
// layers[1].layer.detailControl = 1;
layers[1].layer.detailControl = 1;
for (var l = 0; l < layers.length; l++) {
layers[l].layer.enabled = layers[l].enabled;
worldWindow.addLayer(layers[l].layer);
}

// var source = {type: "boundingBox", coordinates: [-74.0232, 40.6998, -73.97, 40.74]}; // New York (big)
var source = {type: "boundingBox", coordinates: [-74.03, 40.70, -74.0, 40.72]}; // New York (small)
// var source = {type: "boundingBox", coordinates: [-74.03, 40.70, -74.0, 40.72]}; // New York (small)
// var source = {type: "boundingBox", coordinates: [9.04284, 45.3871, 9.27791, 45.536]}; // Milan (PRIN & big)
// var source = {type: "boundingBox", coordinates: [9.05, 45.45, 9.10, 45.50]}; // Milan (medium)
// var source = {type: "boundingBox", coordinates: [9.45, 45.48, 9.50, 45.50]}; // Milan (small)
// var source = {type: "boundingBox", coordinates: [9.1705, 45.4557, 9.2021, 45.4735]}; // Milan (center)
// var source = {type: "boundingBox", coordinates: [9.2, 45.48, 9.21, 45.49]}; // Milan (buggy region - nodes)
// var source = {type: "boundingBox", coordinates: [9.48, 45.18, 9.53, 45.19]}; // region tested in GRASS
// var source = {type: "GeoJSONFile", path: "data/test.geojson"};
var source = {type: "GeoJSONFile", path: "data/prin_small_med.geojson"};

var configuration = {
// interiorColor: new WorldWind.Color(0.67, 0.25, 0.020, 1.0),
interiorColor: new WorldWind.Color(0.02, 0.2, 0.7, 1.0),
applyLighting: true,
extrude: true,
heatmap: {enabled: true, thresholds: [0, 30, 50, 100, 900]},
altitude: "osm",
heatmap: {enabled: true, thresholds: [0, 5, 10, 20, 40, 900]},
// altitude: {type: "number", value: 100},
// altitude: {type: "osm"},
altitude: {type: "property", value: "height_median"},
altitudeMode: WorldWind.RELATIVE_TO_GROUND
};

var test = new OSMBuildingLayer(worldWindow, configuration, source);
test.add();
// test.boundingBox = [9.15651, 45.44919, 9.20246, 45.48449]; // prin_small_med.geojson
test.boundingBox = [9.18307, 45.46073, 9.20421, 45.46957]; // prin_smaller_med.geojson
test.zoom();
});
@@ -6,11 +6,13 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
'libraries/WebWorldWind/src/util/Logger',
'libraries/WebWorldWind/src/geom/BoundingBox',
'libraries/WebWorldWind/src/geom/Sector',
'libraries/WebWorldWind/src/gesture/DragRecognizer',
'libraries/WebWorldWind/src/gesture/PanRecognizer',
'src/OSMLayer',
'src/GeoJSONParserTriangulationOSM',
'jquery',
'osmtogeojson'],
function (MemoryCache, ArgumentError, Logger, BoundingBox, Sector, OSMLayer, GeoJSONParserTriangulationOSM, $, osmtogeojson) {
function (MemoryCache, ArgumentError, Logger, BoundingBox, Sector, DragRecognizer, PanRecognizer, OSMLayer, GeoJSONParserTriangulationOSM, $, osmtogeojson) {
"use strict";

/**
@@ -49,13 +51,23 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
* @type {MemoryCache}
*/
this._propertiesCache = new MemoryCache(50000, 40000);

this._cache = new MemoryCache(100000, 80000);
};

OSMBuildingLayer.prototype = Object.create(OSMLayer.prototype);

/**
*
*/
OSMBuildingLayer.prototype.detectVisibilityChange = function () {

}

/**
* Sectorizes a bounding box. Each sector initially will be 0.01 to 0.01 degrees for all the zoom levels.
* @param {Float[]} boundingBox The bounding box to be sectorized. Intended to be the bounding box of the whole layer.
* @returns {Sector[]} An array of [sectors]{@link Sector} making up the given bounding box.
*/
OSMBuildingLayer.prototype.createSectors = function(boundingBox) {
var sectorSize = 0.01;
@@ -83,16 +95,18 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
sectors.push(new Sector(y1, y2, x1, x2));
}
}

return sectors;
};

/**
* Checks if a given bounding box is visible.
* @param {Float[]} boundingBox Intended to be a bounding box for a {@link Sector} of the OSMBuildingLayer.
* @returns {boolean} True if the bounding box intersects the frustum, otherwise false.
* @param {Sector} sector A {@link Sector} of the OSMBuildingLayer.
* @returns {boolean} True if the sector intersects the frustum, otherwise false.
*/
OSMBuildingLayer.prototype.intersectsVisible = function(boundingBox) {
OSMBuildingLayer.prototype.intersectsVisible = function(sector) {
var boundingBox = new BoundingBox();
boundingBox.setToSector(new Sector(boundingBox[1], boundingBox[3], boundingBox[0], boundingBox[2]), this._worldWindow.drawContext.globe, 0, 15); // Maximum elevation 15 should be changed.
boundingBox.setToSector(sector, this._worldWindow.drawContext.globe, 0, 15); // Maximum elevation 15 should be changed.

return boundingBox.intersectsFrustum(this._worldWindow.drawContext.navigatorState.frustumInModelCoordinates);
};
@@ -108,6 +122,18 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
}
};

/**
*
* @param
* @param
*/
/* OSMBuildingLayer.prototype.cache = function(id, dataOverpassGeoJSON) {
// console.log(id + ", " + dataOverpassGeoJSON);
if(dataOverpassGeoJSON.features.length > 0)
this._cache.putEntry(id, dataOverpassGeoJSON, dataOverpassGeoJSON.features.length);
// console.log(this._cache);
}; */

/**
* Sets the attributes of {@link ShapeAttributes} and four more attributes defined specifically for OSMBuildingLayer, which are "extrude", "heatmap", "altitude" and "altitudeMode".
* @param {GeoJSONGeometry} geometry An object containing the geometry of the OSM data in GeoJSON format for the OSMBuildingLayer.
@@ -122,7 +148,11 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
configuration.heatmap.enabled = this._configuration.heatmap.enabled ? this._configuration.heatmap.enabled : false;
configuration.heatmap.thresholds = this._configuration.heatmap.thresholds ? this._configuration.heatmap.thresholds : [0, 15, 900];
}
configuration.altitude = this._configuration.altitude ? this._configuration.altitude : 15;
configuration.altitude = this._configuration.altitude ? this._configuration.altitude : null;
if (configuration.altitude) {
configuration.altitude.type = this._configuration.altitude.type ? this._configuration.altitude.type : "number";
configuration.altitude.value = this._configuration.altitude.value ? this._configuration.altitude.value : 15;
}
configuration.altitudeMode = this._configuration.altitudeMode ? this._configuration.altitudeMode : WorldWind.RELATIVE_TO_GROUND;

return configuration;
@@ -136,6 +166,15 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
OSMBuildingLayer.prototype.add = function () {
if (this._source.type == "boundingBox" && this._source.coordinates)
this.addByBoundingBox();
/* if (this._source.type == "boundingBox" && this._source.coordinates) {
this.boundingBox = this._source.coordinates;
this.zoom(); // temporary
var sectors = this.createSectors(this.boundingBox);
for (var sectorIndex = 0; sectorIndex < sectors.length; sectorIndex++){
if (this.intersectsVisible(sectors[sectorIndex]))
this.addBySector(sectors[sectorIndex]);
}
} */
else if (this._source.type == "GeoJSONFile" && this._source.path)
this.addByGeoJSONFile();
else {
@@ -145,10 +184,43 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
}
};

/**
*
*/
OSMBuildingLayer.prototype.addBySector = function (sector) {

var worldWindow = this._worldWindow;
var _self = this;

var data = '[out:json][timeout:25];';
data += '(' + this._type + '[' + this._tag + '](' + sector.minLatitude + ',' + sector.minLongitude + ',' + sector.maxLatitude + ',' + sector.maxLongitude + '); ';
data += 'relation[' + this._tag + '](' + sector.minLatitude + ',' + sector.minLongitude + ',' + sector.maxLatitude + ',' + sector.maxLongitude + ');); out body; >; out skel qt;';

$.ajax({
url: 'http://overpass-api.de/api/interpreter',
data: data,
type: 'POST',
success: function(dataOverpass) {
var dataOverpassGeoJSON = osmtogeojson(dataOverpass);
_self.cache(sector.minLatitude + ',' + sector.minLongitude + ',' + sector.maxLatitude + ',' + sector.maxLongitude, dataOverpassGeoJSON);
var dataOverpassGeoJSONString = JSON.stringify(dataOverpassGeoJSON);
var OSMBuildingLayer = new WorldWind.RenderableLayer("OSMBuildingLayer");
var OSMBuildingLayerGeoJSON = new GeoJSONParserTriangulationOSM(dataOverpassGeoJSONString);
OSMBuildingLayerGeoJSON.load(null, _self.shapeConfigurationCallback.bind(_self), OSMBuildingLayer);
worldWindow.addLayer(OSMBuildingLayer);
},
error: function(e) {
throw new ArgumentError(
Logger.logMessage(Logger.LEVEL_SEVERE, "OSMBuildingLayer", "addBySector", "Request failed. Error: " + JSON.stringify(e))
);
}
});
};

/**
* Makes an AJAX request to fetch the OSM building data using the "coordinates" of the layer's "_source" member variable and Overpass API, converts it to GeoJSON using osmtogeojson API,
* adds the GeoJSON to the {@link WorldWindow} using the {@link GeoJSONParserTriangulationOSM}.
* It also sets the "_boundingBox" member variable of the layer.
* It also sets the "boundingBox" member variable of the layer.
* @throws {ArgumentError} If the "coordinates" of the layer's "_source" member variable doesn't have four values.
* @throws {ArgumentError} If the request to OSM fails.
*/
@@ -160,13 +232,13 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
);
}

this._boundingBox = this._source.coordinates;
this.boundingBox = this._source.coordinates;
var worldWindow = this._worldWindow;
var _self = this;

var data = '[out:json][timeout:25];';
data += '(' + this._type + '[' + this._tag + '](' + this._boundingBox[1] + ',' + this._boundingBox[0] + ',' + this._boundingBox[3] + ',' + this._boundingBox[2] + '); ';
data += 'relation[' + this._tag + '](' + this._boundingBox[1] + ',' + this._boundingBox[0] + ',' + this._boundingBox[3] + ',' + this._boundingBox[2] + ');); out body; >; out skel qt;';
data += '(' + this._type + '[' + this._tag + '](' + this.boundingBox[1] + ',' + this.boundingBox[0] + ',' + this.boundingBox[3] + ',' + this.boundingBox[2] + '); ';
data += 'relation[' + this._tag + '](' + this.boundingBox[1] + ',' + this.boundingBox[0] + ',' + this.boundingBox[3] + ',' + this.boundingBox[2] + ');); out body; >; out skel qt;';

$.ajax({
url: 'http://overpass-api.de/api/interpreter',
@@ -180,7 +252,7 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
var OSMBuildingLayerGeoJSON = new GeoJSONParserTriangulationOSM(dataOverpassGeoJSONString);
OSMBuildingLayerGeoJSON.load(null, _self.shapeConfigurationCallback.bind(_self), OSMBuildingLayer);
worldWindow.addLayer(OSMBuildingLayer);
_self.zoom();
_self.zoom(); // temporary
},
error: function(e) {
throw new ArgumentError(
@@ -192,14 +264,14 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',

/**
* Calculates the bounding box of a GeoJSON object, where its features are expected to be of type "Polygon" or "MultiPolygon".
* It also sets the "_boundingBox" member variable of the layer.
* It also sets the "boundingBox" member variable of the layer.
* @param {Object} dataOverpassGeoJSON GeoJSON object of which the bounding box is calculated.
*/
OSMBuildingLayer.prototype.calculateBoundingBox = function (dataGeoJSON) {
var boundingBox = [Infinity, Infinity, -Infinity, -Infinity], polygons, coordinates, latitude, longitude;

for (var featureIndex = 0; featureIndex < GeoJSON.features.length; featureIndex++) {
polygons = GeoJSON.features[featureIndex].geometry.coordinates;
for (var featureIndex = 0; featureIndex < dataGeoJSON.features.length; featureIndex++) {
polygons = dataGeoJSON.features[featureIndex].geometry.coordinates;

for (var polygonsIndex = 0; polygonsIndex < polygons.length; polygonsIndex++) {
for (var coordinatesIndex = 0; coordinatesIndex < polygons[polygonsIndex].length; coordinatesIndex++) {
@@ -212,12 +284,12 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
}
}
}
this._boundingBox = boundingBox;
this.boundingBox = boundingBox;
};

/**
* Makes an AJAX request using the "path" of the layer's "_source" member variable to fetch the GeoJSON file, adds the GeoJSON to the {@link WorldWindow} using the {@link GeoJSONParserTriangulationOSM}.
* It also sets the "_boundingBox" member variable of the layer by calling [calculateBoundingBox]{@link OSMBuildingLayer#calculateBoundingBox}.
* It also sets the "boundingBox" member variable of the layer by calling [calculateBoundingBox]{@link OSMBuildingLayer#calculateBoundingBox}. // Not anymore, because for big files it would take time.
* @throws {ArgumentError} If the data returned from the request is empty.
* @throws {ArgumentError} If the request fails.
*/
@@ -226,6 +298,10 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
var _self = this;

$.ajax({
beforeSend: function(xhr) {
if(xhr.overrideMimeType)
xhr.overrideMimeType("application/json");
},
dataType: "json",
url: this._source.path,
success: function(data) {
@@ -234,13 +310,13 @@ define(['libraries/WebWorldWind/src/cache/MemoryCache',
Logger.logMessage(Logger.LEVEL_SEVERE, "OSMBuildingLayer", "addByGeoJSONFile", "File is empty.")
);
}
_self.calculateBoundingBox(data);
// _self.calculateBoundingBox(data);
var GeoJSONString = JSON.stringify(data);
var OSMBuildingLayer = new WorldWind.RenderableLayer("OSMBuildingLayer");
var OSMBuildingLayerGeoJSON = new GeoJSONParserTriangulationOSM(GeoJSONString);
OSMBuildingLayerGeoJSON.load(null, _self.shapeConfigurationCallback.bind(_self), OSMBuildingLayer);
worldWindow.addLayer(OSMBuildingLayer);
_self.zoom();
// _self.zoom();
},
error: function(e) {
throw new ArgumentError(
@@ -44,13 +44,24 @@ define(['libraries/WebWorldWind/src/error/ArgumentError',
*/
this._tag = null;

this._boundingBox = null;
};

Object.defineProperties (OSMLayer.prototype, {
/**
* It defines the bounding box of the OSM data for the OSMLayer. The order of coordinates of the bounding box is "x1, y1, x2, y2".
* @memberof OSMLayer.prototype
* @type {Float[]}
*/
this._boundingBox = null;
};
boundingBox: {
get: function() {
return this._boundingBox;
},
set: function(boundingBox) {
this._boundingBox = boundingBox;
}
}
});

/**
* Sets the attributes of {@link PlacemarkAttributes} if the geometry is Point or MultiPoint; or of {@link ShapeAttributes} otherwise.
@@ -84,24 +84,36 @@ define([''], function () {

/**
* Sets the altitude of the shape ({@link Polygon} or {@link MultiPolygon}).
* For the {@link OSMBuildingLayer} if extrude is true and altitude is set to "osm", if available the value of OSM "height" tag is used. If the "height" tag is not available an approximate height value is calculated using "building:levels" tag. Every level is considered to be 3 meters. If both are not available, 15 is used by default.
* For the {@link OSMBuildingLayer} if extrude is true and altitude is set to a floating-point number, the set value is used.
* For the {@link OSMBuildingLayer} if extrude is true and altitude is not set, 15 is used by default.
* For the {@link OSMBuildingLayer} if extrude is true, altitude is defined and altitude "type" is set to "number", altitude "value" is used. If altitude "value" is not set, 15 is used.
* For the {@link OSMBuildingLayer} if extrude is true, altitude is defined and altitude "type" is set to "osm", if available the value of OSM "height" tag is used. If the "height" tag is not available an approximate height value is calculated using "building:levels" tag. Every level is considered to be 3 meters. If both are not available, 15 is used by default.
* For the {@link OSMBuildingLayer} if extrude is true, altitude is defined and altitude "type" is set to "property", the value of the property defined in "value" is used. If value of the property is null, 15 is used.
* For the {@link OSMBuildingLayer} if extrude is true and altitude is undefined, 15 is used by default.
* For the {@link OSMBuildingLayer} if extrude is false, 0 is used.
* @param {Object} configuration Configuration is the object returned by [shapeConfigurationCallback]{@link OSMBuildingLayer#shapeConfigurationCallback}.
*/
BuildingShape.prototype.setAltitude = function (configuration) {
var altitude;
if (configuration.extrude && configuration.altitude == "osm") {
if (configuration.extrude && configuration.altitude && configuration.altitude.type == "number") {
if (configuration.altitude.value)
altitude = configuration.altitude.value;
// Not necessary if the BuildingShape is one of OSMBuildingLayer.
else
altitude = 15;
}
else if (configuration.extrude && configuration.altitude && configuration.altitude.type == "osm") {
if (this._properties.tags && this._properties.tags.height)
altitude = this._properties.tags.height;
else if (this._properties.tags && this._properties.tags["building:levels"])
altitude = this._properties.tags["building:levels"]*3;
else
altitude = 15;
}
else if (configuration.extrude && configuration.altitude)
altitude = configuration.altitude;
else if (configuration.extrude && configuration.altitude && configuration.altitude.type == "property") {
if (configuration.altitude.value && this._properties[configuration.altitude.value])
altitude = this._properties[configuration.altitude.value];
else
altitude = 15;
}
else if (configuration.extrude)
altitude = 15;
else

0 comments on commit 9b5dcc9

Please sign in to comment.
You can’t perform that action at this time.