Optimize presets.match

Previous implementation was linear in the number of
presets. This should be near constant time.
This commit is contained in:
John Firebaugh
2013-05-13 20:24:23 -07:00
parent 525d37c647
commit 9502729f5e
6 changed files with 83 additions and 26 deletions

View File

@@ -11,6 +11,37 @@ iD.presets = function() {
other,
other_area;
// Index of presets by (geometry, tag key).
var index = {
point: {},
vertex: {},
line: {},
area: {},
relation: {}
};
all.match = function(entity, resolver) {
var geometry = entity.geometry(resolver),
geometryMatches = index[geometry],
best = -1,
match = geometry === 'area' ? other_area : other;
for (var k in entity.tags) {
var keyMatches = geometryMatches[k];
if (!keyMatches) continue;
for (var i = 0; i < keyMatches.length; i++) {
var score = keyMatches[i].matchScore(entity);
if (score > best) {
best = score;
match = keyMatches[i];
}
}
}
return match;
};
all.load = function(d) {
if (d.fields) {
@@ -45,6 +76,18 @@ iD.presets = function() {
other = all.item('other');
other_area = all.item('other_area');
for (var i = 0; i < all.collection.length; i++) {
var preset = all.collection[i],
geometry = preset.geometry;
for (var j = 0; j < geometry.length; j++) {
var g = index[geometry[j]];
for (var k in preset.tags) {
(g[k] = g[k] || []).push(preset);
}
}
}
return all;
};

View File

@@ -10,32 +10,12 @@ iD.presets.Collection = function(collection) {
});
},
match: function(entity, resolver) {
return presets.matchGeometry(entity.geometry(resolver)).matchTags(entity);
},
matchGeometry: function(geometry) {
return iD.presets.Collection(collection.filter(function(d) {
return d.matchGeometry(geometry);
}));
},
matchTags: function(entity) {
var best = -1,
match;
for (var i = 0; i < collection.length; i++) {
var score = collection[i].matchScore(entity);
if (score > best) {
best = score;
match = collection[i];
}
}
return match;
},
search: function(value) {
if (!value) return this;

View File

@@ -246,6 +246,7 @@
<script src="spec/modes/add_point.js"></script>
<script src="spec/presets.js"></script>
<script src="spec/presets/preset.js"></script>
<script src="spec/presets/collection.js"></script>
<script src="spec/presets/category.js"></script>

View File

@@ -87,6 +87,7 @@
<script src="spec/modes/add_point.js"></script>
<script src="spec/presets.js"></script>
<script src="spec/presets/preset.js"></script>
<script src="spec/presets/collection.js"></script>
<script src="spec/presets/category.js"></script>

38
test/spec/presets.js Normal file
View File

@@ -0,0 +1,38 @@
describe("iD.presets", function() {
var p = {
other: {
tags: {},
geometry: ['point', 'vertex', 'line', 'area']
},
residential: {
tags: {
highway: 'residential'
},
geometry: ['line']
},
park: {
tags: {
leisure: 'park'
},
geometry: ['point', 'area']
}
};
var c = iD.presets().load({presets: p}),
w = iD.Way({tags: { highway: 'residential'}}),
g = iD.Graph().replace(w);
describe("#match", function() {
it("returns a collection containing presets matching a geometry and tags", function() {
var way = iD.Way({tags: { highway: 'residential'}}),
graph = iD.Graph([way]);
expect(c.match(way, graph).id).to.eql('residential');
});
it("returns an other preset when no tags match", function() {
var way = iD.Way({tags: {foo: 'bar'}}),
graph = iD.Graph([way]);
expect(c.match(way, graph).id).to.eql('other');
});
});
});

View File

@@ -36,12 +36,6 @@ describe("iD.presets.Collection", function() {
});
});
describe("#matchTags", function() {
it("returns a new collection only containing presets matching an entity's tags", function() {
expect(c.matchTags(w, g)).to.eql(p.residential);
});
});
describe("#search", function() {
it("filters presets by name", function() {
expect(c.search("resid").collection.indexOf(p.residential) >= 0).to.eql(true);