mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 01:02:58 +00:00
Add more turn logic
This commit is contained in:
@@ -43,6 +43,7 @@
|
||||
<script src="js/id/geo.js"></script>
|
||||
<script src="js/id/geo/extent.js"></script>
|
||||
<script src="js/id/geo/multipolygon.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>
|
||||
|
||||
62
js/id/geo/turn.js
Normal file
62
js/id/geo/turn.js
Normal file
@@ -0,0 +1,62 @@
|
||||
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 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;
|
||||
};
|
||||
@@ -44,6 +44,7 @@
|
||||
<script src="../js/id/geo.js"></script>
|
||||
<script src="../js/id/geo/extent.js"></script>
|
||||
<script src="../js/id/geo/multipolygon.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>
|
||||
@@ -221,6 +222,7 @@
|
||||
|
||||
<script src="spec/geo/extent.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>
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
|
||||
<script src="spec/geo/extent.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>
|
||||
|
||||
276
test/spec/geo/turn.js
Normal file
276
test/spec/geo/turn.js
Normal file
@@ -0,0 +1,276 @@
|
||||
describe("iD.geo.turns", function() {
|
||||
it("returns an empty array for non-ways", function() {
|
||||
var graph = iD.Graph({
|
||||
'n': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': iD.Node({id: 'w'}),
|
||||
'x': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': iD.Node({id: 'w'}),
|
||||
'=': iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
|
||||
'-': iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}})
|
||||
});
|
||||
expect(iD.geo.turns(graph, '=')).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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': iD.Node({id: 'w'}),
|
||||
'=': iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
|
||||
'-': iD.Way({id: '-', nodes: ['w', 'v'], tags: {highway: 'residential'}})
|
||||
});
|
||||
expect(iD.geo.turns(graph, '=')).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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': iD.Node({id: 'w'}),
|
||||
'x': iD.Node({id: 'x'}),
|
||||
'=': iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
|
||||
'-': iD.Way({id: '-', nodes: ['w', 'v', 'x'], tags: {highway: 'residential'}})
|
||||
});
|
||||
expect(iD.geo.turns(graph, '=')).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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': iD.Node({id: 'w'}),
|
||||
'=': iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential', oneway: 'yes'}}),
|
||||
'-': iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}})
|
||||
});
|
||||
expect(iD.geo.turns(graph, '=')).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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': iD.Node({id: 'w'}),
|
||||
'=': iD.Way({id: '=', nodes: ['v', 'u'], tags: {highway: 'residential', oneway: '-1'}}),
|
||||
'-': iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}})
|
||||
});
|
||||
expect(iD.geo.turns(graph, '=')).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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': iD.Node({id: 'w'}),
|
||||
'=': iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
|
||||
'-': iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential', oneway: 'yes'}})
|
||||
});
|
||||
expect(iD.geo.turns(graph, '=')).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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': iD.Node({id: 'w'}),
|
||||
'=': iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
|
||||
'-': iD.Way({id: '-', nodes: ['w', 'v'], tags: {highway: 'residential', oneway: '-1'}})
|
||||
});
|
||||
expect(iD.geo.turns(graph, '=')).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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': 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({
|
||||
'u': iD.Node({id: 'u'}),
|
||||
'v': iD.Node({id: 'v'}),
|
||||
'w': iD.Node({id: 'w'}),
|
||||
'=': iD.Way({id: '=', nodes: ['u', 'v'], tags: {highway: 'residential'}}),
|
||||
'-': iD.Way({id: '-', nodes: ['v', 'w'], tags: {highway: 'residential'}}),
|
||||
'r': iD.Relation({id: 'r', tags: {type: 'restriction'}, members: [
|
||||
{id: '=', role: 'from', type: 'way'},
|
||||
{id: '-', role: 'to', type: 'way'},
|
||||
{id: 'v', role: 'via', type: 'node'}
|
||||
]})
|
||||
});
|
||||
expect(iD.geo.turns(graph, '=')).to.eql([{
|
||||
from: graph.entity('='),
|
||||
to: graph.entity('-'),
|
||||
via: graph.entity('v'),
|
||||
toward: graph.entity('w'),
|
||||
restriction: graph.entity('r')
|
||||
}]);
|
||||
});
|
||||
|
||||
// U-turns
|
||||
// Self-intersections
|
||||
// Split point
|
||||
});
|
||||
Reference in New Issue
Block a user