Show ways in restriction editor as if they were split

This commit is contained in:
John Firebaugh
2014-05-15 16:46:38 -07:00
parent 3b26e8d511
commit 26422d9c9a
10 changed files with 406 additions and 428 deletions
+1 -1
View File
@@ -47,9 +47,9 @@
<script src="js/id/geo.js"></script>
<script src="js/id/geo/extent.js"></script>
<script src="js/id/geo/intersection.js"></script>
<script src="js/id/geo/multipolygon.js"></script>
<script src="js/id/geo/raw_mercator.js"></script>
<script src="js/id/geo/turn.js"></script>
<script src='js/id/renderer/background.js'></script>
<script src='js/id/renderer/background_source.js'></script>
+114
View File
@@ -0,0 +1,114 @@
iD.geo.Turn = function(turn) {
turn = _.clone(turn);
turn.key = function() {
var components = [turn.from, turn.to, turn.via, turn.toward];
if (turn.restriction)
components.push(turn.restriction);
return components.map(iD.Entity.key).join('-');
};
turn.angle = function(projection) {
var v = projection(turn.via.loc),
t = projection(turn.toward.loc);
return Math.atan2(t[1] - v[1], t[0] - v[0]);
};
return turn;
};
iD.geo.Intersection = function(graph, vertexId) {
var vertex = graph.entity(vertexId),
highways = [];
// Pre-split ways that would need to be split in
// order to add a restriction. The real split will
// happen when the restriction is added.
graph.parentWays(vertex).forEach(function(way) {
if (!way.tags.highway || way.isArea() || way.isDegenerate())
return;
if (way.affix(vertexId)) {
highways.push(way);
} else {
var idx = _.indexOf(way.nodes, vertex.id, 1),
wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, idx + 1)}),
wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(idx)});
graph = graph.replace(wayA);
graph = graph.replace(wayB);
highways.push(wayA);
highways.push(wayB);
}
});
var intersection = {
highways: highways,
graph: graph
};
intersection.turns = function(wayId) {
if (!wayId)
return [];
var way = graph.entity(wayId);
if (way.first() === vertex.id && way.tags.oneway === 'yes')
return [];
if (way.last() === vertex.id && way.tags.oneway === '-1')
return [];
function withRestriction(turn) {
graph.parentRelations(turn.from).forEach(function(relation) {
if (relation.tags.type !== 'restriction')
return;
var f = relation.memberByRole('from'),
t = relation.memberByRole('to'),
v = relation.memberByRole('via');
if (f && f.id === turn.from.id &&
t && t.id === turn.to.id &&
v && v.id === turn.via.id) {
turn.restriction = relation;
}
});
return iD.geo.Turn(turn);
}
var turns = [];
highways.forEach(function(parent) {
if (parent === way)
return;
var index = parent.nodes.indexOf(vertex.id);
// backward
if (parent.first() !== vertex.id && parent.tags.oneway !== 'yes') {
turns.push(withRestriction({
from: way,
to: parent,
via: vertex,
toward: graph.entity(parent.nodes[index - 1])
}));
}
// forward
if (parent.last() !== vertex.id && parent.tags.oneway !== '-1') {
turns.push(withRestriction({
from: way,
to: parent,
via: vertex,
toward: graph.entity(parent.nodes[index + 1])
}));
}
});
return turns;
};
return intersection;
};
-82
View File
@@ -1,82 +0,0 @@
iD.geo.Turn = function(turn) {
turn = _.clone(turn);
turn.key = function() {
var components = [turn.from, turn.to, turn.via, turn.toward];
if (turn.restriction)
components.push(turn.restriction);
return components.map(iD.Entity.key).join('-');
};
turn.angle = function(projection) {
var v = projection(turn.via.loc),
t = projection(turn.toward.loc);
return Math.atan2(t[1] - v[1], t[0] - v[0]);
};
return turn;
};
iD.geo.turns = function(graph, entityID) {
var way = graph.entity(entityID);
if (way.type !== 'way' || !way.tags.highway || way.isArea())
return [];
function withRestriction(turn) {
graph.parentRelations(turn.from).forEach(function(relation) {
if (relation.tags.type !== 'restriction')
return;
var f = relation.memberByRole('from'),
t = relation.memberByRole('to'),
v = relation.memberByRole('via');
if (f && f.id === turn.from.id &&
t && t.id === turn.to.id &&
v && v.id === turn.via.id) {
turn.restriction = relation;
}
});
return iD.geo.Turn(turn);
}
var turns = [];
[way.first(), way.last()].forEach(function(nodeID) {
var node = graph.entity(nodeID);
graph.parentWays(node).forEach(function(parent) {
if (parent === way || parent.isDegenerate() || !parent.tags.highway)
return;
if (way.first() === node.id && way.tags.oneway === 'yes')
return;
if (way.last() === node.id && way.tags.oneway === '-1')
return;
var index = parent.nodes.indexOf(node.id);
// backward
if (parent.first() !== node.id && parent.tags.oneway !== 'yes') {
turns.push(withRestriction({
from: way,
to: parent,
via: node,
toward: graph.entity(parent.nodes[index - 1])
}));
}
// forward
if (parent.last() !== node.id && parent.tags.oneway !== '-1') {
turns.push(withRestriction({
from: way,
to: parent,
via: node,
toward: graph.entity(parent.nodes[index + 1])
}));
}
});
});
return turns;
};
+1 -3
View File
@@ -1,7 +1,5 @@
iD.svg.Turns = function(projection) {
return function(surface, graph, wayID) {
var turns = wayID ? iD.geo.turns(graph, wayID) : [];
return function(surface, graph, turns) {
var groups = surface.select('.layer-hit').selectAll('g.turn')
.data(turns, function(turn) { return turn.key(); });
+9 -21
View File
@@ -1,6 +1,6 @@
iD.ui.preset.restrictions = function(field, context) {
var event = d3.dispatch('change'),
entity,
vertex,
selectedID;
function restrictions(selection) {
@@ -23,7 +23,7 @@ iD.ui.preset.restrictions = function(field, context) {
var projection = iD.geo.RawMercator()
.scale(256 * Math.pow(2, z) / (2 * Math.PI));
var s = projection(entity ? entity.loc : [0, 0]);
var s = projection(vertex.loc);
projection
.translate([c[0] - s[0], c[1] - s[1]])
@@ -32,28 +32,16 @@ iD.ui.preset.restrictions = function(field, context) {
var surface = wrap.selectAll('svg'),
filter = function () { return true; },
extent = iD.geo.Extent(),
entities = [],
graph = context.graph(),
intersection = iD.geo.Intersection(context.graph(), vertex.id),
graph = intersection.graph,
lines = iD.svg.Lines(projection, context),
vertices = iD.svg.Vertices(projection, context),
turns = iD.svg.Turns(projection, context);
if (entity) {
entities = graph.parentWays(entity).filter(function (parent) {
return parent.type === 'way' && parent.tags.highway && !parent.isArea();
});
entities.push(entity);
}
if (!selectedID && entities.length) {
selectedID = entities[0].id;
}
surface
.call(vertices, graph, entities, filter, extent, z)
.call(lines, graph, entities, filter)
.call(turns, graph, selectedID);
.call(vertices, graph, [vertex], filter, extent, z)
.call(lines, graph, intersection.highways, filter)
.call(turns, graph, intersection.turns(selectedID));
surface.on('click.select', function() {
var datum = d3.event.target.__data__;
@@ -85,9 +73,9 @@ iD.ui.preset.restrictions = function(field, context) {
}
restrictions.entity = function(_) {
if (!entity || entity.id !== _.id) {
if (!vertex || vertex.id !== _.id) {
selectedID = null;
entity = _;
vertex = _;
}
};
+4 -5
View File
@@ -45,9 +45,9 @@
<script src="../js/id/geo.js"></script>
<script src="../js/id/geo/extent.js"></script>
<script src="../js/id/geo/intersection.js"></script>
<script src="../js/id/geo/multipolygon.js"></script>
<script src="../js/id/geo/raw_mercator.js"></script>
<script src="../js/id/geo/turn.js"></script>
<script src='../js/id/renderer/background.js'></script>
<script src='../js/id/renderer/background_source.js'></script>
@@ -57,14 +57,14 @@
<script src="../js/id/svg.js"></script>
<script src="../js/id/svg/areas.js"></script>
<script src="../js/id/svg/labels.js"></script>
<script src="../js/id/svg/lines.js"></script>
<script src="../js/id/svg/midpoints.js"></script>
<script src="../js/id/svg/points.js"></script>
<script src="../js/id/svg/surface.js"></script>
<script src="../js/id/svg/tag_classes.js"></script>
<script src="../js/id/svg/turns.js"></script>
<script src="../js/id/svg/vertices.js"></script>
<script src="../js/id/svg/labels.js"></script>
<script src="../js/id/svg/restrictions.js"></script>
<script src="../js/id/ui.js"></script>
<script src='../js/id/ui/attribution.js'></script>
@@ -234,8 +234,8 @@
<script src="spec/actions/split.js"></script>
<script src="spec/geo/extent.js"></script>
<script src="spec/geo/intersection.js"></script>
<script src="spec/geo/multipolygon.js"></script>
<script src="spec/geo/turn.js"></script>
<script src="spec/core/connection.js"></script>
<script src="spec/core/graph.js"></script>
@@ -258,7 +258,6 @@
<script src="spec/svg/points.js"></script>
<script src="spec/svg/vertices.js"></script>
<script src="spec/svg/tag_classes.js"></script>
<script src="spec/svg/turns.js"></script>
<script src="spec/ui/inspector.js"></script>
<script src="spec/ui/raw_tag_editor.js"></script>
+1 -2
View File
@@ -49,8 +49,8 @@
<script src="spec/actions/split.js"></script>
<script src="spec/geo/extent.js"></script>
<script src="spec/geo/intersection.js"></script>
<script src="spec/geo/multipolygon.js"></script>
<script src="spec/geo/turn.js"></script>
<script src="spec/core/connection.js"></script>
<script src="spec/core/graph.js"></script>
@@ -73,7 +73,6 @@
<script src="spec/svg/points.js"></script>
<script src="spec/svg/vertices.js"></script>
<script src="spec/svg/tag_classes.js"></script>
<script src="spec/svg/restrictions.js"></script>
<script src="spec/ui/inspector.js"></script>
<script src="spec/ui/raw_tag_editor.js"></script>
+276
View File
@@ -0,0 +1,276 @@
describe('iD.geo.Turn', function() {
describe('#angle', function() {
it("calculates the angle of via to toward", function() {
function projection(x) { return x; }
var turn = iD.geo.Turn({
via: iD.Node({id: 'v', loc: [1, 0]}),
toward: iD.Node({id: 'w', loc: [1, 1]})
});
expect(turn.angle(projection)).to.eql(Math.PI / 2);
});
});
});
describe("iD.geo.Intersection", function() {
describe('highways', function() {
it('excludes non-highways', function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*']}),
iD.Way({id: '-', nodes: ['*', 'w']})
]);
expect(iD.geo.Intersection(graph, '*').highways).to.eql([]);
});
it("excludes degenerate highways", function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['*'], tags: {highway: 'residential'}})
]);
expect(_.pluck(iD.geo.Intersection(graph, '*').highways, 'id')).to.eql(['=']);
});
it('includes line highways', function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['*', 'w']})
]);
expect(_.pluck(iD.geo.Intersection(graph, '*').highways, 'id')).to.eql(['=']);
});
it('excludes area highways', function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*', 'w'], tags: {highway: 'pedestrian', area: 'yes'}})
]);
expect(iD.geo.Intersection(graph, '*').highways).to.eql([]);
});
it('auto-splits highways at the intersection', function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*', 'w'], tags: {highway: 'residential'}})
]);
expect(_.pluck(iD.geo.Intersection(graph, '*').highways, 'id')).to.eql(['=-a', '=-b']);
});
});
describe('#turns', function() {
function ids(turns) {
return turns.map(function (turn) {
var result = {
from: turn.from.id,
to: turn.to.id,
via: turn.via.id,
toward: turn.toward.id
};
if (turn.restriction)
result.restriction = turn.restriction.id;
return result;
});
}
it("permits turns onto a way forward", function() {
// u====*--->w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['*', 'w'], tags: {highway: 'residential'}})
]),
turns = iD.geo.Intersection(graph, '*').turns('=');
expect(ids(turns)).to.eql([{
from: '=',
to: '-',
via: '*',
toward: 'w'
}]);
});
it("permits turns onto a way backward", function() {
// u====*<---w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['w', '*'], tags: {highway: 'residential'}})
]),
turns = iD.geo.Intersection(graph, '*').turns('=');
expect(ids(turns)).to.eql([{from: '=', to: '-', via: '*', toward: 'w'}]);
});
it("permits turns onto a way in both directions", function() {
// w
// |
// u===*
// |
// x
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Node({id: 'x'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['w', '*', 'x'], tags: {highway: 'residential'}})
]),
turns = iD.geo.Intersection(graph, '*').turns('=');
expect(ids(turns)).to.eql([
{from: '=', to: '--a', via: '*', toward: 'w'},
{from: '=', to: '--b', via: '*', toward: 'x'}
]);
});
it("permits turns from a oneway forward", function() {
// u===>v----w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential', oneway: 'yes'}}),
iD.Way({id: '-', nodes: ['*', 'w'], tags: {highway: 'residential'}})
]),
turns = iD.geo.Intersection(graph, '*').turns('=');
expect(ids(turns)).to.eql([{from: '=', to: '-', via: '*', toward: 'w'}]);
});
it("permits turns from a reverse oneway backward", function() {
// u<===*----w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['*', 'u'], tags: {highway: 'residential', oneway: '-1'}}),
iD.Way({id: '-', nodes: ['*', 'w'], tags: {highway: 'residential'}})
]),
turns = iD.geo.Intersection(graph, '*').turns('=');
expect(ids(turns)).to.eql([{from: '=', to: '-', via: '*', toward: 'w'}]);
});
it("omits turns from a oneway backward", function() {
// u<===*----w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['*', 'u'], tags: {highway: 'residential', oneway: 'yes'}}),
iD.Way({id: '-', nodes: ['*', 'w'], tags: {highway: 'residential'}})
]);
expect(iD.geo.Intersection(graph, '*').turns('=')).to.eql([]);
});
it("omits turns from a reverse oneway forward", function() {
// u===>*----w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential', oneway: '-1'}}),
iD.Way({id: '-', nodes: ['*', 'w'], tags: {highway: 'residential'}})
]);
expect(iD.geo.Intersection(graph, '*').turns('=')).to.eql([]);
});
it("permits turns onto a oneway forward", function() {
// u====*--->w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['*', 'w'], tags: {highway: 'residential', oneway: 'yes'}})
]),
turns = iD.geo.Intersection(graph, '*').turns('=');
expect(ids(turns)).to.eql([{from: '=', to: '-', via: '*', toward: 'w'}]);
});
it("permits turns onto a reverse oneway backward", function() {
// u====*<---w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['w', '*'], tags: {highway: 'residential', oneway: '-1'}})
]),
turns = iD.geo.Intersection(graph, '*').turns('=');
expect(ids(turns)).to.eql([{from: '=', to: '-', via: '*', toward: 'w'}]);
});
it("omits turns onto a oneway backward", function() {
// u====*<---w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['w', '*'], tags: {highway: 'residential', oneway: 'yes'}})
]);
expect(iD.geo.Intersection(graph, '*').turns('=')).to.eql([]);
});
it("omits turns onto a reverse oneway forward", function() {
// u====*--->w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['*', 'w'], tags: {highway: 'residential', oneway: '-1'}})
]);
expect(iD.geo.Intersection(graph, '*').turns('=')).to.eql([]);
});
it("restricts turns with a restriction relation", function() {
// u====*--->w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: '*'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', '*'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['*', 'w'], tags: {highway: 'residential'}}),
iD.Relation({id: 'r', tags: {type: 'restriction'}, members: [
{id: '=', role: 'from', type: 'way'},
{id: '-', role: 'to', type: 'way'},
{id: '*', role: 'via', type: 'node'}
]})
]),
turns = iD.geo.Intersection(graph, '*').turns('=');
expect(ids(turns)).to.eql([{
from: '=',
to: '-',
via: '*',
toward: 'w',
restriction: 'r'
}]);
});
});
// 'no' vs 'only'
// U-turns
// Self-intersections
});
-312
View File
@@ -1,312 +0,0 @@
describe('iD.geo.Turn', function() {
describe('#angle', function() {
it("calculates the angle of via to toward", function() {
function projection(x) { return x; }
var turn = iD.geo.Turn({
via: iD.Node({id: 'v', loc: [1, 0]}),
toward: iD.Node({id: 'w', loc: [1, 1]})
});
expect(turn.angle(projection)).to.eql(Math.PI / 2);
});
});
});
describe("iD.geo.turns", function() {
function properties(turns) {
return turns.map(function (turn) { return _.pick(turn, 'from', 'to', 'via', 'toward', 'restriction') });
}
it("returns an empty array for non-ways", function() {
var graph = iD.Graph([
iD.Node({id: 'n'})
]);
expect(iD.geo.turns(graph, 'n')).to.eql([]);
});
it("returns an empty array for non-lines", function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential', area: 'yes'}}),
iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}})
]);
expect(iD.geo.turns(graph, '=')).to.eql([]);
});
it("returns an empty array for an unconnected way", function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Way({id: '=', nodes: ['u', 'v']})
]);
expect(iD.geo.turns(graph, '=')).to.eql([]);
});
it("omits turns onto degenerate ways", function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['v'], tags: {highway: 'residential'}})
]);
expect(iD.geo.turns(graph, '=')).to.eql([]);
});
it("omits turns from non-highways", function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v']}),
iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}})
]);
expect(iD.geo.turns(graph, '=')).to.eql([]);
});
it("omits turns onto non-highways", function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['v', 'w']})
]);
expect(iD.geo.turns(graph, '=')).to.eql([]);
});
it("omits turns onto non-lines", function() {
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Node({id: 'x'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['v', 'w', 'x', 'v'], tags: {highway: 'residential', area: 'yes'}})
]);
expect(iD.geo.turns(graph, '=')).to.eql([]);
});
it("permits turns onto a way forward", function() {
// u====v--->w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}})
]),
turns = iD.geo.turns(graph, '=');
expect(properties(turns)).to.eql([{
from: graph.entity('='),
to: graph.entity('-'),
via: graph.entity('v'),
toward: graph.entity('w')
}]);
});
it("permits turns onto a way backward", function() {
// u====v<---w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['w', 'v'], tags: {highway: 'residential'}})
]),
turns = iD.geo.turns(graph, '=');
expect(properties(turns)).to.eql([{
from: graph.entity('='),
to: graph.entity('-'),
via: graph.entity('v'),
toward: graph.entity('w')
}]);
});
it("permits turns onto a way in both directions", function() {
// w
// |
// u===v
// |
// x
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Node({id: 'x'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['w', 'v', 'x'], tags: {highway: 'residential'}})
]),
turns = iD.geo.turns(graph, '=');
expect(properties(turns)).to.eql([{
from: graph.entity('='),
to: graph.entity('-'),
via: graph.entity('v'),
toward: graph.entity('w')
}, {
from: graph.entity('='),
to: graph.entity('-'),
via: graph.entity('v'),
toward: graph.entity('x')
}]);
});
it("permits turns from a oneway forward", function() {
// u===>v----w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential', oneway: 'yes'}}),
iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}})
]),
turns = iD.geo.turns(graph, '=');
expect(properties(turns)).to.eql([{
from: graph.entity('='),
to: graph.entity('-'),
via: graph.entity('v'),
toward: graph.entity('w')
}]);
});
it("permits turns from a reverse oneway backward", function() {
// u<===v----w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['v', 'u'], tags: {highway: 'residential', oneway: '-1'}}),
iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}})
]),
turns = iD.geo.turns(graph, '=');
expect(properties(turns)).to.eql([{
from: graph.entity('='),
to: graph.entity('-'),
via: graph.entity('v'),
toward: graph.entity('w')
}]);
});
it("omits turns from a oneway backward", function() {
// u<===v----w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['v', 'u'], tags: {highway: 'residential', oneway: 'yes'}}),
iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}})
]);
expect(iD.geo.turns(graph, '=')).to.eql([]);
});
it("omits turns from a reverse oneway forward", function() {
// u===>v----w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential', oneway: '-1'}}),
iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}})
]);
expect(iD.geo.turns(graph, '=')).to.eql([]);
});
it("permits turns onto a oneway forward", function() {
// u====v--->w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential', oneway: 'yes'}})
]),
turns = iD.geo.turns(graph, '=');
expect(properties(turns)).to.eql([{
from: graph.entity('='),
to: graph.entity('-'),
via: graph.entity('v'),
toward: graph.entity('w')
}]);
});
it("permits turns onto a reverse oneway backward", function() {
// u====v<---w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['w', 'v'], tags: {highway: 'residential', oneway: '-1'}})
]),
turns = iD.geo.turns(graph, '=');
expect(properties(turns)).to.eql([{
from: graph.entity('='),
to: graph.entity('-'),
via: graph.entity('v'),
toward: graph.entity('w')
}]);
});
it("omits turns onto a oneway backward", function() {
// u====v<---w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['w', 'v'], tags: {highway: 'residential', oneway: 'yes'}})
]);
expect(iD.geo.turns(graph, '=')).to.eql([]);
});
it("omits turns onto a reverse oneway forward", function() {
// u====v--->w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential', oneway: '-1'}})
]);
expect(iD.geo.turns(graph, '=')).to.eql([]);
});
it("restricts turns with a restriction relation", function() {
// u====v--->w
var graph = iD.Graph([
iD.Node({id: 'u'}),
iD.Node({id: 'v'}),
iD.Node({id: 'w'}),
iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}}),
iD.Relation({id: 'r', tags: {type: 'restriction'}, members: [
{id: '=', role: 'from', type: 'way'},
{id: '-', role: 'to', type: 'way'},
{id: 'v', role: 'via', type: 'node'}
]})
]),
turns = iD.geo.turns(graph, '=');
expect(properties(turns)).to.eql([{
from: graph.entity('='),
to: graph.entity('-'),
via: graph.entity('v'),
toward: graph.entity('w'),
restriction: graph.entity('r')
}]);
});
// 'no' vs 'only'
// U-turns
// Self-intersections
// Split point
});
-2
View File
@@ -1,2 +0,0 @@
describe("iD.svg.Restrictions", function() {
});