From d2479623244393b6b83a2ac43780b2ede59f823a Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 1 May 2013 10:28:40 -0700 Subject: [PATCH] Handle incomplete relations in simpleMultipolygonOuterMember --- index.html | 1 + js/id/geo/multipolygon.js | 50 +++++++++++++++++++++++++++++++++++ js/id/svg/areas.js | 28 +------------------- js/id/svg/lines.js | 29 +------------------- test/index.html | 2 ++ test/index_packaged.html | 1 + test/spec/geo/multipolygon.js | 41 ++++++++++++++++++++++++++++ 7 files changed, 97 insertions(+), 55 deletions(-) create mode 100644 js/id/geo/multipolygon.js create mode 100644 test/spec/geo/multipolygon.js diff --git a/index.html b/index.html index 57ad9c354..3b4f714a3 100644 --- a/index.html +++ b/index.html @@ -41,6 +41,7 @@ + diff --git a/js/id/geo/multipolygon.js b/js/id/geo/multipolygon.js new file mode 100644 index 000000000..df43ae8f0 --- /dev/null +++ b/js/id/geo/multipolygon.js @@ -0,0 +1,50 @@ +// For fixing up rendering of multipolygons with tags on the outer member. +// https://github.com/systemed/iD/issues/613 +iD.geo.isSimpleMultipolygonOuterMember = function(entity, graph) { + if (entity.type !== 'way') + return false; + + var parents = graph.parentRelations(entity); + if (parents.length !== 1) + return false; + + var parent = parents[0]; + if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1) + return false; + + var members = parent.members, member; + for (var i = 0; i < members.length; i++) { + member = members[i]; + if (member.id === entity.id && member.role && member.role !== 'outer') + return false; // Not outer member + if (member.id !== entity.id && (!member.role || member.role === 'outer')) + return false; // Not a simple multipolygon + } + + return parent; +}; + +iD.geo.simpleMultipolygonOuterMember = function(entity, graph) { + if (entity.type !== 'way') + return false; + + var parents = graph.parentRelations(entity); + if (parents.length !== 1) + return false; + + var parent = parents[0]; + if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1) + return false; + + var members = parent.members, member, outerMember; + for (var i = 0; i < members.length; i++) { + member = members[i]; + if (!member.role || member.role === 'outer') { + if (outerMember) + return false; // Not a simple multipolygon + outerMember = member; + } + } + + return outerMember && graph.hasEntity(outerMember.id); +}; diff --git a/js/id/svg/areas.js b/js/id/svg/areas.js index 87a2c15c7..f989c7c1b 100644 --- a/js/id/svg/areas.js +++ b/js/id/svg/areas.js @@ -1,30 +1,4 @@ iD.svg.Areas = function(projection) { - // For fixing up rendering of multipolygons with tags on the outer member. - // https://github.com/systemed/iD/issues/613 - function isSimpleMultipolygonOuterMember(entity, graph) { - if (entity.type !== 'way') - return false; - - var parents = graph.parentRelations(entity); - if (parents.length !== 1) - return false; - - var parent = parents[0]; - if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1) - return false; - - var members = parent.members, member; - for (var i = 0; i < members.length; i++) { - member = members[i]; - if (member.id === entity.id && member.role && member.role !== 'outer') - return false; // Not outer member - if (member.id !== entity.id && (!member.role || member.role === 'outer')) - return false; // Not a simple multipolygon - } - - return parent; - } - // Patterns only work in Firefox when set directly on element var patterns = { wetland: 'wetland', @@ -62,7 +36,7 @@ iD.svg.Areas = function(projection) { var entity = entities[i]; if (entity.geometry(graph) !== 'area') continue; - if (multipolygon = isSimpleMultipolygonOuterMember(entity, graph)) { + if (multipolygon = iD.geo.isSimpleMultipolygonOuterMember(entity, graph)) { areas[multipolygon.id] = { entity: multipolygon.mergeTags(entity.tags), area: Math.abs(path.area(entity.asGeoJSON(graph, true))) diff --git a/js/id/svg/lines.js b/js/id/svg/lines.js index ee5328e2c..a81bff073 100644 --- a/js/id/svg/lines.js +++ b/js/id/svg/lines.js @@ -32,33 +32,6 @@ iD.svg.Lines = function(projection) { return as - bs; } - // For fixing up rendering of multipolygons with tags on the outer member. - // https://github.com/systemed/iD/issues/613 - function simpleMultipolygonOuterMember(entity, graph) { - if (entity.type !== 'way') - return false; - - var parents = graph.parentRelations(entity); - if (parents.length !== 1) - return false; - - var parent = parents[0]; - if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1) - return false; - - var members = parent.members, member, outer; - for (var i = 0; i < members.length; i++) { - member = members[i]; - if (!member.role || member.role === 'outer') { - if (outer) - return false; // Not a simple multipolygon - outer = graph.entity(member.id); - } - } - - return outer; - } - return function drawLines(surface, graph, entities, filter) { function drawPaths(group, lines, filter, klass, lineString) { lines = lines.filter(function(line) { @@ -95,7 +68,7 @@ iD.svg.Lines = function(projection) { for (var i = 0; i < entities.length; i++) { var entity = entities[i], - outer = simpleMultipolygonOuterMember(entity, graph); + outer = iD.geo.simpleMultipolygonOuterMember(entity, graph); if (outer) { lines.push(entity.mergeTags(outer.tags)); } else if (entity.geometry(graph) === 'line') { diff --git a/test/index.html b/test/index.html index fee7b71f4..8fa705b2c 100644 --- a/test/index.html +++ b/test/index.html @@ -42,6 +42,7 @@ + @@ -200,6 +201,7 @@ + diff --git a/test/index_packaged.html b/test/index_packaged.html index d83e6033d..2d7e7c55d 100644 --- a/test/index_packaged.html +++ b/test/index_packaged.html @@ -44,6 +44,7 @@ + diff --git a/test/spec/geo/multipolygon.js b/test/spec/geo/multipolygon.js new file mode 100644 index 000000000..19ac5559f --- /dev/null +++ b/test/spec/geo/multipolygon.js @@ -0,0 +1,41 @@ +describe("iD.geo.simpleMultipolygonOuterMember", function() { + it("returns the outer member of a simple multipolygon", function() { + var inner = iD.Way(), + outer = iD.Way(), + relation = iD.Relation({tags: {type: 'multipolygon'}, members: [ + {id: outer.id, role: 'outer'}, + {id: inner.id, role: 'inner'}] + }), + graph = iD.Graph([inner, outer, relation]); + + expect(iD.geo.simpleMultipolygonOuterMember(inner, graph)).to.equal(outer); + expect(iD.geo.simpleMultipolygonOuterMember(outer, graph)).to.equal(outer); + }); + + it("returns falsy for a complex multipolygon", function() { + var inner = iD.Way(), + outer1 = iD.Way(), + outer2 = iD.Way(), + relation = iD.Relation({tags: {type: 'multipolygon'}, members: [ + {id: outer1.id, role: 'outer'}, + {id: outer2.id, role: 'outer'}, + {id: inner.id, role: 'inner'}] + }), + graph = iD.Graph([inner, outer1, outer2, relation]); + + expect(iD.geo.simpleMultipolygonOuterMember(inner, graph)).not.to.be.ok; + expect(iD.geo.simpleMultipolygonOuterMember(outer1, graph)).not.to.be.ok; + expect(iD.geo.simpleMultipolygonOuterMember(outer2, graph)).not.to.be.ok; + }); + + it("handles incomplete relations", function() { + var way = iD.Way({id: 'w'}), + relation = iD.Relation({id: 'r', tags: {type: 'multipolygon'}, members: [ + {id: 'o', role: 'outer'}, + {id: 'w', role: 'inner'}] + }), + graph = iD.Graph([way, relation]); + + expect(iD.geo.simpleMultipolygonOuterMember(way, graph)).to.be.undefined; + }); +});