diff --git a/modules/services/mapillary.js b/modules/services/mapillary.js index e7afb42d4..5e13da7b2 100644 --- a/modules/services/mapillary.js +++ b/modules/services/mapillary.js @@ -1,12 +1,9 @@ /* global Mapillary:false */ import _find from 'lodash-es/find'; -import _flatten from 'lodash-es/flatten'; import _forEach from 'lodash-es/forEach'; -import _map from 'lodash-es/map'; import _some from 'lodash-es/some'; import _union from 'lodash-es/union'; -import { range as d3_range } from 'd3-array'; import { dispatch as d3_dispatch } from 'd3-dispatch'; import { request as d3_request } from 'd3-request'; import { @@ -213,57 +210,29 @@ function parsePagination(links) { } -// partition viewport into `psize` x `psize` regions -function partitionViewport(psize, projection) { - var dimensions = projection.clipExtent()[1]; - psize = psize || 16; - var cols = d3_range(0, dimensions[0], psize); - var rows = d3_range(0, dimensions[1], psize); - var partitions = []; +// partition viewport into higher zoom tiles +function partitionViewport(projection) { + var z = geoScaleToZoom(projection.scale()); + var z2 = (Math.ceil(z * 2) / 2) + 2.5; // round to next 0.5 and add 2.5 + var tiler = utilTiler().zoomExtent([z2, z2]); - rows.forEach(function(y) { - cols.forEach(function(x) { - var min = [x, y + psize]; - var max = [x + psize, y]; - partitions.push( - geoExtent(projection.invert(min), projection.invert(max))); - }); - }); - - return partitions; + return tiler.getTiles(projection) + .map(function(tile) { return tile.extent; }); } // no more than `limit` results per partition. -function searchLimited(psize, limit, projection, rtree) { - limit = limit || 3; +function searchLimited(limit, projection, rtree) { + limit = limit || 5; - var partitions = partitionViewport(psize, projection); - var results; + return partitionViewport(projection) + .reduce(function(result, extent) { + var found = rtree.search(extent.bbox()) + .slice(0, limit) + .map(function(d) { return d.data; }); - // console.time('previous'); - results = _flatten(_map(partitions, function(extent) { - return rtree.search(extent.bbox()) - .slice(0, limit) - .map(function(d) { return d.data; }); - })); - // console.timeEnd('previous'); - - // console.time('new'); - // results = partitions.reduce(function(result, extent) { - // var found = rtree.search(extent.bbox()) - // .map(function(d) { return d.data; }) - // .sort(function(a, b) { - // return a.loc[1] - b.loc[1]; - // // return a.key.localeCompare(b.key); - // }) - // .slice(0, limit); - - // return (found.length ? result.concat(found) : result); - // }, []); - // console.timeEnd('new'); - - return results; + return (found.length ? result.concat(found) : result); + }, []); } @@ -309,14 +278,14 @@ export default { images: function(projection) { - var psize = 16, limit = 3; - return searchLimited(psize, limit, projection, _mlyCache.images.rtree); + var limit = 5; + return searchLimited(limit, projection, _mlyCache.images.rtree); }, signs: function(projection) { - var psize = 32, limit = 3; - return searchLimited(psize, limit, projection, _mlyCache.map_features.rtree); + var limit = 5; + return searchLimited(limit, projection, _mlyCache.map_features.rtree); }, diff --git a/modules/services/openstreetcam.js b/modules/services/openstreetcam.js index 07ef328d4..4f1d180bc 100644 --- a/modules/services/openstreetcam.js +++ b/modules/services/openstreetcam.js @@ -1,10 +1,7 @@ import _find from 'lodash-es/find'; -import _flatten from 'lodash-es/flatten'; import _forEach from 'lodash-es/forEach'; -import _map from 'lodash-es/map'; import _union from 'lodash-es/union'; -import { range as d3_range } from 'd3-array'; import { dispatch as d3_dispatch } from 'd3-dispatch'; import { request as d3_request } from 'd3-request'; @@ -164,40 +161,29 @@ function loadNextTilePage(which, currZoom, url, tile) { } -// partition viewport into `psize` x `psize` regions -function partitionViewport(psize, projection) { - var dimensions = projection.clipExtent()[1]; - psize = psize || 16; - var cols = d3_range(0, dimensions[0], psize); - var rows = d3_range(0, dimensions[1], psize); - var partitions = []; +// partition viewport into higher zoom tiles +function partitionViewport(projection) { + var z = geoScaleToZoom(projection.scale()); + var z2 = (Math.ceil(z * 2) / 2) + 2.5; // round to next 0.5 and add 2.5 + var tiler = utilTiler().zoomExtent([z2, z2]); - rows.forEach(function(y) { - cols.forEach(function(x) { - var min = [x, y + psize]; - var max = [x + psize, y]; - partitions.push( - geoExtent(projection.invert(min), projection.invert(max))); - }); - }); - - return partitions; + return tiler.getTiles(projection) + .map(function(tile) { return tile.extent; }); } // no more than `limit` results per partition. -function searchLimited(psize, limit, projection, rtree) { - limit = limit || 3; +function searchLimited(limit, projection, rtree) { + limit = limit || 5; - var partitions = partitionViewport(psize, projection); - var results; + return partitionViewport(projection) + .reduce(function(result, extent) { + var found = rtree.search(extent.bbox()) + .slice(0, limit) + .map(function(d) { return d.data; }); - results = _flatten(_map(partitions, function(extent) { - return rtree.search(extent.bbox()) - .slice(0, limit) - .map(function(d) { return d.data; }); - })); - return results; + return (found.length ? result.concat(found) : result); + }, []); } @@ -237,8 +223,8 @@ export default { images: function(projection) { - var psize = 16, limit = 3; - return searchLimited(psize, limit, projection, _oscCache.images.rtree); + var limit = 5; + return searchLimited(limit, projection, _oscCache.images.rtree); }, diff --git a/modules/services/streetside.js b/modules/services/streetside.js index d748d9251..a7bdf4eb4 100644 --- a/modules/services/streetside.js +++ b/modules/services/streetside.js @@ -1,12 +1,9 @@ import _extend from 'lodash-es/extend'; import _find from 'lodash-es/find'; -import _flatten from 'lodash-es/flatten'; import _forEach from 'lodash-es/forEach'; -import _map from 'lodash-es/map'; import _union from 'lodash-es/union'; import { dispatch as d3_dispatch } from 'd3-dispatch'; -import { range as d3_range } from 'd3-array'; import { timer as d3_timer } from 'd3-timer'; import { @@ -25,6 +22,7 @@ import { geoMetersToLon, geoPointInPolygon, geoRotate, + geoScaleToZoom, geoVecLength } from '../geo'; @@ -233,45 +231,30 @@ function getBubbles(url, tile, callback) { }); } -/** - * partitionViewport() partition viewport into `psize` x `psize` regions. - */ -function partitionViewport(psize, projection) { - var dimensions = projection.clipExtent()[1]; - psize = psize || 16; - var cols = d3_range(0, dimensions[0], psize); - var rows = d3_range(0, dimensions[1], psize); - var partitions = []; +// partition viewport into higher zoom tiles +function partitionViewport(projection) { + var z = geoScaleToZoom(projection.scale()); + var z2 = (Math.ceil(z * 2) / 2) + 2.5; // round to next 0.5 and add 2.5 + var tiler = utilTiler().zoomExtent([z2, z2]); - rows.forEach(function (y) { - cols.forEach(function (x) { - var min = [x, y + psize]; - var max = [x + psize, y]; - partitions.push(geoExtent(projection.invert(min), projection.invert(max))); - }); - }); - - return partitions; + return tiler.getTiles(projection) + .map(function(tile) { return tile.extent; }); } -/** - * searchLimited(). - */ -function searchLimited(psize, limit, projection, rtree) { - limit = limit || 3; +// no more than `limit` results per partition. +function searchLimited(limit, projection, rtree) { + limit = limit || 5; - var partitions = partitionViewport(psize, projection); - var results; + return partitionViewport(projection) + .reduce(function(result, extent) { + var found = rtree.search(extent.bbox()) + .slice(0, limit) + .map(function(d) { return d.data; }); - results = _flatten(_map(partitions, function (extent) { - return rtree.search(extent.bbox()) - .slice(0, limit) - .map(function (d) { return d.data; }); - })); - - return results; + return (found.length ? result.concat(found) : result); + }, []); } @@ -485,8 +468,8 @@ export default { * bubbles() */ bubbles: function (projection) { - var psize = 32, limit = 3; - return searchLimited(psize, limit, projection, _ssCache.bubbles.rtree); + var limit = 5; + return searchLimited(limit, projection, _ssCache.bubbles.rtree); }, diff --git a/modules/svg/mapillary_images.js b/modules/svg/mapillary_images.js index 641882790..55dfa7dd3 100644 --- a/modules/svg/mapillary_images.js +++ b/modules/svg/mapillary_images.js @@ -217,8 +217,8 @@ export function svgMapillaryImages(projection, context, dispatch) { function drawImages(selection) { - var enabled = svgMapillaryImages.enabled, - service = getService(); + var enabled = svgMapillaryImages.enabled; + var service = getService(); layer = selection.selectAll('.layer-mapillary-images') .data(service ? [0] : []); diff --git a/modules/util/tiler.js b/modules/util/tiler.js index b695da3da..ead3a75b7 100644 --- a/modules/util/tiler.js +++ b/modules/util/tiler.js @@ -111,6 +111,31 @@ export function utilTiler() { }; + /** + * getGeoJSON() returns a FeatureCollection for debugging tiles + */ + tiler.getGeoJSON = function(projection) { + var features = tiler.getTiles(projection).map(function(tile) { + return { + type: 'Feature', + properties: { + id: tile.id, + name: tile.id + }, + geometry: { + type: 'Polygon', + coordinates: [ tile.extent.polygon() ] + } + }; + }); + + return { + type: 'FeatureCollection', + features: features + }; + }; + + tiler.tileSize = function(val) { if (!arguments.length) return _tileSize; _tileSize = val; diff --git a/test/spec/services/mapillary.js b/test/spec/services/mapillary.js index f01107fbd..6e9667a0b 100644 --- a/test/spec/services/mapillary.js +++ b/test/spec/services/mapillary.js @@ -248,18 +248,19 @@ describe('iD.serviceMapillary', function() { ]); }); - it('limits results no more than 3 stacked images in one spot', function() { + it('limits results no more than 5 stacked images in one spot', function() { var features = [ { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '0', loc: [10,0], ca: 90 } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '1', loc: [10,0], ca: 90 } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '2', loc: [10,0], ca: 90 } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '3', loc: [10,0], ca: 90 } }, - { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '4', loc: [10,0], ca: 90 } } + { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '4', loc: [10,0], ca: 90 } }, + { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '5', loc: [10,0], ca: 90 } } ]; mapillary.cache().images.rtree.load(features); var res = mapillary.images(context.projection); - expect(res).to.have.length.of.at.most(3); + expect(res).to.have.length.of.at.most(5); }); }); @@ -284,7 +285,7 @@ describe('iD.serviceMapillary', function() { ]); }); - it('limits results no more than 3 stacked signs in one spot', function() { + it('limits results no more than 5 stacked signs in one spot', function() { var detections = [{ detection_key: '78vqha63gs1upg15s823qckcmn', image_key: 'bwYs-uXLDvm_meo_EC5Nzw' @@ -294,12 +295,13 @@ describe('iD.serviceMapillary', function() { { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '1', loc: [10,0], detections: detections } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '2', loc: [10,0], detections: detections } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '3', loc: [10,0], detections: detections } }, - { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '4', loc: [10,0], detections: detections } } + { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '4', loc: [10,0], detections: detections } }, + { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '5', loc: [10,0], detections: detections } } ]; mapillary.cache().map_features.rtree.load(features); var res = mapillary.signs(context.projection); - expect(res).to.have.length.of.at.most(3); + expect(res).to.have.length.of.at.most(5); }); }); diff --git a/test/spec/services/openstreetcam.js b/test/spec/services/openstreetcam.js index 01658facf..67bbadf0d 100644 --- a/test/spec/services/openstreetcam.js +++ b/test/spec/services/openstreetcam.js @@ -244,18 +244,19 @@ describe('iD.serviceOpenstreetcam', function() { ]); }); - it('limits results no more than 3 stacked images in one spot', function() { + it('limits results no more than 5 stacked images in one spot', function() { var features = [ { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '0', loc: [10,0], ca: 90, sequence_id: '100', sequence_index: 0 } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '1', loc: [10,0], ca: 90, sequence_id: '100', sequence_index: 1 } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '2', loc: [10,0], ca: 90, sequence_id: '100', sequence_index: 2 } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '3', loc: [10,0], ca: 90, sequence_id: '100', sequence_index: 3 } }, - { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '4', loc: [10,0], ca: 90, sequence_id: '100', sequence_index: 4 } } + { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '4', loc: [10,0], ca: 90, sequence_id: '100', sequence_index: 4 } }, + { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '5', loc: [10,0], ca: 90, sequence_id: '100', sequence_index: 5 } } ]; openstreetcam.cache().images.rtree.load(features); var res = openstreetcam.images(context.projection); - expect(res).to.have.length.of.at.most(3); + expect(res).to.have.length.of.at.most(5); }); }); diff --git a/test/spec/services/streetside.js b/test/spec/services/streetside.js index ab6ca67a2..f0ebebe79 100644 --- a/test/spec/services/streetside.js +++ b/test/spec/services/streetside.js @@ -132,18 +132,19 @@ describe('iD.serviceStreetside', function() { ]); }); - it('limits results no more than 3 stacked bubbles in one spot', function() { + it('limits results no more than 5 stacked bubbles in one spot', function() { var features = [ { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: 1, loc: [10, 0], ca: 90, pr: undefined, ne: 2, pano: true, sequence_id: 1 } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: 2, loc: [10, 0], ca: 90, pr: 1, ne: 3, pano: true, sequence_id: 1 } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: 3, loc: [10, 0], ca: 90, pr: 2, ne: 4, pano: true, sequence_id: 1 } }, { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: 4, loc: [10, 0], ca: 90, pr: 3, ne: 5, pano: true, sequence_id: 1 } }, - { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: 5, loc: [10, 0], ca: 90, pr: 4, ne: undefined, pano: true, sequence_id: 1 } } + { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: 5, loc: [10, 0], ca: 90, pr: 4, ne: 6, pano: true, sequence_id: 1 } }, + { minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: 6, loc: [10, 0], ca: 90, pr: 5, ne: undefined, pano: true, sequence_id: 1 } } ]; streetside.cache().bubbles.rtree.load(features); var res = streetside.bubbles(context.projection); - expect(res).to.have.length.of.at.most(3); + expect(res).to.have.length.of.at.most(5); }); });