mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-15 05:30:35 +02:00
Use new Mapillary API calls for map_features, image_detections
(closes #5374)
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
import _find from 'lodash-es/find';
|
||||
import _flatten from 'lodash-es/flatten';
|
||||
import _forEach from 'lodash-es/forEach';
|
||||
import _isEmpty from 'lodash-es/isEmpty';
|
||||
import _map from 'lodash-es/map';
|
||||
import _some from 'lodash-es/some';
|
||||
import _union from 'lodash-es/union';
|
||||
@@ -111,6 +110,9 @@ function loadNextTilePage(which, currZoom, url, tile) {
|
||||
var loc = feature.geometry.coordinates;
|
||||
var d;
|
||||
|
||||
// An image (shown as a green dot on the map) is a single street photo with extra
|
||||
// information such as location, camera angle (CA), camera model, and so on.
|
||||
// Each image feature is a GeoJSON Point
|
||||
if (which === 'images') {
|
||||
d = {
|
||||
loc: loc,
|
||||
@@ -120,17 +122,44 @@ function loadNextTilePage(which, currZoom, url, tile) {
|
||||
captured_by: feature.properties.username,
|
||||
pano: feature.properties.pano
|
||||
};
|
||||
|
||||
cache.forImageKey[d.key] = d; // cache imageKey -> image
|
||||
|
||||
// Mapillary organizes images as sequences. A sequence of images are continuously captured
|
||||
// by a user at a give time. Sequences are shown on the map as green lines.
|
||||
// Each sequence feature is a GeoJSON LineString
|
||||
} else if (which === 'sequences') {
|
||||
var sequenceKey = feature.properties.key;
|
||||
cache.lineString[sequenceKey] = feature; // cache sequenceKey -> lineString
|
||||
feature.properties.coordinateProperties.image_keys.forEach(function(imageKey) {
|
||||
cache.forImageKey[imageKey] = sequenceKey; // cache imageKey -> sequenceKey
|
||||
});
|
||||
return false; // because no `d` data worth loading into an rbush
|
||||
return false; // because no `d` data worth loading into an rbush
|
||||
|
||||
} else if (which === 'objects') {
|
||||
// An image detection is a semantic pixel area on an image. The area could indicate
|
||||
// sky, trees, sidewalk in the image. A detection can be a polygon, a bounding box, or a point.
|
||||
// Each image_detection feature is a GeoJSON Point (located where the image was taken)
|
||||
} else if (which === 'image_detections') {
|
||||
d = {
|
||||
key: feature.properties.key,
|
||||
image_key: feature.properties.image_key,
|
||||
value: feature.properties.value,
|
||||
package: feature.properties.package,
|
||||
shape: feature.properties.shape
|
||||
};
|
||||
|
||||
// cache imageKey -> image_detections
|
||||
if (!cache.forImageKey[d.image_key]) {
|
||||
cache.forImageKey[d.image_key] = [];
|
||||
}
|
||||
cache.forImageKey[d.image_key].push(d);
|
||||
return false; // because no `d` data worth loading into an rbush
|
||||
|
||||
|
||||
// A map feature is a real world object that can be shown on a map. It could be any object
|
||||
// recognized from images, manually added in images, or added on the map.
|
||||
// Each map feature is a GeoJSON Point (located where the feature is)
|
||||
} else if (which === 'map_features') {
|
||||
d = {
|
||||
loc: loc,
|
||||
key: feature.properties.key,
|
||||
@@ -138,18 +167,6 @@ function loadNextTilePage(which, currZoom, url, tile) {
|
||||
package: feature.properties.package,
|
||||
detections: feature.properties.detections
|
||||
};
|
||||
|
||||
// cache imageKey -> detectionKey
|
||||
feature.properties.detections.forEach(function(detection) {
|
||||
var imageKey = detection.image_key;
|
||||
var detectionKey = detection.detection_key;
|
||||
if (!_mlyCache.detections[imageKey]) {
|
||||
_mlyCache.detections[imageKey] = {};
|
||||
}
|
||||
if (!_mlyCache.detections[imageKey][detectionKey]) {
|
||||
_mlyCache.detections[imageKey][detectionKey] = {};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -158,11 +175,13 @@ function loadNextTilePage(which, currZoom, url, tile) {
|
||||
|
||||
}).filter(Boolean);
|
||||
|
||||
cache.rtree.load(features);
|
||||
if (cache.rtree && features) {
|
||||
cache.rtree.load(features);
|
||||
}
|
||||
|
||||
if (which === 'images' || which === 'sequences') {
|
||||
dispatch.call('loadedImages');
|
||||
} else if (which === 'objects') {
|
||||
} else if (which === 'map_features') {
|
||||
dispatch.call('loadedSigns');
|
||||
}
|
||||
|
||||
@@ -266,8 +285,11 @@ export default {
|
||||
if (cache.images && cache.images.inflight) {
|
||||
_forEach(cache.images.inflight, abortRequest);
|
||||
}
|
||||
if (cache.objects && cache.objects.inflight) {
|
||||
_forEach(cache.objects.inflight, abortRequest);
|
||||
if (cache.image_detections && cache.image_detections.inflight) {
|
||||
_forEach(cache.image_detections.inflight, abortRequest);
|
||||
}
|
||||
if (cache.map_features && cache.map_features.inflight) {
|
||||
_forEach(cache.map_features.inflight, abortRequest);
|
||||
}
|
||||
if (cache.sequences && cache.sequences.inflight) {
|
||||
_forEach(cache.sequences.inflight, abortRequest);
|
||||
@@ -276,9 +298,9 @@ export default {
|
||||
|
||||
_mlyCache = {
|
||||
images: { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: rbush(), forImageKey: {} },
|
||||
objects: { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: rbush() },
|
||||
sequences: { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: rbush(), forImageKey: {}, lineString: {} },
|
||||
detections: {}
|
||||
image_detections: { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, forImageKey: {} },
|
||||
map_features: { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: rbush() },
|
||||
sequences: { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: rbush(), forImageKey: {}, lineString: {} }
|
||||
};
|
||||
|
||||
_mlySelectedImage = null;
|
||||
@@ -294,7 +316,7 @@ export default {
|
||||
|
||||
signs: function(projection) {
|
||||
var psize = 32, limit = 3;
|
||||
return searchLimited(psize, limit, projection, _mlyCache.objects.rtree);
|
||||
return searchLimited(psize, limit, projection, _mlyCache.map_features.rtree);
|
||||
},
|
||||
|
||||
|
||||
@@ -335,7 +357,8 @@ export default {
|
||||
loadSigns: function(context, projection) {
|
||||
// if we are looking at signs, we'll actually need to fetch images too
|
||||
loadTiles('images', apibase + 'images?', projection);
|
||||
loadTiles('objects', apibase + 'map_features?layers=trafficsigns&', projection);
|
||||
loadTiles('map_features', apibase + 'map_features?layers=trafficsigns&min_nbr_image_detections=1&', projection);
|
||||
loadTiles('image_detections', apibase + 'image_detections?layers=trafficsigns&', projection);
|
||||
},
|
||||
|
||||
|
||||
@@ -537,6 +560,7 @@ export default {
|
||||
|
||||
this.setStyles(null, true);
|
||||
|
||||
// if signs signs are shown, highlight the ones that appear in this image
|
||||
d3_selectAll('.layer-mapillary-signs .icon-sign')
|
||||
.classed('selected', function(d) {
|
||||
return _some(d.detections, function(detection) {
|
||||
@@ -620,63 +644,32 @@ export default {
|
||||
if (!_mlyViewer || _mlyFallback) return;
|
||||
|
||||
var imageKey = d && d.key;
|
||||
var detections = (imageKey && _mlyCache.detections[imageKey]) || [];
|
||||
if (!imageKey) return;
|
||||
|
||||
_forEach(detections, function(data, k) {
|
||||
if (_isEmpty(data)) {
|
||||
loadDetection(k);
|
||||
} else {
|
||||
var tag = makeTag(data);
|
||||
if (tag) {
|
||||
var tagComponent = _mlyViewer.getComponent('tag');
|
||||
tagComponent.add([tag]);
|
||||
}
|
||||
var detections = _mlyCache.image_detections.forImageKey[imageKey] || [];
|
||||
detections.forEach(function(data) {
|
||||
var tag = makeTag(data);
|
||||
if (tag) {
|
||||
var tagComponent = _mlyViewer.getComponent('tag');
|
||||
tagComponent.add([tag]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function loadDetection(detectionKey) {
|
||||
var url = apibase + 'image_detections/' +
|
||||
detectionKey + '?' + utilQsString({ client_id: clientId });
|
||||
|
||||
d3_request(url)
|
||||
.mimeType('application/json')
|
||||
.response(function(xhr) {
|
||||
return JSON.parse(xhr.responseText);
|
||||
})
|
||||
.get(function(err, data) {
|
||||
if (!data || !data.properties) return;
|
||||
|
||||
var imageKey = data.properties.image_key;
|
||||
_mlyCache.detections[imageKey][detectionKey] = data;
|
||||
|
||||
var selectedKey = _mlySelectedImage && _mlySelectedImage.key;
|
||||
if (imageKey === selectedKey) {
|
||||
var tag = makeTag(data);
|
||||
if (tag) {
|
||||
var tagComponent = _mlyViewer.getComponent('tag');
|
||||
tagComponent.add([tag]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function makeTag(data) {
|
||||
var valueParts = data.properties.value.split('--');
|
||||
var valueParts = data.value.split('--');
|
||||
if (valueParts.length !== 3) return;
|
||||
|
||||
var text = valueParts[1].replace(/-/g, ' ');
|
||||
var tag;
|
||||
|
||||
// Currently only two shapes <Polygon|Point>
|
||||
if (data.properties.shape.type === 'Polygon') {
|
||||
if (data.shape.type === 'Polygon') {
|
||||
var polygonGeometry = new Mapillary
|
||||
.TagComponent
|
||||
.PolygonGeometry(data.properties.shape.coordinates[0]);
|
||||
.PolygonGeometry(data.shape.coordinates[0]);
|
||||
|
||||
tag = new Mapillary.TagComponent.OutlineTag(
|
||||
data.properties.key,
|
||||
data.key,
|
||||
polygonGeometry,
|
||||
{
|
||||
text: text,
|
||||
@@ -688,13 +681,13 @@ export default {
|
||||
}
|
||||
);
|
||||
|
||||
} else if (data.properties.shape.type === 'Point') {
|
||||
} else if (data.shape.type === 'Point') {
|
||||
var pointGeometry = new Mapillary
|
||||
.TagComponent
|
||||
.PointGeometry(data.properties.shape.coordinates[0]);
|
||||
.PointGeometry(data.shape.coordinates[0]);
|
||||
|
||||
tag = new Mapillary.TagComponent.SpotTag(
|
||||
data.properties.key,
|
||||
data.key,
|
||||
pointGeometry,
|
||||
{
|
||||
text: text,
|
||||
|
||||
@@ -32,9 +32,9 @@ describe('iD.serviceMapillary', function() {
|
||||
it('Initializes cache one time', function() {
|
||||
var cache = mapillary.cache();
|
||||
expect(cache).to.have.property('images');
|
||||
expect(cache).to.have.property('objects');
|
||||
expect(cache).to.have.property('image_detections');
|
||||
expect(cache).to.have.property('map_features');
|
||||
expect(cache).to.have.property('sequences');
|
||||
expect(cache).to.have.property('detections');
|
||||
|
||||
mapillary.init();
|
||||
var cache2 = mapillary.cache();
|
||||
@@ -275,7 +275,7 @@ describe('iD.serviceMapillary', function() {
|
||||
{ minX: 10, minY: 1, maxX: 10, maxY: 1, data: { key: '2', loc: [10,1], detections: detections } }
|
||||
];
|
||||
|
||||
mapillary.cache().objects.rtree.load(features);
|
||||
mapillary.cache().map_features.rtree.load(features);
|
||||
var res = mapillary.signs(context.projection);
|
||||
|
||||
expect(res).to.deep.eql([
|
||||
@@ -297,7 +297,7 @@ describe('iD.serviceMapillary', function() {
|
||||
{ minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '4', loc: [10,0], detections: detections } }
|
||||
];
|
||||
|
||||
mapillary.cache().objects.rtree.load(features);
|
||||
mapillary.cache().map_features.rtree.load(features);
|
||||
var res = mapillary.signs(context.projection);
|
||||
expect(res).to.have.length.of.at.most(3);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user