Better inferRestriction for no_u_turn

* where from.node === to.node
* where from.way and to.way are oneways joined at a narrow angle
This commit is contained in:
Bryan Housel
2014-09-02 16:43:31 -04:00
parent cf715a5156
commit 43777d5259
4 changed files with 74 additions and 23 deletions

View File

@@ -11,14 +11,8 @@
// `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
// (The action does not check that these entities form a valid intersection.)
//
// If `restriction` is not provided, it is automatically determined by the
// angle of the turn:
//
// 0-5 degrees: no_u_turn
// 5-158 degrees: no_right_turn
// 158-202 degrees: no_straight_on
// 202-355 degrees: no_left_turn
// 355-360 degrees: no_u_turn
// If `restriction` is not provided, it is automatically determined by
// iD.geo.inferRestriction.
//
// If necessary, the `from` and `to` ways are split. In these cases, `from.node`
// and `to.node` are used to determine which portion of the split ways become
@@ -74,9 +68,10 @@ iD.actions.RestrictTurn = function(turn, projection, restrictionId) {
type: 'restriction',
restriction: turn.restriction ||
iD.geo.inferRestriction(
graph.entity(turn.from.node),
via,
graph.entity(turn.to.node),
graph,
turn.from,
turn.via,
turn.to,
projection)
},
members: [

View File

@@ -118,23 +118,33 @@ iD.geo.Intersection = function(graph, vertexId) {
return intersection;
};
iD.geo.inferRestriction = function(from, via, to, projection) {
var angle = iD.geo.angle(via, from, projection) -
iD.geo.angle(via, to, projection);
iD.geo.inferRestriction = function(graph, from, via, to, projection) {
var fromWay = graph.entity(from.way),
fromNode = graph.entity(from.node),
toWay = graph.entity(to.way),
toNode = graph.entity(to.node),
viaNode = graph.entity(via.node),
fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
(fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
(toWay.tags.oneway === '-1' && toWay.last() === via.node),
angle = iD.geo.angle(viaNode, fromNode, projection) -
iD.geo.angle(viaNode, toNode, projection);
angle = angle * 180 / Math.PI;
while (angle < 0)
angle += 360;
if (angle < 5)
if (fromNode === toNode)
return 'no_u_turn';
if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
return 'no_u_turn';
if (angle < 158)
return 'no_right_turn';
if (angle < 202)
return 'no_straight_on';
if (angle < 355)
if (angle > 202)
return 'no_left_turn';
return 'no_u_turn';
return 'no_straight_on';
};

View File

@@ -99,9 +99,10 @@ iD.ui.preset.restrictions = function(field, context) {
} else {
preset = presets.item('type/restriction/' +
iD.geo.inferRestriction(
graph.entity(datum.from.node),
graph.entity(datum.via.node),
graph.entity(datum.to.node),
graph,
datum.from,
datum.via,
datum.to,
projection));
}

View File

@@ -250,7 +250,7 @@ describe("iD.actions.RestrictTurn", function() {
expect(_.pick(r.memberByRole('to'), 'id', 'type')).to.eql({id: '==', type: 'way'});
});
it('guesses the restriction type based on the turn angle', function() {
it('infers the restriction type based on the turn angle', function() {
// u====*~~~~w
// |
// x
@@ -306,4 +306,49 @@ describe("iD.actions.RestrictTurn", function() {
}, projection, 'r')(graph);
expect(u.entity('r').tags.restriction).to.equal('no_u_turn');
});
it('infers no_u_turn from acute angle made by forward oneways', function() {
// *
// / \
// w2/ \w1
// / \
// u x
var graph = iD.Graph([
iD.Node({id: 'u', loc: [-1, -20]}),
iD.Node({id: '*', loc: [ 0, 0]}),
iD.Node({id: 'x', loc: [ 1, -20]}),
iD.Way({id: 'w1', nodes: ['x', '*'], tags: {oneway: 'yes'}}),
iD.Way({id: 'w2', nodes: ['*', 'u'], tags: {oneway: 'yes'}})
]);
var r = iD.actions.RestrictTurn({
from: {node: 'x', way: 'w1'},
via: {node: '*'},
to: {node: 'u', way: 'w2'}
}, projection, 'r')(graph);
expect(r.entity('r').tags.restriction).to.equal('no_u_turn');
});
it('infers no_u_turn from acute angle made by reverse oneways', function() {
// *
// / \
// w2/ \w1
// / \
// u x
var graph = iD.Graph([
iD.Node({id: 'u', loc: [-1, -20]}),
iD.Node({id: '*', loc: [ 0, 0]}),
iD.Node({id: 'x', loc: [ 1, -20]}),
iD.Way({id: 'w1', nodes: ['*', 'x'], tags: {oneway: '-1'}}),
iD.Way({id: 'w2', nodes: ['u', '*'], tags: {oneway: '-1'}})
]);
var r = iD.actions.RestrictTurn({
from: {node: 'x', way: 'w1'},
via: {node: '*'},
to: {node: 'u', way: 'w2'}
}, projection, 'r')(graph);
expect(r.entity('r').tags.restriction).to.equal('no_u_turn');
});
});