Browse Source

Merge pull request #443 from pelias/expose-bbox

Expose bbox
pull/459/head
Diana Shkolnikov 9 years ago
parent
commit
c463772e31
  1. 49
      helper/geojsonify.js
  2. 38
      middleware/parseBBox.js
  3. 7
      routes/v1.js
  4. 2
      test/unit/fixture/autocomplete_linguistic_with_admin.js
  5. 125
      test/unit/helper/geojsonify.js
  6. 65
      test/unit/middleware/parseBBox.js
  7. 1
      test/unit/run.js

49
helper/geojsonify.js

@ -29,7 +29,8 @@ var DETAILS_PROPS = [
'locality_id',
'locality_a',
'neighbourhood',
'neighbourhood_id'
'neighbourhood_id',
'bounding_box'
];
@ -50,11 +51,16 @@ function geojsonifyPlaces( docs ){
return !!doc;
});
// get all the bounding_box corners as well as single points
// to be used for computing the overall bounding_box for the FeatureCollection
var extentPoints = extractExtentPoints(geodata);
// convert to geojson
var geojson = GeoJSON.parse( geodata, { Point: ['lat', 'lng'] });
var geojsonExtentPoints = GeoJSON.parse( extentPoints, { Point: ['lat', 'lng'] });
// bounding box calculations
computeBBox(geojson);
computeBBox(geojson, geojsonExtentPoints);
return geojson;
}
@ -105,23 +111,56 @@ function addLabel(src, dst) {
dst.label = labelGenerator(dst);
}
/**
* Collect all points from the geodata.
* If an item is a single point, just use that.
* If an item has a bounding box, add two corners of the box as individual points.
*
* @param {Array} geodata
* @returns {Array}
*/
function extractExtentPoints(geodata) {
var extentPoints = [];
geodata.forEach(function (place) {
if (place.bounding_box) {
extentPoints.push({
lng: place.bounding_box.min_lon,
lat: place.bounding_box.min_lat
});
extentPoints.push({
lng: place.bounding_box.max_lon,
lat: place.bounding_box.max_lat
});
}
else {
extentPoints.push({
lng: place.lng,
lat: place.lat
});
}
});
return extentPoints;
}
/**
* Compute bbox that encompasses all features in the result set.
* Set bbox property on the geojson object.
*
* @param {object} geojson
*/
function computeBBox(geojson) {
function computeBBox(geojson, geojsonExtentPoints) {
// @note: extent() sometimes throws Errors for unusual data
// eg: https://github.com/pelias/pelias/issues/84
try {
var bbox = extent( geojson );
var bbox = extent( geojsonExtentPoints );
if( !!bbox ){
geojson.bbox = bbox;
}
} catch( e ){
console.error( 'bbox error', e.message, e.stack );
console.error( 'geojson', JSON.stringify( geojson, null, 2 ) );
console.error( 'geojson', JSON.stringify( geojsonExtentPoints, null, 2 ) );
}
}

38
middleware/parseBBox.js

@ -0,0 +1,38 @@
var logger = require('pelias-logger').get('api');
/**
* Parses the bounding box property in docs, if one is found
*/
function setup() {
return function (req, res, next) {
// do nothing if no result data set
if (!res || !res.data) {
return next();
}
res.data = res.data.map(parseBBox);
next();
};
}
/*
* Parse the bbox property and form an object
*/
function parseBBox(place) {
if (place && place.bounding_box) {
try {
place.bounding_box = JSON.parse(place.bounding_box);
}
catch (err) {
logger.error('Invalid bounding_box json string:', place);
delete place.bounding_box;
}
}
return place;
}
module.exports = setup;

7
routes/v1.js

@ -34,7 +34,8 @@ var postProc = {
localNamingConventions: require('../middleware/localNamingConventions'),
renamePlacenames: require('../middleware/renamePlacenames'),
geocodeJSON: require('../middleware/geocodeJSON'),
sendJSON: require('../middleware/sendJSON')
sendJSON: require('../middleware/sendJSON'),
parseBoundingBox: require('../middleware/parseBBox')
};
/**
@ -65,6 +66,7 @@ function addRoutes(app, peliasConfig) {
postProc.dedupe(),
postProc.localNamingConventions(),
postProc.renamePlacenames(),
postProc.parseBoundingBox(),
postProc.geocodeJSON(peliasConfig, base),
postProc.sendJSON
]),
@ -76,6 +78,7 @@ function addRoutes(app, peliasConfig) {
postProc.dedupe(),
postProc.localNamingConventions(),
postProc.renamePlacenames(),
postProc.parseBoundingBox(),
postProc.geocodeJSON(peliasConfig, base),
postProc.sendJSON
]),
@ -90,6 +93,7 @@ function addRoutes(app, peliasConfig) {
postProc.dedupe(),
postProc.localNamingConventions(),
postProc.renamePlacenames(),
postProc.parseBoundingBox(),
postProc.geocodeJSON(peliasConfig, base),
postProc.sendJSON
]),
@ -98,6 +102,7 @@ function addRoutes(app, peliasConfig) {
controllers.place(),
postProc.localNamingConventions(),
postProc.renamePlacenames(),
postProc.parseBoundingBox(),
postProc.geocodeJSON(peliasConfig, base),
postProc.sendJSON
]),

2
test/unit/fixture/autocomplete_linguistic_with_admin.js

@ -106,7 +106,7 @@ module.exports = {
}
],
'score_mode': 'first',
'boost_mode': 'replace',
'boost_mode': 'replace'
}
},
{

125
test/unit/helper/geojsonify.js

@ -207,6 +207,131 @@ module.exports.tests.search = function(test, common) {
t.deepEqual(json, expected, 'all docs mapped');
t.end();
});
test('filtering out empty items', function (t) {
var input = [
{
'bounding_box': {
'min_lat': 40.6514712164,
'max_lat': 40.6737320588,
'min_lon': -73.8967895508,
'max_lon': -73.8665771484
},
'locality': [
'New York'
],
'source': 'whosonfirst',
'layer': 'neighbourhood',
'population': 173198,
'popularity': 495,
'center_point': {
'lon': -73.881319,
'lat': 40.663303
},
'name': {
'default': 'East New York'
},
'source_id': '85816607',
'category': [],
'_id': '85816607',
'_type': 'neighbourhood',
'_score': 21.434,
'confidence': 0.888,
'country': [
'United States'
],
'country_id': [
'85633793'
],
'country_a': [
'USA'
],
'region': [
'New York'
],
'region_id': [
'85688543'
],
'region_a': [
'NY'
],
'county': [
'Kings County'
],
'county_id': [
'102082361'
],
'county_a': [
null
],
'localadmin': [
'Brooklyn'
],
'localadmin_id': [
'404521211'
],
'localadmin_a': [
null
],
'locality_id': [
'85977539'
],
'locality_a': [
null
],
'neighbourhood': [],
'neighbourhood_id': []
}
];
var expected = {
'type': 'FeatureCollection',
'bbox': [-73.8967895508, 40.6514712164, -73.8665771484, 40.6737320588],
'features': [
{
'type': 'Feature',
'properties': {
'id': '85816607',
'gid': 'whosonfirst:neighbourhood:85816607',
'layer': 'neighbourhood',
'source': 'whosonfirst',
'name': 'East New York',
'confidence': 0.888,
'country': 'United States',
'country_id': '85633793',
'country_a': 'USA',
'region': 'New York',
'region_id': '85688543',
'region_a': 'NY',
'county': 'Kings County',
'county_id': '102082361',
'localadmin': 'Brooklyn',
'localadmin_id': '404521211',
'locality': 'New York',
'locality_id': '85977539',
'bounding_box': {
'min_lat': 40.6514712164,
'max_lat': 40.6737320588,
'min_lon': -73.8967895508,
'max_lon': -73.8665771484
},
'label': 'East New York, Brooklyn, NY, USA'
},
'geometry': {
'type': 'Point',
'coordinates': [
-73.881319,
40.663303
]
}
}
]
};
var json = geojsonify.search( input );
t.deepEqual(json, expected, 'all wanted properties exposed');
t.end();
});
};
module.exports.all = function (tape, common) {

65
test/unit/middleware/parseBBox.js

@ -0,0 +1,65 @@
var parseBBox = require('../../../middleware/parseBBox')();
module.exports.tests = {};
module.exports.tests.computeDistance = function(test, common) {
test('valid bounding_box json', function(t) {
var res = {
data: [
{
bounding_box: '{"min_lat":40.6514712164,"max_lat":40.6737320588,"min_lon":-73.8967895508,"max_lon":-73.8665771484}'
}
]
};
var expected = {
data: [
{
bounding_box: {
min_lat: 40.6514712164,
max_lat: 40.6737320588,
min_lon: -73.8967895508,
max_lon: -73.8665771484
}
}
]
};
parseBBox({}, res, function () {
t.deepEquals(res, expected, 'correct bounding_box');
t.end();
});
});
test('invalid bounding_box json', function(t) {
var res = {
data: [
{
bounding_box: 'garbage json'
}
]
};
var expected = {
data: [
{}
]
};
parseBBox({}, res, function () {
t.deepEquals(res, expected, 'correct bounding_box');
t.end();
});
});
};
module.exports.all = function (tape, common) {
function test(name, testFunction) {
return tape('[middleware] parseBBox: ' + name, testFunction);
}
for( var testCase in module.exports.tests ){
module.exports.tests[testCase](test, common);
}
};

1
test/unit/run.js

@ -27,6 +27,7 @@ var tests = [
require('./middleware/distance'),
require('./middleware/localNamingConventions'),
require('./middleware/dedupe'),
require('./middleware/parseBBox'),
require('./query/autocomplete'),
require('./query/autocomplete_defaults'),
require('./query/search_defaults'),

Loading…
Cancel
Save