Introduce Entity transients; fix #187

This commit is contained in:
John Firebaugh
2012-12-06 14:11:45 -05:00
parent b8a06aa215
commit 6b08193125
3 changed files with 80 additions and 38 deletions
+41 -2
View File
@@ -1,13 +1,23 @@
iD.Entity = function(a, b, c) {
if (!(this instanceof iD.Entity)) return new iD.Entity(a, b, c);
_.extend(this, {tags: {}}, a, b, c);
this.tags = {};
this.transients = {};
var sources = [a, b, c], source;
for (var i = 0; i < sources.length; ++i) {
source = sources[i];
for (var prop in source) {
if (prop !== 'transients' && Object.prototype.hasOwnProperty.call(source, prop)) {
this[prop] = source[prop];
}
}
}
if (!this.id) {
this.id = iD.util.id(this.type);
this._updated = true;
}
delete this._extent;
if (iD.debug) {
Object.freeze(this);
@@ -31,6 +41,35 @@ iD.Entity.prototype = {
return this._updated && +this.id.slice(1) > 0;
},
intersects: function(extent, resolver) {
if (this.type === 'node') {
return this.loc[0] > extent[0][0] &&
this.loc[0] < extent[1][0] &&
this.loc[1] < extent[0][1] &&
this.loc[1] > extent[1][1];
} else if (this.type === 'way') {
var _extent = this.transients.extent;
if (!_extent) {
_extent = this.transients.extent = [[-Infinity, Infinity], [Infinity, -Infinity]];
for (var i = 0, l = this.nodes.length; i < l; i++) {
var node = resolver.entity(this.nodes[i]);
if (node.loc[0] > _extent[0][0]) _extent[0][0] = node.loc[0];
if (node.loc[0] < _extent[1][0]) _extent[1][0] = node.loc[0];
if (node.loc[1] < _extent[0][1]) _extent[0][1] = node.loc[1];
if (node.loc[1] > _extent[1][1]) _extent[1][1] = node.loc[1];
}
}
return _extent[0][0] > extent[0][0] &&
_extent[1][0] < extent[1][0] &&
_extent[0][1] < extent[0][1] &&
_extent[1][1] > extent[1][1];
} else {
return false;
}
},
hasInterestingTags: function() {
return _.keys(this.tags).some(function (key) {
return key != "attribution" &&
+2 -35
View File
@@ -55,46 +55,13 @@ iD.Graph.prototype = {
return iD.Graph(entities, annotation);
},
nodeIntersect: function(entity, extent) {
return entity.loc[0] > extent[0][0] &&
entity.loc[0] < extent[1][0] &&
entity.loc[1] < extent[0][1] &&
entity.loc[1] > extent[1][1];
},
wayIntersect: function(entity, extent) {
return entity._extent[0][0] > extent[0][0] &&
entity._extent[1][0] < extent[1][0] &&
entity._extent[0][1] < extent[0][1] &&
entity._extent[1][1] > extent[1][1];
},
indexWay: function(way) {
if (way.type === 'way' && !way._extent) {
// top left, bottom right
var extent = [[-Infinity, Infinity], [Infinity, -Infinity]];
var w = way;
for (var j = 0, l = w.nodes.length; j < l; j++) {
if (w.nodes[j].loc[0] > extent[0][0]) extent[0][0] = w.nodes[j].loc[0];
if (w.nodes[j].loc[0] < extent[1][0]) extent[1][0] = w.nodes[j].loc[0];
if (w.nodes[j].loc[1] < extent[0][1]) extent[0][1] = w.nodes[j].loc[1];
if (w.nodes[j].loc[1] > extent[1][1]) extent[1][1] = w.nodes[j].loc[1];
}
way._extent = extent;
}
return true;
},
// 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.type === 'node' && this.nodeIntersect(entity, extent)) {
items.push(entity);
} else if (entity.type === 'way') {
var w = this.fetch(entity.id);
if (this.indexWay(w) && this.wayIntersect(w, extent)) items.push(w);
if (entity.intersects(extent, this)) {
items.push(this.fetch(entity.id));
}
}
return items;
+37 -1
View File
@@ -23,7 +23,17 @@ describe('Entity', function () {
var attrs = {tags: {foo: 'bar'}},
e = iD.Entity().update(attrs);
expect(attrs).to.eql({tags: {foo: 'bar'}});
})
});
it("doesn't copy transients", function () {
var entity = iD.Entity();
entity.transients['foo'] = 'bar';
expect(entity.update({}).transients).not.to.have.property('foo');
});
it("doesn't copy prototype properties", function () {
expect(iD.Entity().update({})).not.to.have.ownProperty('update');
});
});
describe("#created", function () {
@@ -102,6 +112,16 @@ describe('Node', function () {
it("sets tags as specified", function () {
expect(iD.Node({tags: {foo: 'bar'}}).tags).to.eql({foo: 'bar'});
});
describe("#intersects", function () {
it("returns true for a node within the given extent", function () {
expect(iD.Node({loc: [0, 0]}).intersects([[-180, 90], [180, -90]])).to.equal(true);
});
it("returns false for a node outside the given extend", function () {
expect(iD.Node({loc: [0, 0]}).intersects([[100, 90], [180, -90]])).to.equal(false);
});
});
});
describe('Way', function () {
@@ -133,6 +153,22 @@ describe('Way', function () {
it("sets tags as specified", function () {
expect(iD.Way({tags: {foo: 'bar'}}).tags).to.eql({foo: 'bar'});
});
describe("#intersects", function () {
it("returns true for a way with a node within the given extent", function () {
var node = iD.Node({loc: [0, 0]}),
way = iD.Way({nodes: [node.id]}),
graph = iD.Graph([node, way]);
expect(way.intersects([[-180, 90], [180, -90]], graph)).to.equal(true);
});
it("returns false for way with no nodes within the given extent", function () {
var node = iD.Node({loc: [0, 0]}),
way = iD.Way({nodes: [node.id]}),
graph = iD.Graph([node, way]);
expect(way.intersects([[100, 90], [180, -90]], graph)).to.equal(false);
});
});
});
describe('Relation', function () {