Fast parent calculation.

This commit is contained in:
Tom MacWright
2013-01-09 14:52:39 -05:00
parent 543a6e169c
commit eedc0fce9d
8 changed files with 79 additions and 25 deletions

View File

@@ -103,7 +103,7 @@
<body>
<div id="iD"></div><script>
var id = iD();
id.connection().url('http://api06.dev.openstreetmap.org');
// id.connection().url('http://api06.dev.openstreetmap.org');
d3.select("#iD").call(id);
</script></body>
</html>

View File

@@ -3,7 +3,7 @@ iD.actions.DeleteNode = function(nodeId) {
return function(graph) {
var node = graph.entity(nodeId);
graph.parentWays(nodeId)
graph.parentWays(node)
.forEach(function(parent) {
graph = iD.actions.RemoveWayNode(parent.id, nodeId)(graph);
});

View File

@@ -3,7 +3,7 @@ iD.actions.DeleteWay = function(wayId) {
return function(graph) {
var way = graph.entity(wayId);
graph.parentRelations(wayId)
graph.parentRelations(way)
.forEach(function(parent) {
graph = iD.actions.RemoveRelationMember(parent.id, wayId)(graph);
});
@@ -17,7 +17,8 @@ iD.actions.DeleteWay = function(wayId) {
graph = iD.actions.RemoveWayNode(wayId, nodeId)(graph);
if (!graph.parentWays(nodeId).length && !graph.parentRelations(nodeId).length) {
if (!graph.parentWays(node).length &&
!graph.parentRelations(node).length) {
if (!node.hasInterestingTags()) {
graph = graph.remove(node);
} else {

View File

@@ -62,7 +62,7 @@ iD.actions.ReverseWay = function(wayId) {
tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
}
graph.parentRelations(way.id).forEach(function (relation) {
graph.parentRelations(way).forEach(function (relation) {
relation.members.forEach(function (member, index) {
if (member.id === way.id && (role = {forward: 'backward', backward: 'forward'}[member.role])) {
graph = iD.actions.UpdateRelationMember(relation.id, index, {role: role})(graph);

View File

@@ -86,17 +86,53 @@ iD.Connection = function() {
var root = dom.childNodes[0];
var entities = {};
refNodes = {};
var rparentsOf = {},
wparentsOf = {};
function addEntity(obj) {
var o = objectData(obj);
entities[o.id] = o;
var i;
if (o.type === 'relation') {
for (i = 0; i < o.members.length; i++) {
if (o.members[i].id) {
if (rparentsOf[o.members[i].id] === undefined) {
rparentsOf[o.members[i].id] = [];
}
rparentsOf[o.members[i].id].push(o.id);
}
}
}
if (o.type === 'way') {
for (i = 0; i < o.nodes.length; i++) {
if (o.nodes[i]) {
if (wparentsOf[o.nodes[i]] === undefined) {
wparentsOf[o.nodes[i]] = [];
}
wparentsOf[o.nodes[i]].push(o.id);
}
}
}
}
_.forEach(root.getElementsByTagName('way'), addEntity);
_.forEach(root.getElementsByTagName('node'), addEntity);
_.forEach(root.getElementsByTagName('relation'), addEntity);
return iD.Graph(entities);
var g = iD.Graph(entities);
for (var i in wparentsOf) {
if (entities[i]) g.transient(entities[i],
'parentWays', d3.functor(wparentsOf[i]));
}
for (i in rparentsOf) {
if (entities[i]) g.transient(entities[i],
'parentRelations', d3.functor(rparentsOf[i]));
}
return g;
}
function authenticated() {

View File

@@ -25,7 +25,8 @@ iD.Graph.prototype = {
transient: function(entity, key, fn) {
var id = entity.id,
transients = this.transients[id] || (this.transients[id] = {});
transients = this.transients[id] ||
(this.transients[id] = {});
if (transients[key]) {
return transients[key];
@@ -45,23 +46,38 @@ iD.Graph.prototype = {
return nodes;
},
parentWays: function(id) {
var o = [];
for (var i in this.entities) {
if (this.entities[i] &&
this.entities[i].type === 'way' &&
this.entities[i].nodes.indexOf(id) !== -1) {
o.push(this.entities[i]);
parentWays: function(entity) {
var graph = this;
return this.transient(entity, 'parentWays',
function generateParentWays() {
var o = [];
for (var i in graph.entities) {
if (graph.entities[i] &&
graph.entities[i].type === 'way' &&
graph.entities[i].nodes.indexOf(this.id) !== -1) {
o.push(graph.entities[i]);
}
}
}
return o;
return o;
});
},
parentRelations: function(id) {
parentRelations: function(entity) {
// This is slow and a bad hack.
return _.filter(this.entities, function buildParentRelations(e) {
return e && e.type === 'relation' &&
_.pluck(e.members, 'id').indexOf(id) !== -1;
var graph = this;
return this.transient(entity, 'parentRelations',
function generateParentRelations() {
var o = [], id = this.id;
for (var i in graph.entities) {
if (graph.entities[i] &&
graph.entities[i].type === 'relation' &&
_.find(graph.entities[i].members, function(e) {
return e.id === id;
})) {
o.push(graph.entities[i]);
}
}
return o;
});
},

View File

@@ -79,7 +79,7 @@ iD.Map = function() {
var id = difference[j];
only[id] = graph.fetch(id);
if (only[id] && only[id].type === 'node') {
var parents = graph.parentWays(id);
var parents = graph.parentWays(only[id]);
for (var k = 0; k < parents.length; k++) {
// Don't re-fetch parents
if (only[parents[k].id] === undefined) {

View File

@@ -69,18 +69,19 @@ describe('iD.Graph', function() {
var node = iD.Node({id: "n1"}),
way = iD.Way({id: "w1", nodes: ["n1"]}),
graph = iD.Graph({n1: node, w1: way});
expect(graph.parentWays("n1")).to.eql([way]);
expect(graph.parentWays("n2")).to.eql([]);
expect(graph.parentWays(node)).to.eql([way]);
expect(graph.parentWays(way)).to.eql([]);
});
});
describe("#parentRelations", function() {
it("returns an array of relations that contain the given entity id", function () {
var node = iD.Node({id: "n1"}),
nonnode = iD.Node({id: "n2"}),
relation = iD.Relation({id: "r1", members: [{ id: "n1", role: 'from' }]}),
graph = iD.Graph({n1: node, r1: relation});
expect(graph.parentRelations("n1")).to.eql([relation]);
expect(graph.parentRelations("n2")).to.eql([]);
expect(graph.parentRelations(node)).to.eql([relation]);
expect(graph.parentRelations(nonnode)).to.eql([]);
});
});