From 6b0819312523790514d7878468c1228d3a3ff64d Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 6 Dec 2012 14:11:45 -0500 Subject: [PATCH] Introduce Entity transients; fix #187 --- js/id/graph/entity.js | 43 +++++++++++++++++++++++++++++++++++++-- js/id/graph/graph.js | 37 ++------------------------------- test/spec/graph/entity.js | 38 +++++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 38 deletions(-) diff --git a/js/id/graph/entity.js b/js/id/graph/entity.js index b0019f18d..b3f698704 100644 --- a/js/id/graph/entity.js +++ b/js/id/graph/entity.js @@ -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" && diff --git a/js/id/graph/graph.js b/js/id/graph/graph.js index a97356ff1..a830214d4 100644 --- a/js/id/graph/graph.js +++ b/js/id/graph/graph.js @@ -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; diff --git a/test/spec/graph/entity.js b/test/spec/graph/entity.js index 71954b73a..0273ee4c6 100644 --- a/test/spec/graph/entity.js +++ b/test/spec/graph/entity.js @@ -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 () {