WebWorldWind/apps/NaturalLanguageForm/js/BuildingPolygonHandler.js
2015-08-28 17:13:35 -07:00

215 lines
8.7 KiB
JavaScript

/**
* Created by Matthew on 8/13/2015.
*/
/*
* This modules calls the polygon api, calls the building info api.
*
*
*/
define(['OSMBuildingDataRetriever',
'BuildingFactory',
'lodash',
'OpenStreetMapConfig'],
function (OSMBuildingDataRetriever,
BuildingFactory,
_,
OpenStreetMapConfig) {
/*
Given a WorldWind Location or WorldWind Position, uses the maximum bounding
box distances from the config object to define a bounding box for usage in
the OpenStreetMap API and the RTree.
@param center : the object containing the longitude and latitude points of the bounding rect's
center point
@return : returns an array, [top, left, bottom, right], that represents the bounding rectangle
*/
function getBoundingRectLocs (center, grid) {
var jQueryDoc = $(window.document),
jQH = jQueryDoc.height(),
jQW = jQueryDoc.width(),
R = jQH/jQW,
size = (grid ||.002);
center.latitude = Math.round(center.latitude/(2*size))*(2*size);
center.longitude = Math.round(center.longitude/(2*size/R))*(2*size/R);
return [
center.latitude + size,
center.longitude - size/R,
center.latitude - size,
center.longitude + size/R
];
}
/*
* Arranges the ordering of a bounding box array in an appropriate manner to be used with rbush
*
* @param bbox: any bounding box array
*
* @return: Returns bounding box in the form [minlat, minlong, maxlat, maxlon]
*/
function bboxToNode (bbox) {
return [
Math.min(bbox[0],bbox[2]),
Math.min(bbox[1],bbox[3]),
Math.max(bbox[0],bbox[2]),
Math.max(bbox[1],bbox[3])
]
}
var BuildingPolygonHandler = function ( layer ) {
var self = this;
self._OSMBuildingData = new OSMBuildingDataRetriever();
self._buildingFactory = new BuildingFactory();
self._config = new OpenStreetMapConfig();
self._tempBuildingIDTracker = [];
self._layer = layer;
self._boxesOwned = {};
/*
* Manages building and bounding box calls. Acts as an access point by the layer. The layer calls this
* function with draw context as an arg.
*
* @param drawContext: Drawcontext of layer
*/
self.buildingHandler = function (drawContext) {
//console.log(drawContext)
var callCompleteCallback = function () {self.isInCall = false;};
var eyeAltitude = drawContext.eyePosition.altitude;
var box = getBoundingRectLocs(
{
latitude: drawContext.eyePosition.latitude,
longitude: drawContext.eyePosition.longitude
}
);
if (!self.isInCall && eyeAltitude <= self._config._maxBuildingDrawHeight) {
self.isInCall = true;
self.getBuildingArrayAndType(
box,
self.buildingRenderableHandler,
callCompleteCallback
);
}
};
/*
* Behaves as callback function for the api caller to add renderables to the layer.
*
* @param building: a renderable building abstraction from the building module.
*/
self.buildingRenderableHandler = function (building) {
if (building) {
self._layer.addRenderable(building, function(renderable){return renderable.bbox})
}
};
};
/*
* If a bounding box has not been called for yet, it calls the api with that bounding box then calls the second
* api for the building details. Bounding boxes are stored in a key object for checking if a box has been
* called for already. Upon return from the last of the buildings, the call is opened up again for another
* call.
*
* @param box: bounding box in the form given by the getboudingrecslocs function.
* @param buildingRetreivedCallback: Function to call when a single building date has been returned. This is
* called with the building as an argument.
* @param CompletionCallback: Callback function to call when the last few of the buildings are retrieved or if
* the call has already been made.
*/
BuildingPolygonHandler.prototype.getBuildingArrayAndType = function (
box,
buildingRetreivedCallback,
CompletionCallback) {
var self = this;
//console.log('called')
var box = [box[0], box[3], box[2], box[1]];
//console.log(box)
var boxKey = (box.map(function(entry){return entry.toFixed(5)})).join(',');
//console.log(boxKey)
if (!self._boxesOwned[boxKey]) {
self._boxesOwned[boxKey] = true;
self._OSMBuildingData.requestOSMBuildingData(box, function (buildingIdArray) {
var numberOfBuildingsFullyRetreived = 0;
buildingIdArray.forEach(function (buildingData) {
var building = self.buildingFromDatum(buildingData);
if (self._tempBuildingIDTracker.indexOf(building.id) === -1) {
self._tempBuildingIDTracker.push(building.id);
self._OSMBuildingData.requestBuildingInfoById(building.id, function (data) {
var features = data['features'];
if (features) {
var first = features[0];
}
if (first) {
var properties = first['properties'];
}
if (properties) {
var tags = properties['tags'];
}
if (tags) {
var buildingType = tags['building'];
}
if (buildingType) {
building.buildingType = buildingType;
}
if (building.buildingType) {
building.bbox = bboxToNode(box);
buildingRetreivedCallback(building)
}
numberOfBuildingsFullyRetreived++;
//console.log(numberOfBuildingsFullyRetreived, 'of', buildingIdArray.length)
if (numberOfBuildingsFullyRetreived >= buildingIdArray.length - 5) {
CompletionCallback()
}
});
} else {
numberOfBuildingsFullyRetreived++;
//console.log(numberOfBuildingsFullyRetreived, 'of', buildingIdArray.length)
if (numberOfBuildingsFullyRetreived >= buildingIdArray.length - 5) {
CompletionCallback()
}
}
});
})
} else {
//console.log('This is an old box');
CompletionCallback()
}
};
/*
* Puts building data from the api into a form that we can work with.
*
* @param buildingData: Building data as returned by the api
*
* @return: building renderable abstraction as given by the building module.
*/
BuildingPolygonHandler.prototype.buildingFromDatum = function(buildingData) {
var self = this;
var id = buildingData['id'];
var geometry = buildingData['geometry'];
var coordinates = geometry['coordinates'];
var points = coordinates[0];
var polygon = _.map(points, function(point) {
return new WorldWind.Position(point[1], point[0], 100);
});
return self._buildingFactory.createBuilding(id, polygon, undefined);
};
return BuildingPolygonHandler
}
);