mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-15 21:48:20 +02:00
Show ways in restriction editor as if they were split
This commit is contained in:
+1
-1
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
@@ -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(); });
|
||||
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -1,2 +0,0 @@
|
||||
describe("iD.svg.Restrictions", function() {
|
||||
});
|
||||
Reference in New Issue
Block a user