mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-24 17:14:04 +02:00
Merge pull request #2720 from openstreetmap/mapillary-streetsigns2
Mapillary street signs
This commit is contained in:
+9
-5
@@ -38,7 +38,9 @@
|
||||
<script src='../js/id/id.js'></script>
|
||||
<script src='../js/id/util.js'></script>
|
||||
|
||||
<script src='../js/id/services/countrycode.js'></script>
|
||||
<script src='../js/id/services.js'></script>
|
||||
<script src='../js/id/services/mapillary.js'></script>
|
||||
<script src='../js/id/services/nominatim.js'></script>
|
||||
<script src='../js/id/services/taginfo.js'></script>
|
||||
<script src='../js/id/services/wikipedia.js'></script>
|
||||
|
||||
@@ -56,7 +58,8 @@
|
||||
<script src='../js/id/renderer/map.js'></script>
|
||||
<script src='../js/id/renderer/gpx_layer.js'></script>
|
||||
<script src='../js/id/renderer/tile_layer.js'></script>
|
||||
<script src='../js/id/renderer/mapillary_layer.js'></script>
|
||||
<script src='../js/id/renderer/mapillary_image_layer.js'></script>
|
||||
<script src='../js/id/renderer/mapillary_sign_layer.js'></script>
|
||||
|
||||
<script src="../js/id/svg.js"></script>
|
||||
<script src="../js/id/svg/areas.js"></script>
|
||||
@@ -261,6 +264,7 @@
|
||||
<script src="spec/actions/split.js"></script>
|
||||
<script src="spec/actions/unrestrict_turn.js"></script>
|
||||
|
||||
<script src="spec/geo.js"></script>
|
||||
<script src="spec/geo/extent.js"></script>
|
||||
<script src="spec/geo/intersection.js"></script>
|
||||
<script src="spec/geo/multipolygon.js"></script>
|
||||
@@ -300,9 +304,9 @@
|
||||
<script src="spec/ui/preset/localized.js"></script>
|
||||
<script src="spec/ui/preset/wikipedia.js"></script>
|
||||
|
||||
<script src="spec/countrycode.js"></script>
|
||||
<script src="spec/geo.js"></script>
|
||||
<script src="spec/taginfo.js"></script>
|
||||
<script src="spec/services/mapillary.js"></script>
|
||||
<script src="spec/services/nominatim.js"></script>
|
||||
<script src="spec/services/taginfo.js"></script>
|
||||
|
||||
<script src="spec/util.js"></script>
|
||||
<script src='spec/util/session_mutex.js'></script>
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
<script src="spec/actions/straighten.js"></script>
|
||||
<script src="spec/actions/unrestrict_turn.js"></script>
|
||||
|
||||
<script src="spec/geo.js"></script>
|
||||
<script src="spec/geo/extent.js"></script>
|
||||
<script src="spec/geo/intersection.js"></script>
|
||||
<script src="spec/geo/multipolygon.js"></script>
|
||||
@@ -98,9 +99,9 @@
|
||||
<script src="spec/ui/preset/localized.js"></script>
|
||||
<script src="spec/ui/preset/wikipedia.js"></script>
|
||||
|
||||
<script src="spec/countrycode.js"></script>
|
||||
<script src="spec/geo.js"></script>
|
||||
<script src="spec/taginfo.js"></script>
|
||||
<script src="spec/services/mapillary.js"></script>
|
||||
<script src="spec/services/nominatim.js"></script>
|
||||
<script src="spec/services/taginfo.js"></script>
|
||||
|
||||
<script src="spec/util.js"></script>
|
||||
<script src='spec/util/session_mutex.js'></script>
|
||||
|
||||
+14
-1
@@ -57,7 +57,20 @@ describe("iD.geo.Extent", function () {
|
||||
|
||||
describe("#center", function () {
|
||||
it("returns the center point", function () {
|
||||
expect(iD.geo.Extent([0, 0], [5, 10]).center()).to.eql([2.5, 5]);
|
||||
expect(iD.geo.Extent([0, 0], [5, 10]).center()).to.eql([2.5, 5]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#rectangle", function () {
|
||||
it("returns the extent as a rectangle", function () {
|
||||
expect(iD.geo.Extent([0, 0], [5, 10]).rectangle()).to.eql([0, 0, 5, 10]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#polygon", function () {
|
||||
it("returns the extent as a polygon", function () {
|
||||
expect(iD.geo.Extent([0, 0], [5, 10]).polygon())
|
||||
.to.eql([[0, 0], [0, 10], [5, 10], [5, 0], [0, 0]]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
describe('iD.services.mapillary', function() {
|
||||
var dimensions = [64, 64],
|
||||
context, server, mapillary;
|
||||
|
||||
beforeEach(function() {
|
||||
context = iD();
|
||||
context.projection.scale(667544.214430109); // z14
|
||||
|
||||
server = sinon.fakeServer.create();
|
||||
mapillary = iD.services.mapillary();
|
||||
mapillary.reset();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
server.restore();
|
||||
});
|
||||
|
||||
|
||||
describe('Mapillary service', function() {
|
||||
it('Initializes cache one time', function() {
|
||||
var cache = iD.services.mapillary.cache;
|
||||
expect(cache).to.have.property('images');
|
||||
expect(cache).to.have.property('signs');
|
||||
|
||||
var mapillary2 = iD.services.mapillary();
|
||||
var cache2 = iD.services.mapillary.cache;
|
||||
expect(cache).to.equal(cache2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#loadImages', function() {
|
||||
it('fires loadedImages when images are loaded', function() {
|
||||
var spy = sinon.spy();
|
||||
mapillary.on('loadedImages', spy);
|
||||
mapillary.loadImages(context.projection, dimensions);
|
||||
|
||||
var match = /search\/im\/geojson/,
|
||||
features = [{
|
||||
type: 'Feature',
|
||||
geometry: { type: 'Point', coordinates: [0,0] },
|
||||
properties: { ca: 90, key: '0' }
|
||||
}],
|
||||
response = { type: 'FeatureCollection', features: features };
|
||||
|
||||
server.respondWith('GET', match,
|
||||
[200, { 'Content-Type': 'application/json' }, JSON.stringify(response) ]);
|
||||
server.respond();
|
||||
|
||||
expect(spy).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
it('loads multiple pages of image results', function() {
|
||||
var spy = sinon.spy();
|
||||
mapillary.on('loadedImages', spy);
|
||||
mapillary.loadImages(context.projection, dimensions);
|
||||
|
||||
var features0 = [],
|
||||
features1 = [],
|
||||
i;
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
features0.push({
|
||||
type: 'Feature',
|
||||
geometry: { type: 'Point', coordinates: [0,0] },
|
||||
properties: { ca: 90, key: String(i) }
|
||||
});
|
||||
}
|
||||
for (i = 0; i < 500; i++) {
|
||||
features1.push({
|
||||
type: 'Feature',
|
||||
geometry: { type: 'Point', coordinates: [0,0] },
|
||||
properties: { ca: 90, key: String(1000 + i) }
|
||||
});
|
||||
}
|
||||
|
||||
var match0 = /page=0/,
|
||||
response0 = { type: 'FeatureCollection', features: features0 },
|
||||
match1 = /page=1/,
|
||||
response1 = { type: 'FeatureCollection', features: features1 }
|
||||
|
||||
server.respondWith('GET', match0,
|
||||
[200, { 'Content-Type': 'application/json' }, JSON.stringify(response0) ]);
|
||||
server.respondWith('GET', match1,
|
||||
[200, { 'Content-Type': 'application/json' }, JSON.stringify(response1) ]);
|
||||
server.respond();
|
||||
|
||||
expect(spy).to.have.been.calledTwice;
|
||||
});
|
||||
});
|
||||
|
||||
describe('#loadSigns', function() {
|
||||
it('loads sign_defs', function() {
|
||||
mapillary.loadSigns(context, context.projection, dimensions);
|
||||
|
||||
var base = 'regulatory--maximum-speed-limit-65--',
|
||||
match = /traffico\/string-maps\/(\w+)-map.json/;
|
||||
|
||||
server.respondWith('GET', match, function (xhr, id) {
|
||||
xhr.respond(200, { 'Content-Type': 'application/json' },
|
||||
'{ "' + base + id + '": true }');
|
||||
});
|
||||
server.respond();
|
||||
|
||||
var sign_defs = iD.services.mapillary.sign_defs;
|
||||
|
||||
expect(sign_defs).to.have.property('au')
|
||||
.that.is.an('object')
|
||||
.that.deep.equals({'regulatory--maximum-speed-limit-65--au': true});
|
||||
expect(sign_defs).to.have.property('br')
|
||||
.that.is.an('object')
|
||||
.that.deep.equals({'regulatory--maximum-speed-limit-65--br': true});
|
||||
expect(sign_defs).to.have.property('ca')
|
||||
.that.is.an('object')
|
||||
.that.deep.equals({'regulatory--maximum-speed-limit-65--ca': true});
|
||||
expect(sign_defs).to.have.property('eu')
|
||||
.that.is.an('object')
|
||||
.that.deep.equals({'regulatory--maximum-speed-limit-65--de': true});
|
||||
expect(sign_defs).to.have.property('us')
|
||||
.that.is.an('object')
|
||||
.that.deep.equals({'regulatory--maximum-speed-limit-65--us': true});
|
||||
});
|
||||
|
||||
it('fires loadedSigns when signs are loaded', function() {
|
||||
var spy = sinon.spy();
|
||||
mapillary.on('loadedSigns', spy);
|
||||
mapillary.loadSigns(context, context.projection, dimensions);
|
||||
|
||||
var match = /search\/im\/geojson\/or/,
|
||||
rects = [{
|
||||
'package': 'trafficsign_us_3.0',
|
||||
rect: [ 0.805, 0.463, 0.833, 0.502 ],
|
||||
length: 4,
|
||||
score: '1.27',
|
||||
type: 'regulatory--maximum-speed-limit-65--us'
|
||||
}],
|
||||
features = [{
|
||||
type: 'Feature',
|
||||
geometry: { type: 'Point', coordinates: [0,0] },
|
||||
properties: { rects: rects, key: '0' }
|
||||
}],
|
||||
response = { type: 'FeatureCollection', features: features };
|
||||
|
||||
server.respondWith('GET', match,
|
||||
[200, { 'Content-Type': 'application/json' }, JSON.stringify(response) ]);
|
||||
server.respond();
|
||||
|
||||
expect(spy).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
it('loads multiple pages of signs results', function() {
|
||||
var spy = sinon.spy();
|
||||
mapillary.on('loadedSigns', spy);
|
||||
mapillary.loadSigns(context, context.projection, dimensions);
|
||||
|
||||
var rects = [{
|
||||
'package': 'trafficsign_us_3.0',
|
||||
rect: [ 0.805, 0.463, 0.833, 0.502 ],
|
||||
length: 4,
|
||||
score: '1.27',
|
||||
type: 'regulatory--maximum-speed-limit-65--us'
|
||||
}],
|
||||
features0 = [],
|
||||
features1 = [],
|
||||
i;
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
features0.push({
|
||||
type: 'Feature',
|
||||
geometry: { type: 'Point', coordinates: [0,0] },
|
||||
properties: { rects: rects, key: String(i) }
|
||||
});
|
||||
}
|
||||
for (i = 0; i < 500; i++) {
|
||||
features1.push({
|
||||
type: 'Feature',
|
||||
geometry: { type: 'Point', coordinates: [0,0] },
|
||||
properties: { rects: rects, key: String(1000 + i) }
|
||||
});
|
||||
}
|
||||
|
||||
var match0 = /page=0/,
|
||||
response0 = { type: 'FeatureCollection', features: features0 },
|
||||
match1 = /page=1/,
|
||||
response1 = { type: 'FeatureCollection', features: features1 }
|
||||
|
||||
server.respondWith('GET', match0,
|
||||
[200, { 'Content-Type': 'application/json' }, JSON.stringify(response0) ]);
|
||||
server.respondWith('GET', match1,
|
||||
[200, { 'Content-Type': 'application/json' }, JSON.stringify(response1) ]);
|
||||
server.respond();
|
||||
|
||||
expect(spy).to.have.been.calledTwice;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('#images', function() {
|
||||
it('returns images in the visible map area', function() {
|
||||
var features = [
|
||||
[0, 0, 0, 0, { key: '0', loc: [0,0], ca: 90 }],
|
||||
[0, 0, 0, 0, { key: '1', loc: [0,0], ca: 90 }],
|
||||
[0, 1, 0, 1, { key: '2', loc: [0,1], ca: 90 }]
|
||||
];
|
||||
|
||||
iD.services.mapillary.cache.images.rtree.load(features);
|
||||
var res = mapillary.images(context.projection, dimensions);
|
||||
|
||||
expect(res).to.deep.eql([
|
||||
{ key: '0', loc: [0,0], ca: 90 },
|
||||
{ key: '1', loc: [0,0], ca: 90 }
|
||||
]);
|
||||
});
|
||||
|
||||
it('limits results no more than 3 stacked images in one spot', function() {
|
||||
var features = [
|
||||
[0, 0, 0, 0, { key: '0', loc: [0,0], ca: 90 }],
|
||||
[0, 0, 0, 0, { key: '1', loc: [0,0], ca: 90 }],
|
||||
[0, 0, 0, 0, { key: '2', loc: [0,0], ca: 90 }],
|
||||
[0, 0, 0, 0, { key: '3', loc: [0,0], ca: 90 }],
|
||||
[0, 0, 0, 0, { key: '4', loc: [0,0], ca: 90 }]
|
||||
];
|
||||
|
||||
iD.services.mapillary.cache.images.rtree.load(features);
|
||||
var res = mapillary.images(context.projection, dimensions);
|
||||
expect(res).to.have.length.of.at.most(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#signs', function() {
|
||||
it('returns signs in the visible map area', function() {
|
||||
var signs = [{
|
||||
'package': 'trafficsign_us_3.0',
|
||||
rect: [ 0.805, 0.463, 0.833, 0.502 ],
|
||||
length: 4,
|
||||
score: '1.27',
|
||||
type: 'regulatory--maximum-speed-limit-65--us'
|
||||
}],
|
||||
features = [
|
||||
[0, 0, 0, 0, { key: '0', loc: [0,0], signs: signs }],
|
||||
[0, 0, 0, 0, { key: '1', loc: [0,0], signs: signs }],
|
||||
[0, 1, 0, 1, { key: '2', loc: [0,1], signs: signs }]
|
||||
];
|
||||
|
||||
iD.services.mapillary.cache.signs.rtree.load(features);
|
||||
var res = mapillary.signs(context.projection, dimensions);
|
||||
|
||||
expect(res).to.deep.eql([
|
||||
{ key: '0', loc: [0,0], signs: signs },
|
||||
{ key: '1', loc: [0,0], signs: signs }
|
||||
]);
|
||||
});
|
||||
|
||||
it('limits results no more than 3 stacked signs in one spot', function() {
|
||||
var signs = [{
|
||||
'package': 'trafficsign_us_3.0',
|
||||
rect: [ 0.805, 0.463, 0.833, 0.502 ],
|
||||
length: 4,
|
||||
score: '1.27',
|
||||
type: 'regulatory--maximum-speed-limit-65--us'
|
||||
}],
|
||||
features = [
|
||||
[0, 0, 0, 0, { key: '0', loc: [0,0], signs: signs }],
|
||||
[0, 0, 0, 0, { key: '1', loc: [0,0], signs: signs }],
|
||||
[0, 0, 0, 0, { key: '2', loc: [0,0], signs: signs }],
|
||||
[0, 0, 0, 0, { key: '3', loc: [0,0], signs: signs }],
|
||||
[0, 0, 0, 0, { key: '4', loc: [0,0], signs: signs }]
|
||||
];
|
||||
|
||||
iD.services.mapillary.cache.signs.rtree.load(features);
|
||||
var res = mapillary.signs(context.projection, dimensions);
|
||||
expect(res).to.have.length.of.at.most(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#signsSupported', function() {
|
||||
it('returns false for Internet Explorer', function() {
|
||||
var detect = iD.detect;
|
||||
iD.detect = function() { return { ie: true, browser: 'Internet Explorer' }; };
|
||||
expect(mapillary.signsSupported()).to.be.false;
|
||||
iD.detect = detect;
|
||||
});
|
||||
|
||||
it('returns false for Safari', function() {
|
||||
var detect = iD.detect;
|
||||
iD.detect = function() { return { ie: false, browser: 'Safari' }; };
|
||||
expect(mapillary.signsSupported()).to.be.false;
|
||||
iD.detect = detect;
|
||||
});
|
||||
});
|
||||
|
||||
describe('#signHTML', function() {
|
||||
it('returns sign HTML', function() {
|
||||
iD.services.mapillary.sign_defs = {
|
||||
us: {'regulatory--maximum-speed-limit-65--us': '<span class="t">65</span>'}
|
||||
};
|
||||
|
||||
var signdata = {
|
||||
key: '0',
|
||||
loc: [0,0],
|
||||
signs: [{
|
||||
'package': 'trafficsign_us_3.0',
|
||||
rect: [ 0.805, 0.463, 0.833, 0.502 ],
|
||||
length: 4,
|
||||
score: '1.27',
|
||||
type: 'regulatory--maximum-speed-limit-65--us'
|
||||
}]
|
||||
};
|
||||
|
||||
expect(mapillary.signHTML(signdata)).to.eql('<span class="t">65</span>')
|
||||
});
|
||||
});
|
||||
|
||||
describe('#selectedThumbnail', function() {
|
||||
it('sets thumbnail image', function() {
|
||||
mapillary.selectedThumbnail('foo');
|
||||
expect(iD.services.mapillary.thumb).to.eql('foo');
|
||||
});
|
||||
|
||||
it('gets thumbnail image', function() {
|
||||
iD.services.mapillary.thumb = 'bar';
|
||||
expect(mapillary.selectedThumbnail()).to.eql('bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#reset', function() {
|
||||
it('resets cache and thumbnail image', function() {
|
||||
iD.services.mapillary.cache.foo = 'bar';
|
||||
iD.services.mapillary.thumb = 'bar';
|
||||
|
||||
mapillary.reset();
|
||||
expect(iD.services.mapillary.cache).to.not.have.property('foo');
|
||||
expect(iD.services.mapillary.thumb).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,10 +1,10 @@
|
||||
describe("iD.countryCode", function() {
|
||||
var server, countryCode;
|
||||
describe("iD.services.nominatim", function() {
|
||||
var server, nominatim;
|
||||
|
||||
beforeEach(function() {
|
||||
server = sinon.fakeServer.create();
|
||||
iD.countryCode.cache = null;
|
||||
countryCode = iD.countryCode();
|
||||
nominatim = iD.services.nominatim();
|
||||
nominatim.reset();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
@@ -15,10 +15,10 @@ describe("iD.countryCode", function() {
|
||||
return iD.util.stringQs(url.substring(url.indexOf('?') + 1));
|
||||
}
|
||||
|
||||
describe("#search", function() {
|
||||
it("calls the given callback with the results of the search query", function() {
|
||||
describe("#countryCode", function() {
|
||||
it("calls the given callback with the results of the country code query", function() {
|
||||
var callback = sinon.spy();
|
||||
countryCode.search([16, 48], callback);
|
||||
nominatim.countryCode([16, 48], callback);
|
||||
|
||||
server.respondWith("GET", "https://nominatim.openstreetmap.org/reverse?addressdetails=1&format=json&lat=48&lon=16",
|
||||
[200, { "Content-Type": "application/json" },
|
||||
@@ -29,9 +29,9 @@ describe("iD.countryCode", function() {
|
||||
{format: "json", addressdetails: "1", lat: "48", lon: "16"});
|
||||
expect(callback).to.have.been.calledWith(null, "at");
|
||||
});
|
||||
it("should not cache the first search result", function() {
|
||||
it("should not cache the first country code result", function() {
|
||||
var callback = sinon.spy();
|
||||
countryCode.search([16, 48], callback);
|
||||
nominatim.countryCode([16, 48], callback);
|
||||
|
||||
server.respondWith("GET", "https://nominatim.openstreetmap.org/reverse?addressdetails=1&format=json&lat=48&lon=16",
|
||||
[200, { "Content-Type": "application/json" },
|
||||
@@ -45,7 +45,7 @@ describe("iD.countryCode", function() {
|
||||
server.restore();
|
||||
server = sinon.fakeServer.create();
|
||||
|
||||
countryCode.search([17, 49], callback);
|
||||
nominatim.countryCode([17, 49], callback);
|
||||
|
||||
server.respondWith("GET", "https://nominatim.openstreetmap.org/reverse?addressdetails=1&format=json&lat=49&lon=17",
|
||||
[200, { "Content-Type": "application/json" },
|
||||
@@ -56,9 +56,9 @@ describe("iD.countryCode", function() {
|
||||
{format: "json", addressdetails: "1", lat: "49", lon: "17"});
|
||||
expect(callback).to.have.been.calledWith(null, "cz");
|
||||
});
|
||||
it("should cache the first search result", function() {
|
||||
it("should cache the first country code result", function() {
|
||||
var callback = sinon.spy();
|
||||
countryCode.search([16, 48], callback);
|
||||
nominatim.countryCode([16, 48], callback);
|
||||
|
||||
server.respondWith("GET", "https://nominatim.openstreetmap.org/reverse?addressdetails=1&format=json&lat=48&lon=16",
|
||||
[200, { "Content-Type": "application/json" },
|
||||
@@ -72,7 +72,7 @@ describe("iD.countryCode", function() {
|
||||
server.restore();
|
||||
server = sinon.fakeServer.create();
|
||||
|
||||
countryCode.search([16.01, 48.01], callback);
|
||||
nominatim.countryCode([16.01, 48.01], callback);
|
||||
|
||||
server.respondWith("GET", "https://nominatim.openstreetmap.org/reverse?addressdetails=1&format=json&lat=48.01&lon=16.01",
|
||||
[200, { "Content-Type": "application/json" },
|
||||
@@ -83,7 +83,7 @@ describe("iD.countryCode", function() {
|
||||
});
|
||||
it("calls the given callback with an error", function() {
|
||||
var callback = sinon.spy();
|
||||
countryCode.search([1000, 1000], callback);
|
||||
nominatim.countryCode([1000, 1000], callback);
|
||||
|
||||
server.respondWith("GET", "https://nominatim.openstreetmap.org/reverse?addressdetails=1&format=json&lat=1000&lon=1000",
|
||||
[200, { "Content-Type": "application/json" },
|
||||
@@ -1,9 +1,9 @@
|
||||
describe("iD.taginfo", function() {
|
||||
describe("iD.services.taginfo", function() {
|
||||
var server, taginfo;
|
||||
|
||||
beforeEach(function() {
|
||||
server = sinon.fakeServer.create();
|
||||
taginfo = iD.taginfo();
|
||||
taginfo = iD.services.taginfo();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
Reference in New Issue
Block a user