mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-20 15:34:49 +02:00
Merge branch 'tree-intersects'
Conflicts: js/id/behavior/lasso.js
This commit is contained in:
@@ -151,6 +151,7 @@
|
||||
<script src='js/id/core/node.js'></script>
|
||||
<script src='js/id/core/relation.js'></script>
|
||||
<script src='js/id/core/way.js'></script>
|
||||
<script src='js/id/core/tree.js'></script>
|
||||
|
||||
<script src='js/id/connection.js'></script>
|
||||
<script src='js/id/validate.js'></script>
|
||||
|
||||
@@ -49,7 +49,7 @@ iD.behavior.Lasso = function(context) {
|
||||
.on('mouseup.lasso', null);
|
||||
|
||||
if (d3.event.clientX !== pos[0] || d3.event.clientY !== pos[1]) {
|
||||
var selected = context.graph().intersects(extent).filter(function (entity) {
|
||||
var selected = context.intersects(extent).filter(function (entity) {
|
||||
return entity.type === 'node';
|
||||
});
|
||||
|
||||
|
||||
+25
-16
@@ -25,6 +25,18 @@ iD.Difference = function(base, head) {
|
||||
}
|
||||
});
|
||||
|
||||
function addParents(parents, result) {
|
||||
for (var i = 0; i < parents.length; i++) {
|
||||
var parent = parents[i];
|
||||
|
||||
if (parent.id in result)
|
||||
continue;
|
||||
|
||||
result[parent.id] = parent;
|
||||
addParents(head.parentRelations(parent), result);
|
||||
}
|
||||
}
|
||||
|
||||
var difference = {};
|
||||
|
||||
difference.length = function() {
|
||||
@@ -67,21 +79,18 @@ iD.Difference = function(base, head) {
|
||||
return result;
|
||||
};
|
||||
|
||||
difference.addParents = function(entities) {
|
||||
|
||||
for (var i in entities) {
|
||||
addParents(head.parentWays(entities[i]), entities);
|
||||
addParents(head.parentRelations(entities[i]), entities);
|
||||
}
|
||||
return entities;
|
||||
},
|
||||
|
||||
difference.complete = function(extent) {
|
||||
var result = {}, id, change;
|
||||
|
||||
function addParents(parents) {
|
||||
for (var i = 0; i < parents.length; i++) {
|
||||
var parent = parents[i];
|
||||
|
||||
if (parent.id in result)
|
||||
continue;
|
||||
|
||||
result[parent.id] = parent;
|
||||
addParents(head.parentRelations(parent));
|
||||
}
|
||||
}
|
||||
|
||||
for (id in changes) {
|
||||
change = changes[id];
|
||||
|
||||
@@ -99,10 +108,10 @@ iD.Difference = function(base, head) {
|
||||
if (entity.type === 'way') {
|
||||
var nh = h ? h.nodes : [],
|
||||
nb = b ? b.nodes : [],
|
||||
diff;
|
||||
diff, i;
|
||||
|
||||
diff = _.difference(nh, nb);
|
||||
for (var i = 0; i < diff.length; i++) {
|
||||
for (i = 0; i < diff.length; i++) {
|
||||
result[diff[i]] = head.entity(diff[i]);
|
||||
}
|
||||
|
||||
@@ -111,9 +120,9 @@ iD.Difference = function(base, head) {
|
||||
result[diff[i]] = head.entity(diff[i]);
|
||||
}
|
||||
}
|
||||
addParents(head.parentWays(entity), result);
|
||||
addParents(head.parentRelations(entity), result);
|
||||
|
||||
addParents(head.parentWays(entity));
|
||||
addParents(head.parentRelations(entity));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
+1
-12
@@ -226,21 +226,10 @@ iD.Graph.prototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
// get all objects that intersect an extent.
|
||||
intersects: function(extent) {
|
||||
var items = [];
|
||||
for (var i in this.entities) {
|
||||
var entity = this.entities[i];
|
||||
if (entity && this.hasAllChildren(entity) && entity.intersects(extent, this)) {
|
||||
items.push(entity);
|
||||
}
|
||||
}
|
||||
return items;
|
||||
},
|
||||
|
||||
hasAllChildren: function(entity) {
|
||||
// we're only checking changed entities, since we assume fetched data
|
||||
// must have all children present
|
||||
var i;
|
||||
if (this.entities.hasOwnProperty(entity.id)) {
|
||||
if (entity.type === 'way') {
|
||||
for (i = 0; i < entity.nodes.length; i++) {
|
||||
|
||||
+15
-1
@@ -1,5 +1,5 @@
|
||||
iD.History = function(context) {
|
||||
var stack, index,
|
||||
var stack, index, tree,
|
||||
imagery_used = 'Bing',
|
||||
dispatch = d3.dispatch('change', 'undone', 'redone'),
|
||||
lock = false;
|
||||
@@ -41,10 +41,19 @@ iD.History = function(context) {
|
||||
},
|
||||
|
||||
merge: function(entities) {
|
||||
|
||||
|
||||
var base = stack[0].graph.base(),
|
||||
newentities = Object.keys(entities).filter(function(i) {
|
||||
return !base.entities[i];
|
||||
});
|
||||
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
stack[i].graph.rebase(entities);
|
||||
}
|
||||
|
||||
tree.rebase(newentities);
|
||||
|
||||
dispatch.change();
|
||||
},
|
||||
|
||||
@@ -124,6 +133,10 @@ iD.History = function(context) {
|
||||
}
|
||||
},
|
||||
|
||||
intersects: function(extent) {
|
||||
return tree.intersects(extent, stack[index].graph);
|
||||
},
|
||||
|
||||
difference: function() {
|
||||
var base = stack[0].graph,
|
||||
head = stack[index].graph;
|
||||
@@ -168,6 +181,7 @@ iD.History = function(context) {
|
||||
reset: function() {
|
||||
stack = [{graph: iD.Graph()}];
|
||||
index = 0;
|
||||
tree = iD.Tree(stack[0].graph);
|
||||
dispatch.change();
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
|
||||
|
||||
iD.Tree = function(graph) {
|
||||
|
||||
var rtree = new RTree(),
|
||||
m = 1000 * 1000 * 100,
|
||||
head = graph,
|
||||
queuedCreated = [],
|
||||
queuedModified = [],
|
||||
x, y, dx, dy, rebased;
|
||||
|
||||
function extentRectangle(extent) {
|
||||
x = m * extent[0][0],
|
||||
y = m * extent[0][1],
|
||||
dx = m * extent[1][0] - x || 1,
|
||||
dy = m * extent[1][1] - y || 1;
|
||||
return new RTree.Rectangle(~~x, ~~y, ~~dx - 1, ~~dy - 1);
|
||||
}
|
||||
|
||||
function insert(entity) {
|
||||
rtree.insert(extentRectangle(entity.extent(head)), entity.id);
|
||||
}
|
||||
|
||||
function remove(entity) {
|
||||
rtree.remove(extentRectangle(entity.extent(graph)), entity.id);
|
||||
}
|
||||
|
||||
function reinsert(entity) {
|
||||
remove(graph.entities[entity.id]);
|
||||
insert(entity);
|
||||
}
|
||||
|
||||
var tree = {
|
||||
|
||||
rebase: function(entities) {
|
||||
for (var i = 0; i < entities.length; i++) {
|
||||
if (!graph.entities.hasOwnProperty(entities[i])) {
|
||||
insert(graph.entity(entities[i]), true);
|
||||
}
|
||||
}
|
||||
rebased = true;
|
||||
return tree;
|
||||
},
|
||||
|
||||
intersects: function(extent, g) {
|
||||
|
||||
head = g;
|
||||
|
||||
if (graph !== head || rebased) {
|
||||
var diff = iD.Difference(graph, head),
|
||||
modified = {};
|
||||
|
||||
diff.modified().forEach(function(d) {
|
||||
var loc = graph.entities[d.id].loc;
|
||||
if (!loc || loc[0] !== d.loc[0] || loc[1] !== d.loc[1]) {
|
||||
modified[d.id] = d;
|
||||
}
|
||||
});
|
||||
|
||||
var created = diff.created().concat(queuedCreated);
|
||||
modified = d3.values(diff.addParents(modified)).concat(queuedModified);
|
||||
queuedCreated = [];
|
||||
queuedModified = [];
|
||||
|
||||
modified.forEach(function(d) {
|
||||
if (head.hasAllChildren(d)) reinsert(d);
|
||||
else queuedModified.push(d);
|
||||
});
|
||||
|
||||
created.forEach(function(d) {
|
||||
if (head.hasAllChildren(d)) insert(d);
|
||||
else queuedCreated.push(d);
|
||||
});
|
||||
|
||||
diff.deleted().forEach(remove);
|
||||
|
||||
graph = head;
|
||||
rebased = false;
|
||||
}
|
||||
|
||||
return rtree.search(extentRectangle(extent))
|
||||
.map(function(id) { return graph.entity(id); });
|
||||
},
|
||||
|
||||
graph: function() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return tree;
|
||||
};
|
||||
@@ -36,6 +36,7 @@ window.iD = function () {
|
||||
context.undo = history.undo;
|
||||
context.redo = history.redo;
|
||||
context.changes = history.changes;
|
||||
context.intersects = history.intersects;
|
||||
|
||||
/* Graph */
|
||||
context.entity = function(id) {
|
||||
|
||||
@@ -65,7 +65,7 @@ iD.Map = function(context) {
|
||||
graph = context.graph();
|
||||
|
||||
if (!difference) {
|
||||
all = graph.intersects(extent);
|
||||
all = context.intersects(extent);
|
||||
filter = d3.functor(true);
|
||||
} else {
|
||||
var complete = difference.complete(extent);
|
||||
|
||||
@@ -2,7 +2,7 @@ iD.ui.Contributors = function(context) {
|
||||
function update(selection) {
|
||||
var users = {},
|
||||
limit = 3,
|
||||
entities = context.graph().intersects(context.map().extent());
|
||||
entities = context.intersects(context.map().extent());
|
||||
|
||||
for (var i in entities) {
|
||||
if (entities[i].user) users[entities[i].user] = true;
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
<script src='../js/id/core/node.js'></script>
|
||||
<script src='../js/id/core/relation.js'></script>
|
||||
<script src='../js/id/core/way.js'></script>
|
||||
<script src='../js/id/core/tree.js'></script>
|
||||
|
||||
<script src='../js/id/connection.js'></script>
|
||||
|
||||
@@ -186,6 +187,7 @@
|
||||
<script src="spec/core/relation.js"></script>
|
||||
<script src="spec/core/history.js"></script>
|
||||
<script src="spec/core/difference.js"></script>
|
||||
<script src="spec/core/tree.js"></script>
|
||||
|
||||
<script src="spec/renderer/background.js"></script>
|
||||
<script src="spec/renderer/map.js"></script>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
describe("iD.Tree", function() {
|
||||
var tree;
|
||||
|
||||
beforeEach(function() {
|
||||
tree = iD.Tree(iD.Graph());
|
||||
});
|
||||
|
||||
describe("#rebase", function() {
|
||||
it("adds entities to the tree", function() {
|
||||
var node = iD.Node({ id: 'n', loc: [1, 1]});
|
||||
tree.graph().rebase({ 'n': node });
|
||||
tree.rebase(['n']);
|
||||
expect(tree.intersects(iD.geo.Extent([0, 0], [2, 2]), tree.graph())).to.eql([node]);
|
||||
});
|
||||
|
||||
it("does not insert if entity has a modified version", function() {
|
||||
var node = iD.Node({ id: 'n', loc: [1, 1]}),
|
||||
node_ = node.update({ loc: [10, 10]}),
|
||||
g = tree.graph().replace(node_);
|
||||
expect(tree.intersects(iD.geo.Extent([9, 9], [11, 11]), g)).to.eql([node_]);
|
||||
tree.graph().rebase({ 'n': node });
|
||||
tree.rebase(['n']);
|
||||
expect(tree.intersects(iD.geo.Extent([0, 0], [2, 2]), g)).to.eql([]);
|
||||
expect(tree.intersects(iD.geo.Extent([0, 0], [11, 11]), g)).to.eql([node_]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#intersects", function() {
|
||||
it("excludes entities with missing children, adds them when all are present", function() {
|
||||
var way = iD.Way({id: 'w1', nodes: ['n']});
|
||||
var g = tree.graph().replace(way);
|
||||
expect(tree.intersects(iD.geo.Extent([0, 0], [1, 1]), g)).to.eql([]);
|
||||
var node = iD.Node({id: 'n', loc: [0.5, 0.5]});
|
||||
g = tree.graph().replace(node);
|
||||
expect(tree.intersects(iD.geo.Extent([0, 0], [1, 1]), g)).to.eql([way, node]);
|
||||
});
|
||||
|
||||
it("includes entities that used to have missing children, after rebase added them", function() {
|
||||
var base = tree.graph();
|
||||
var way = iD.Way({id: 'w1', nodes: ['n']});
|
||||
var g = base.replace(way);
|
||||
expect(tree.intersects(iD.geo.Extent([0, 0], [1, 1]), g)).to.eql([]);
|
||||
var node = iD.Node({id: 'n', loc: [0.5, 0.5]});
|
||||
base.rebase({ 'n': node });
|
||||
tree.rebase(['n']);
|
||||
expect(tree.intersects(iD.geo.Extent([0, 0], [1, 1]), g)).to.eql([way, node]);
|
||||
});
|
||||
|
||||
it("includes entities within extent, excludes those without", function() {
|
||||
var n1 = iD.Node({ id: 'n1', loc: [1, 1]});
|
||||
var n2 = iD.Node({ id: 'n2', loc: [3, 3]});
|
||||
var g = tree.graph().replace(n1).replace(n2);
|
||||
expect(tree.intersects(iD.geo.Extent([0, 0], [1.1, 1.1]), g)).to.eql([n1]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user