mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 17:23:02 +00:00
Merge pull request #4693 from openstreetmap/doubled_back_routes
Fixes for joining and splitting bugs
This commit is contained in:
@@ -1,32 +1,175 @@
|
||||
import { osmJoinWays } from '../osm';
|
||||
import _clone from 'lodash-es/clone';
|
||||
import _groupBy from 'lodash-es/groupBy';
|
||||
import _omit from 'lodash-es/omit';
|
||||
|
||||
import { osmJoinWays, osmWay } from '../osm';
|
||||
|
||||
|
||||
export function actionAddMember(relationId, member, memberIndex) {
|
||||
return function(graph) {
|
||||
export function actionAddMember(relationId, member, memberIndex, insertPair) {
|
||||
|
||||
return function action(graph) {
|
||||
var relation = graph.entity(relationId);
|
||||
|
||||
if (isNaN(memberIndex) && member.type === 'way') {
|
||||
var members = relation.indexedMembers();
|
||||
members.push(member);
|
||||
if ((isNaN(memberIndex) || insertPair) && member.type === 'way') {
|
||||
// Try to perform sensible inserts based on how the ways join together
|
||||
graph = addWayMember(relation, graph);
|
||||
} else {
|
||||
graph = graph.replace(relation.addMember(member, memberIndex));
|
||||
}
|
||||
|
||||
var joined = osmJoinWays(members, graph);
|
||||
for (var i = 0; i < joined.length; i++) {
|
||||
var segment = joined[i];
|
||||
for (var j = 0; j < segment.length && segment.length >= 2; j++) {
|
||||
if (segment[j] !== member)
|
||||
continue;
|
||||
return graph;
|
||||
};
|
||||
|
||||
if (j === 0) {
|
||||
memberIndex = segment[j + 1].index;
|
||||
} else if (j === segment.length - 1) {
|
||||
memberIndex = segment[j - 1].index + 1;
|
||||
|
||||
// Add a way member into the relation "wherever it makes sense".
|
||||
// In this situation we were not supplied a memberIndex.
|
||||
function addWayMember(relation, graph) {
|
||||
var groups, tempWay, item, i, j, k;
|
||||
|
||||
if (insertPair) {
|
||||
// We're adding a member that must stay paired with an existing member.
|
||||
// (This feature is used by `actionSplit`)
|
||||
//
|
||||
// This is tricky because the members may exist multiple times in the
|
||||
// member list, and with different A-B/B-A ordering and different roles.
|
||||
// (e.g. a bus route that loops out and back - #4589).
|
||||
//
|
||||
// Replace the existing member with a temporary way,
|
||||
// so that `osmJoinWays` can treat the pair like a single way.
|
||||
tempWay = osmWay({ id: 'wTemp', nodes: insertPair.nodes });
|
||||
graph = graph.replace(tempWay);
|
||||
var tempMember = { id: tempWay.id, type: 'way', role: member.role };
|
||||
var tempRelation = relation.replaceMember({id: insertPair.originalID}, tempMember, true);
|
||||
groups = _groupBy(tempRelation.members, function(m) { return m.type; });
|
||||
groups.way = groups.way || [];
|
||||
|
||||
} else {
|
||||
// Add the member anywhere, one time. Just push and let `osmJoinWays` decide where to put it.
|
||||
groups = _groupBy(relation.members, function(m) { return m.type; });
|
||||
groups.way = groups.way || [];
|
||||
groups.way.push(member);
|
||||
}
|
||||
|
||||
var members = withIndex(groups.way);
|
||||
var joined = osmJoinWays(members, graph);
|
||||
|
||||
// `joined` might not contain all of the way members,
|
||||
// But will contain only the completed (downloaded) members
|
||||
for (i = 0; i < joined.length; i++) {
|
||||
var segment = joined[i];
|
||||
var nodes = segment.nodes.slice();
|
||||
var startIndex = segment[0].index;
|
||||
|
||||
// j = array index in `members` where this segment starts
|
||||
for (j = 0; j < members.length; j++) {
|
||||
if (members[j].index === startIndex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// k = each member in segment
|
||||
for (k = 0; k < segment.length; k++) {
|
||||
item = segment[k];
|
||||
var way = graph.entity(item.id);
|
||||
|
||||
// If this is a paired item, generate members in correct order and role
|
||||
if (tempWay && item.id === tempWay.id) {
|
||||
if (nodes[0].id === insertPair.nodes[0]) {
|
||||
item.pair = [
|
||||
{ id: insertPair.originalID, type: 'way', role: item.role },
|
||||
{ id: insertPair.insertedID, type: 'way', role: item.role }
|
||||
];
|
||||
} else {
|
||||
memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
|
||||
item.pair = [
|
||||
{ id: insertPair.insertedID, type: 'way', role: item.role },
|
||||
{ id: insertPair.originalID, type: 'way', role: item.role }
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// reorder `members` if necessary
|
||||
if (k > 0) {
|
||||
if (j+k >= members.length || item.index !== members[j+k].index) {
|
||||
moveMember(members, item.index, j+k);
|
||||
}
|
||||
}
|
||||
|
||||
nodes.splice(0, way.nodes.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return graph.replace(relation.addMember(member, memberIndex));
|
||||
};
|
||||
if (tempWay) {
|
||||
graph = graph.remove(tempWay);
|
||||
}
|
||||
|
||||
// Final pass: skip dead items, split pairs, remove index properties
|
||||
var wayMembers = [];
|
||||
for (i = 0; i < members.length; i++) {
|
||||
item = members[i];
|
||||
if (item.index === -1) continue;
|
||||
|
||||
if (item.pair) {
|
||||
wayMembers.push(item.pair[0]);
|
||||
wayMembers.push(item.pair[1]);
|
||||
} else {
|
||||
wayMembers.push(_omit(item, 'index'));
|
||||
}
|
||||
}
|
||||
|
||||
// Write members in the order: nodes, ways, relations
|
||||
// This is reccomended for Public Transport routes:
|
||||
// see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
|
||||
var newMembers = (groups.node || []).concat(wayMembers, (groups.relation || []));
|
||||
|
||||
return graph.replace(relation.update({members: newMembers}));
|
||||
|
||||
|
||||
// `moveMember()` changes the `members` array in place by splicing
|
||||
// the item with `.index = findIndex` to where it belongs,
|
||||
// and marking the old position as "dead" with `.index = -1`
|
||||
//
|
||||
// j=5, k=0 jk
|
||||
// segment 5 4 7 6
|
||||
// members 0 1 2 3 4 5 6 7 8 9 keep 5 in j+k
|
||||
//
|
||||
// j=5, k=1 j k
|
||||
// segment 5 4 7 6
|
||||
// members 0 1 2 3 4 5 6 7 8 9 move 4 to j+k
|
||||
// members 0 1 2 3 x 5 4 6 7 8 9 moved
|
||||
//
|
||||
// j=5, k=2 j k
|
||||
// segment 5 4 7 6
|
||||
// members 0 1 2 3 x 5 4 6 7 8 9 move 7 to j+k
|
||||
// members 0 1 2 3 x 5 4 7 6 x 8 9 moved
|
||||
//
|
||||
// j=5, k=3 j k
|
||||
// segment 5 4 7 6
|
||||
// members 0 1 2 3 x 5 4 7 6 x 8 9 keep 6 in j+k
|
||||
//
|
||||
function moveMember(arr, findIndex, toIndex) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (arr[i].index === findIndex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var item = _clone(arr[i]);
|
||||
arr[i].index = -1; // mark as dead
|
||||
item.index = toIndex;
|
||||
arr.splice(toIndex, 0, item);
|
||||
}
|
||||
|
||||
|
||||
// This is the same as `Relation.indexedMembers`,
|
||||
// Except we don't want to index all the members, only the ways
|
||||
function withIndex(arr) {
|
||||
var result = new Array(arr.length);
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
result[i] = arr[i];
|
||||
result[i].index = i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import _extend from 'lodash-es/extend';
|
||||
import _groupBy from 'lodash-es/groupBy';
|
||||
import _map from 'lodash-es/map';
|
||||
|
||||
import { actionDeleteWay } from './delete_way';
|
||||
|
||||
import {
|
||||
osmIsInterestingTag,
|
||||
osmJoinWays
|
||||
} from '../osm';
|
||||
import { osmIsInterestingTag, osmJoinWays } from '../osm';
|
||||
|
||||
|
||||
// Join ways at the end node they share.
|
||||
@@ -27,25 +22,30 @@ export function actionJoin(ids) {
|
||||
|
||||
|
||||
var action = function(graph) {
|
||||
var ways = ids.map(graph.entity, graph),
|
||||
survivor = ways[0];
|
||||
var ways = ids.map(graph.entity, graph);
|
||||
var survivorID = ways[0].id;
|
||||
|
||||
// Prefer to keep an existing way.
|
||||
for (var i = 0; i < ways.length; i++) {
|
||||
if (!ways[i].isNew()) {
|
||||
survivor = ways[i];
|
||||
survivorID = ways[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var joined = osmJoinWays(ways, graph)[0];
|
||||
var sequences = osmJoinWays(ways, graph);
|
||||
var joined = sequences[0];
|
||||
|
||||
survivor = survivor.update({nodes: _map(joined.nodes, 'id')});
|
||||
// We might need to reverse some of these ways before joining them. #4688
|
||||
// `joined.actions` property will contain any actions we need to apply.
|
||||
graph = sequences.actions.reduce(function(g, action) { return action(g); }, graph);
|
||||
|
||||
var survivor = graph.entity(survivorID);
|
||||
survivor = survivor.update({ nodes: joined.nodes.map(function(n) { return n.id; }) });
|
||||
graph = graph.replace(survivor);
|
||||
|
||||
joined.forEach(function(way) {
|
||||
if (way.id === survivor.id)
|
||||
return;
|
||||
if (way.id === survivorID) return;
|
||||
|
||||
graph.parentRelations(way).forEach(function(parent) {
|
||||
graph = graph.replace(parent.replaceMember(way, survivor));
|
||||
@@ -70,10 +70,10 @@ export function actionJoin(ids) {
|
||||
if (joined.length > 1)
|
||||
return 'not_adjacent';
|
||||
|
||||
var nodeIds = _map(joined[0].nodes, 'id').slice(1, -1),
|
||||
relation,
|
||||
tags = {},
|
||||
conflicting = false;
|
||||
var nodeIds = joined[0].nodes.map(function(n) { return n.id; }).slice(1, -1);
|
||||
var relation;
|
||||
var tags = {};
|
||||
var conflicting = false;
|
||||
|
||||
joined[0].forEach(function(way) {
|
||||
var parents = graph.parentRelations(way);
|
||||
|
||||
@@ -29,7 +29,7 @@ import { utilWrap } from '../util';
|
||||
// https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
|
||||
//
|
||||
export function actionSplit(nodeId, newWayIds) {
|
||||
var wayIds;
|
||||
var _wayIDs;
|
||||
|
||||
// if the way is closed, we need to search for a partner node
|
||||
// to split the way at.
|
||||
@@ -42,11 +42,11 @@ export function actionSplit(nodeId, newWayIds) {
|
||||
// For example: bone-shaped areas get split across their waist
|
||||
// line, circles across the diameter.
|
||||
function splitArea(nodes, idxA, graph) {
|
||||
var lengths = new Array(nodes.length),
|
||||
length,
|
||||
i,
|
||||
best = 0,
|
||||
idxB;
|
||||
var lengths = new Array(nodes.length);
|
||||
var length;
|
||||
var i;
|
||||
var best = 0;
|
||||
var idxB;
|
||||
|
||||
function wrap(index) {
|
||||
return utilWrap(index, nodes.length);
|
||||
@@ -84,16 +84,17 @@ export function actionSplit(nodeId, newWayIds) {
|
||||
|
||||
|
||||
function split(graph, wayA, newWayId) {
|
||||
var wayB = osmWay({id: newWayId, tags: wayA.tags}),
|
||||
nodesA,
|
||||
nodesB,
|
||||
isArea = wayA.isArea(),
|
||||
isOuter = osmIsSimpleMultipolygonOuterMember(wayA, graph);
|
||||
var wayB = osmWay({id: newWayId, tags: wayA.tags});
|
||||
var origNodes = wayA.nodes.slice();
|
||||
var nodesA;
|
||||
var nodesB;
|
||||
var isArea = wayA.isArea();
|
||||
var isOuter = osmIsSimpleMultipolygonOuterMember(wayA, graph);
|
||||
|
||||
if (wayA.isClosed()) {
|
||||
var nodes = wayA.nodes.slice(0, -1),
|
||||
idxA = _indexOf(nodes, nodeId),
|
||||
idxB = splitArea(nodes, idxA, graph);
|
||||
var nodes = wayA.nodes.slice(0, -1);
|
||||
var idxA = _indexOf(nodes, nodeId);
|
||||
var idxB = splitArea(nodes, idxA, graph);
|
||||
|
||||
if (idxB < idxA) {
|
||||
nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
|
||||
@@ -134,7 +135,13 @@ export function actionSplit(nodeId, newWayIds) {
|
||||
role: relation.memberById(wayA.id).role
|
||||
};
|
||||
|
||||
graph = actionAddMember(relation.id, member)(graph);
|
||||
var insertPair = {
|
||||
originalID: wayA.id,
|
||||
insertedID: wayB.id,
|
||||
nodes: origNodes
|
||||
};
|
||||
|
||||
graph = actionAddMember(relation.id, member, undefined, insertPair)(graph);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -144,7 +151,8 @@ export function actionSplit(nodeId, newWayIds) {
|
||||
members: [
|
||||
{id: wayA.id, role: 'outer', type: 'way'},
|
||||
{id: wayB.id, role: 'outer', type: 'way'}
|
||||
]});
|
||||
]
|
||||
});
|
||||
|
||||
graph = graph.replace(multipolygon);
|
||||
graph = graph.replace(wayA.update({tags: {}}));
|
||||
@@ -165,15 +173,15 @@ export function actionSplit(nodeId, newWayIds) {
|
||||
|
||||
|
||||
action.ways = function(graph) {
|
||||
var node = graph.entity(nodeId),
|
||||
parents = graph.parentWays(node),
|
||||
hasLines = _some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
|
||||
var node = graph.entity(nodeId);
|
||||
var parents = graph.parentWays(node);
|
||||
var hasLines = _some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
|
||||
|
||||
return parents.filter(function(parent) {
|
||||
if (wayIds && wayIds.indexOf(parent.id) === -1)
|
||||
if (_wayIDs && _wayIDs.indexOf(parent.id) === -1)
|
||||
return false;
|
||||
|
||||
if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
|
||||
if (!_wayIDs && hasLines && parent.geometry(graph) !== 'line')
|
||||
return false;
|
||||
|
||||
if (parent.isClosed()) {
|
||||
@@ -193,14 +201,14 @@ export function actionSplit(nodeId, newWayIds) {
|
||||
|
||||
action.disabled = function(graph) {
|
||||
var candidates = action.ways(graph);
|
||||
if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
|
||||
if (candidates.length === 0 || (_wayIDs && _wayIDs.length !== candidates.length))
|
||||
return 'not_eligible';
|
||||
};
|
||||
|
||||
|
||||
action.limitWays = function(_) {
|
||||
if (!arguments.length) return wayIds;
|
||||
wayIds = _;
|
||||
if (!arguments.length) return _wayIDs;
|
||||
_wayIDs = _;
|
||||
return action;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { actionReverse } from '../actions/reverse';
|
||||
import { osmIsInterestingTag } from './tags';
|
||||
import { osmWay } from './way';
|
||||
|
||||
|
||||
// For fixing up rendering of multipolygons with tags on the outer member.
|
||||
@@ -62,87 +63,122 @@ export function osmSimpleMultipolygonOuterMember(entity, graph) {
|
||||
}
|
||||
|
||||
|
||||
// Join `array` into sequences of connecting ways.
|
||||
//
|
||||
// Join `toJoin` array into sequences of connecting ways.
|
||||
|
||||
// Segments which share identical start/end nodes will, as much as possible,
|
||||
// be connected with each other.
|
||||
//
|
||||
// The return value is a nested array. Each constituent array contains elements
|
||||
// of `array` which have been determined to connect. Each consitituent array
|
||||
// also has a `nodes` property whose value is an ordered array of member nodes,
|
||||
// with appropriate order reversal and start/end coordinate de-duplication.
|
||||
// of `toJoin` which have been determined to connect.
|
||||
//
|
||||
// Members of `array` must have, at minimum, `type` and `id` properties.
|
||||
// Thus either an array of `osmWay`s or a relation member array may be
|
||||
// used.
|
||||
// Each consitituent array also has a `nodes` property whose value is an
|
||||
// ordered array of member nodes, with appropriate order reversal and
|
||||
// start/end coordinate de-duplication.
|
||||
//
|
||||
// If an member has a `tags` property, its tags will be reversed via
|
||||
// Members of `toJoin` must have, at minimum, `type` and `id` properties.
|
||||
// Thus either an array of `osmWay`s or a relation member array may be used.
|
||||
//
|
||||
// If an member is an `osmWay`, its tags and childnodes may be reversed via
|
||||
// `actionReverse` in the output.
|
||||
//
|
||||
// The returned sequences array also has an `actions` array property, containing
|
||||
// any reversal actions that should be applied to the graph, should the calling
|
||||
// code attempt to actually join the given ways.
|
||||
//
|
||||
// Incomplete members (those for which `graph.hasEntity(element.id)` returns
|
||||
// false) and non-way members are ignored.
|
||||
//
|
||||
export function osmJoinWays(array, graph) {
|
||||
var joined = [], member, current, nodes, first, last, i, how, what;
|
||||
|
||||
array = array.filter(function(member) {
|
||||
return member.type === 'way' && graph.hasEntity(member.id);
|
||||
});
|
||||
|
||||
export function osmJoinWays(toJoin, graph) {
|
||||
function resolve(member) {
|
||||
return graph.childNodes(graph.entity(member.id));
|
||||
}
|
||||
|
||||
function reverse(member) {
|
||||
return member.tags ? actionReverse(member.id, { reverseOneway: true })(graph).entity(member.id) : member;
|
||||
function reverse(item) {
|
||||
var action = actionReverse(item.id, { reverseOneway: true });
|
||||
sequences.actions.push(action);
|
||||
return (item instanceof osmWay) ? action(graph).entity(item.id) : item;
|
||||
}
|
||||
|
||||
while (array.length) {
|
||||
member = array.shift();
|
||||
current = [member];
|
||||
current.nodes = nodes = resolve(member).slice();
|
||||
joined.push(current);
|
||||
// make a copy containing only the items to join
|
||||
toJoin = toJoin.filter(function(member) {
|
||||
return member.type === 'way' && graph.hasEntity(member.id);
|
||||
});
|
||||
|
||||
while (array.length && nodes[0] !== nodes[nodes.length - 1]) {
|
||||
first = nodes[0];
|
||||
last = nodes[nodes.length - 1];
|
||||
|
||||
for (i = 0; i < array.length; i++) {
|
||||
member = array[i];
|
||||
what = resolve(member);
|
||||
var sequences = [];
|
||||
sequences.actions = [];
|
||||
|
||||
if (last === what[0]) {
|
||||
how = nodes.push;
|
||||
what = what.slice(1);
|
||||
while (toJoin.length) {
|
||||
// start a new sequence
|
||||
var item = toJoin.shift();
|
||||
var currWays = [item];
|
||||
var currNodes = resolve(item).slice();
|
||||
var doneSequence = false;
|
||||
|
||||
// add to it
|
||||
while (toJoin.length && !doneSequence) {
|
||||
var start = currNodes[0];
|
||||
var end = currNodes[currNodes.length - 1];
|
||||
var fn = null;
|
||||
var nodes = null;
|
||||
var i;
|
||||
|
||||
// Find the next way/member to join.
|
||||
for (i = 0; i < toJoin.length; i++) {
|
||||
item = toJoin[i];
|
||||
nodes = resolve(item);
|
||||
|
||||
// Strongly prefer to generate a forward path that preserves the order
|
||||
// of the members array. For multipolygons and most relations, member
|
||||
// order does not matter - but for routes, it does. If we started this
|
||||
// sequence backwards (i.e. next member way attaches to the start node
|
||||
// and not the end node), reverse the initial way before continuing.
|
||||
if (currWays.length === 1 && nodes[0] !== end && nodes[nodes.length - 1] !== end &&
|
||||
(nodes[nodes.length - 1] === start || nodes[0] === start)
|
||||
) {
|
||||
currWays[0] = reverse(currWays[0]);
|
||||
currNodes.reverse();
|
||||
start = currNodes[0];
|
||||
end = currNodes[currNodes.length - 1];
|
||||
}
|
||||
|
||||
if (nodes[0] === end) {
|
||||
fn = currNodes.push; // join to end
|
||||
nodes = nodes.slice(1);
|
||||
break;
|
||||
} else if (last === what[what.length - 1]) {
|
||||
how = nodes.push;
|
||||
what = what.slice(0, -1).reverse();
|
||||
member = reverse(member);
|
||||
} else if (nodes[nodes.length - 1] === end) {
|
||||
fn = currNodes.push; // join to end
|
||||
nodes = nodes.slice(0, -1).reverse();
|
||||
item = reverse(item);
|
||||
break;
|
||||
} else if (first === what[what.length - 1]) {
|
||||
how = nodes.unshift;
|
||||
what = what.slice(0, -1);
|
||||
} else if (nodes[nodes.length - 1] === start) {
|
||||
fn = currNodes.unshift; // join to beginning
|
||||
nodes = nodes.slice(0, -1);
|
||||
break;
|
||||
} else if (first === what[0]) {
|
||||
how = nodes.unshift;
|
||||
what = what.slice(1).reverse();
|
||||
member = reverse(member);
|
||||
} else if (nodes[0] === start) {
|
||||
fn = currNodes.unshift; // join to beginning
|
||||
nodes = nodes.slice(1).reverse();
|
||||
item = reverse(item);
|
||||
break;
|
||||
} else {
|
||||
what = how = null;
|
||||
fn = nodes = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!what)
|
||||
break; // No more joinable ways.
|
||||
if (!nodes) { // couldn't find a joinable way/member
|
||||
doneSequence = true;
|
||||
break;
|
||||
}
|
||||
|
||||
how.apply(current, [member]);
|
||||
how.apply(nodes, what);
|
||||
fn.apply(currWays, [item]);
|
||||
fn.apply(currNodes, nodes);
|
||||
|
||||
array.splice(i, 1);
|
||||
toJoin.splice(i, 1);
|
||||
}
|
||||
|
||||
currWays.nodes = currNodes;
|
||||
sequences.push(currWays);
|
||||
}
|
||||
|
||||
return joined;
|
||||
return sequences;
|
||||
}
|
||||
|
||||
@@ -161,9 +161,9 @@ _extend(osmRelation.prototype, {
|
||||
|
||||
// Wherever a member appears with id `needle.id`, replace it with a member
|
||||
// with id `replacement.id`, type `replacement.type`, and the original role,
|
||||
// unless a member already exists with that id and role. Return an updated
|
||||
// relation.
|
||||
replaceMember: function(needle, replacement) {
|
||||
// By default, adding a duplicate member (by id and role) is prevented.
|
||||
// Return an updated relation.
|
||||
replaceMember: function(needle, replacement, keepDuplicates) {
|
||||
if (!this.memberById(needle.id))
|
||||
return this;
|
||||
|
||||
@@ -173,7 +173,7 @@ _extend(osmRelation.prototype, {
|
||||
var member = this.members[i];
|
||||
if (member.id !== needle.id) {
|
||||
members.push(member);
|
||||
} else if (!this.memberByIdAndRole(replacement.id, member.role)) {
|
||||
} else if (keepDuplicates || !this.memberByIdAndRole(replacement.id, member.role)) {
|
||||
members.push({id: replacement.id, type: replacement.type, role: member.role});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
describe('iD.actionAddMember', function() {
|
||||
it('adds an member to a relation at the specified index', function() {
|
||||
var r = iD.Relation({members: [{id: '1'}, {id: '3'}]}),
|
||||
g = iD.actionAddMember(r.id, {id: '2'}, 1)(iD.Graph([r]));
|
||||
var r = iD.osmRelation({members: [{id: '1'}, {id: '3'}]});
|
||||
var g = iD.actionAddMember(r.id, {id: '2'}, 1)(iD.coreGraph([r]));
|
||||
expect(g.entity(r.id).members).to.eql([{id: '1'}, {id: '2'}, {id: '3'}]);
|
||||
});
|
||||
|
||||
@@ -10,81 +10,197 @@ describe('iD.actionAddMember', function() {
|
||||
return graph.entity('r').members.map(function (m) { return m.id; });
|
||||
}
|
||||
|
||||
specify('no members', function() {
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a', loc: [0, 0]}),
|
||||
iD.Node({id: 'b', loc: [0, 0]}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Relation({id: 'r'})
|
||||
it('handles incomplete relations', function () {
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'c', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'd', loc: [0, 0]}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
|
||||
iD.osmWay({id: '=', nodes: ['c','d']}),
|
||||
iD.osmRelation({id: 'r', members: [
|
||||
{id: '~', type: 'way'},
|
||||
{id: '-', type: 'way'}
|
||||
]})
|
||||
]);
|
||||
|
||||
graph = iD.actionAddMember('r', {id: '=', type: 'way'})(graph);
|
||||
expect(members(graph)).to.eql(['~', '-', '=']);
|
||||
});
|
||||
|
||||
it('adds the member to a relation with no members', function() {
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [0, 0]}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmRelation({id: 'r'})
|
||||
]);
|
||||
|
||||
graph = iD.actionAddMember('r', {id: '-', type: 'way'})(graph);
|
||||
expect(members(graph)).to.eql(['-']);
|
||||
});
|
||||
|
||||
specify('not connecting', function() {
|
||||
// a--->b c===>d
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a', loc: [0, 0]}),
|
||||
iD.Node({id: 'b', loc: [0, 0]}),
|
||||
iD.Node({id: 'c', loc: [0, 0]}),
|
||||
iD.Node({id: 'd', loc: [0, 0]}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['c', 'd']}),
|
||||
iD.Relation({id: 'r', members: [{id: '-', type: 'way'}]})
|
||||
it('appends the member if the ways are not connecting', function() {
|
||||
// Before: a ---> b
|
||||
// After: a ---> b .. c ===> d
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'c', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'd', loc: [0, 0]}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['c', 'd']}),
|
||||
iD.osmRelation({id: 'r', members: [
|
||||
{id: '-', type: 'way'}
|
||||
]})
|
||||
]);
|
||||
|
||||
graph = iD.actionAddMember('r', {id: '=', type: 'way'})(graph);
|
||||
expect(members(graph)).to.eql(['-', '=']);
|
||||
});
|
||||
|
||||
specify('connecting at end', function() {
|
||||
// a--->b===>c
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a', loc: [0, 0]}),
|
||||
iD.Node({id: 'b', loc: [0, 0]}),
|
||||
iD.Node({id: 'c', loc: [0, 0]}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']}),
|
||||
iD.Relation({id: 'r', members: [{id: '-', type: 'way'}]})
|
||||
it('appends the member if the way connects at end', function() {
|
||||
// Before: a ---> b
|
||||
// After: a ---> b ===> c
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'c', loc: [0, 0]}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']}),
|
||||
iD.osmRelation({id: 'r', members: [
|
||||
{id: '-', type: 'way'}
|
||||
]})
|
||||
]);
|
||||
|
||||
graph = iD.actionAddMember('r', {id: '=', type: 'way'})(graph);
|
||||
expect(members(graph)).to.eql(['-', '=']);
|
||||
});
|
||||
|
||||
specify('connecting at beginning', function() {
|
||||
// a===>b--->c~~~>d
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a', loc: [0, 0]}),
|
||||
iD.Node({id: 'b', loc: [0, 0]}),
|
||||
iD.Node({id: 'c', loc: [0, 0]}),
|
||||
iD.Node({id: 'd', loc: [0, 0]}),
|
||||
iD.Way({id: '=', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '-', nodes: ['b', 'c']}),
|
||||
iD.Way({id: '~', nodes: ['c', 'd']}),
|
||||
iD.Relation({id: 'r', members: [{id: '-', type: 'way'}, {id: '~', type: 'way'}]})
|
||||
it('inserts the member if the way connects at beginning', function() {
|
||||
// Before: b ---> c ~~~> d
|
||||
// After: a ===> b ---> c ~~~> d
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'c', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'd', loc: [0, 0]}),
|
||||
iD.osmWay({id: '=', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '-', nodes: ['b', 'c']}),
|
||||
iD.osmWay({id: '~', nodes: ['c', 'd']}),
|
||||
iD.osmRelation({id: 'r', members: [
|
||||
{id: '-', type: 'way'},
|
||||
{id: '~', type: 'way'}
|
||||
]})
|
||||
]);
|
||||
|
||||
graph = iD.actionAddMember('r', {id: '=', type: 'way'})(graph);
|
||||
expect(members(graph)).to.eql(['=', '-', '~']);
|
||||
});
|
||||
|
||||
specify('connecting in middle', function() {
|
||||
// a--->b===>c~~~>d
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a', loc: [0, 0]}),
|
||||
iD.Node({id: 'b', loc: [0, 0]}),
|
||||
iD.Node({id: 'c', loc: [0, 0]}),
|
||||
iD.Node({id: 'd', loc: [0, 0]}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']}),
|
||||
iD.Way({id: '~', nodes: ['c', 'd']}),
|
||||
iD.Relation({id: 'r', members: [{id: '-', type: 'way'}, {id: '~', type: 'way'}]})
|
||||
it('inserts the member if the way connects in middle', function() {
|
||||
// Before: a ---> b .. c ~~~> d
|
||||
// After: a ---> b ===> c ~~~> d
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'c', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'd', loc: [0, 0]}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']}),
|
||||
iD.osmWay({id: '~', nodes: ['c', 'd']}),
|
||||
iD.osmRelation({id: 'r', members: [
|
||||
{id: '-', type: 'way'},
|
||||
{id: '~', type: 'way'}
|
||||
]})
|
||||
]);
|
||||
|
||||
graph = iD.actionAddMember('r', {id: '=', type: 'way'})(graph);
|
||||
expect(members(graph)).to.eql(['-', '=', '~']);
|
||||
});
|
||||
|
||||
it('inserts the member multiple times if insertPair provided (middle)', function() {
|
||||
// Before: a ---> b .. c ~~~> d <~~~ c .. b <--- a
|
||||
// After: a ---> b ===> c ~~~> d <~~~ c <=== b <--- a
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'c', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'd', loc: [0, 0]}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']}),
|
||||
iD.osmWay({id: '~', nodes: ['c', 'd']}),
|
||||
iD.osmRelation({id: 'r', members: [
|
||||
{id: '-', type: 'way'},
|
||||
{id: '~', type: 'way'},
|
||||
{id: '~', type: 'way'},
|
||||
{id: '-', type: 'way'}
|
||||
]})
|
||||
]);
|
||||
|
||||
var member = { id: '=', type: 'way' };
|
||||
var insertPair = {
|
||||
originalID: '-',
|
||||
insertedID: '=',
|
||||
nodes: ['a','b','c']
|
||||
};
|
||||
graph = iD.actionAddMember('r', member, undefined, insertPair)(graph);
|
||||
expect(members(graph)).to.eql(['-', '=', '~', '~', '=', '-']);
|
||||
});
|
||||
|
||||
it('inserts the member multiple times if insertPair provided (beginning/end)', function() {
|
||||
// Before: b <=== c ~~~> d <~~~ c ===> b
|
||||
// After: a <--- b <=== c ~~~> d <~~~ c ===> b ---> a
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'c', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'd', loc: [0, 0]}),
|
||||
iD.osmWay({id: '-', nodes: ['b', 'a']}),
|
||||
iD.osmWay({id: '=', nodes: ['c', 'b']}),
|
||||
iD.osmWay({id: '~', nodes: ['c', 'd']}),
|
||||
iD.osmRelation({id: 'r', members: [
|
||||
{id: '=', type: 'way'},
|
||||
{id: '~', type: 'way'},
|
||||
{id: '~', type: 'way'},
|
||||
{id: '=', type: 'way'}
|
||||
]})
|
||||
]);
|
||||
|
||||
var member = { id: '-', type: 'way' };
|
||||
var insertPair = {
|
||||
originalID: '=',
|
||||
insertedID: '-',
|
||||
nodes: ['c','b','a']
|
||||
};
|
||||
graph = iD.actionAddMember('r', member, undefined, insertPair)(graph);
|
||||
expect(members(graph)).to.eql(['-', '=', '~', '~', '=', '-']);
|
||||
});
|
||||
|
||||
it('reorders members as node, way, relation (for Public Transport routing)', function() {
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'c', loc: [0, 0]}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']}),
|
||||
iD.osmRelation({id: 'r', members: [
|
||||
{ id: 'n1', type: 'node', role: 'forward' },
|
||||
{ id: '-', type: 'way', role: 'forward' },
|
||||
{ id: 'r1', type: 'relation', role: 'forward' },
|
||||
{ id: 'n2', type: 'node', role: 'forward' }
|
||||
]})
|
||||
]);
|
||||
|
||||
graph = iD.actionAddMember('r', { id: '=', type: 'way', role: 'forward' })(graph);
|
||||
expect(graph.entity('r').members).to.eql([
|
||||
{ id: 'n1', type: 'node', role: 'forward' },
|
||||
{ id: 'n2', type: 'node', role: 'forward' },
|
||||
{ id: '-', type: 'way', role: 'forward' },
|
||||
{ id: '=', type: 'way', role: 'forward' },
|
||||
{ id: 'r1', type: 'relation', role: 'forward' }
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,67 +2,67 @@ describe('iD.actionJoin', function () {
|
||||
describe('#disabled', function () {
|
||||
it('returns falsy for ways that share an end/start node', function () {
|
||||
// a --> b ==> c
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).not.to.be.ok;
|
||||
});
|
||||
|
||||
it('returns falsy for ways that share a start/end node', function () {
|
||||
// a <-- b <== c
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['b', 'a']}),
|
||||
iD.Way({id: '=', nodes: ['c', 'b']})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['b', 'a']}),
|
||||
iD.osmWay({id: '=', nodes: ['c', 'b']})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).not.to.be.ok;
|
||||
});
|
||||
|
||||
it('returns falsy for ways that share a start/start node', function () {
|
||||
// a <-- b ==> c
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['b', 'a']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['b', 'a']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).not.to.be.ok;
|
||||
});
|
||||
|
||||
it('returns falsy for ways that share an end/end node', function () {
|
||||
// a --> b <== c
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['c', 'b']})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['c', 'b']})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).not.to.be.ok;
|
||||
});
|
||||
|
||||
it('returns falsy for more than two ways when connected, regardless of order', function () {
|
||||
// a --> b ==> c ~~> d
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Node({id: 'd'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']}),
|
||||
iD.Way({id: '~', nodes: ['c', 'd']})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmNode({id: 'd'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']}),
|
||||
iD.osmWay({id: '~', nodes: ['c', 'd']})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=', '~']).disabled(graph)).not.to.be.ok;
|
||||
expect(iD.actionJoin(['-', '~', '=']).disabled(graph)).not.to.be.ok;
|
||||
@@ -73,9 +73,9 @@ describe('iD.actionJoin', function () {
|
||||
});
|
||||
|
||||
it('returns \'not_eligible\' for non-line geometries', function () {
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['a']).disabled(graph)).to.equal('not_eligible');
|
||||
});
|
||||
@@ -84,14 +84,14 @@ describe('iD.actionJoin', function () {
|
||||
// a -- b -- c
|
||||
// |
|
||||
// d
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Node({id: 'd'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b', 'c']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'd']})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmNode({id: 'd'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'd']})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).to.equal('not_adjacent');
|
||||
});
|
||||
@@ -101,18 +101,18 @@ describe('iD.actionJoin', function () {
|
||||
// from: -
|
||||
// to: =
|
||||
// via: b
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']}),
|
||||
iD.Relation({id: 'r', tags: {type: 'restriction'}, members: [
|
||||
{type: 'way', id: '-', role: 'from'},
|
||||
{type: 'way', id: '=', role: 'to'},
|
||||
{type: 'node', id: 'b', role: 'via'}
|
||||
]})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']}),
|
||||
iD.osmRelation({id: 'r', tags: {type: 'restriction'}, members: [
|
||||
{type: 'way', id: '-', role: 'from'},
|
||||
{type: 'way', id: '=', role: 'to'},
|
||||
{type: 'node', id: 'b', role: 'via'}
|
||||
]})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).to.equal('restriction');
|
||||
});
|
||||
@@ -124,20 +124,20 @@ describe('iD.actionJoin', function () {
|
||||
// from: -
|
||||
// to: |
|
||||
// via: b
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Node({id: 'd'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']}),
|
||||
iD.Way({id: '|', nodes: ['b', 'd']}),
|
||||
iD.Relation({id: 'r', tags: {type: 'restriction'}, members: [
|
||||
{type: 'way', id: '-', role: 'from'},
|
||||
{type: 'way', id: '|', role: 'to'},
|
||||
{type: 'node', id: 'b', role: 'via'}
|
||||
]})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmNode({id: 'd'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']}),
|
||||
iD.osmWay({id: '|', nodes: ['b', 'd']}),
|
||||
iD.osmRelation({id: 'r', tags: {type: 'restriction'}, members: [
|
||||
{type: 'way', id: '-', role: 'from'},
|
||||
{type: 'way', id: '|', role: 'to'},
|
||||
{type: 'node', id: 'b', role: 'via'}
|
||||
]})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).to.equal('restriction');
|
||||
});
|
||||
@@ -149,20 +149,20 @@ describe('iD.actionJoin', function () {
|
||||
// from: -
|
||||
// to: |
|
||||
// via: a
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Node({id: 'd'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']}),
|
||||
iD.Way({id: '|', nodes: ['a', 'd']}),
|
||||
iD.Relation({id: 'r', tags: {type: 'restriction'}, members: [
|
||||
{type: 'way', id: '-', role: 'from'},
|
||||
{type: 'way', id: '|', role: 'to'},
|
||||
{type: 'node', id: 'a', role: 'via'}
|
||||
]})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmNode({id: 'd'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']}),
|
||||
iD.osmWay({id: '|', nodes: ['a', 'd']}),
|
||||
iD.osmRelation({id: 'r', tags: {type: 'restriction'}, members: [
|
||||
{type: 'way', id: '-', role: 'from'},
|
||||
{type: 'way', id: '|', role: 'to'},
|
||||
{type: 'node', id: 'a', role: 'via'}
|
||||
]})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).not.to.be.ok;
|
||||
});
|
||||
@@ -176,68 +176,68 @@ describe('iD.actionJoin', function () {
|
||||
// from: |
|
||||
// to: \
|
||||
// via: b
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Node({id: 'd'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']}),
|
||||
iD.Way({id: '|', nodes: ['d', 'b']}),
|
||||
iD.Way({id: '\\', nodes: ['b', 'e']}),
|
||||
iD.Relation({id: 'r', tags: {type: 'restriction'}, members: [
|
||||
{type: 'way', id: '|', role: 'from'},
|
||||
{type: 'way', id: '\\', role: 'to'},
|
||||
{type: 'node', id: 'b', role: 'via'}
|
||||
]})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmNode({id: 'd'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']}),
|
||||
iD.osmWay({id: '|', nodes: ['d', 'b']}),
|
||||
iD.osmWay({id: '\\', nodes: ['b', 'e']}),
|
||||
iD.osmRelation({id: 'r', tags: {type: 'restriction'}, members: [
|
||||
{type: 'way', id: '|', role: 'from'},
|
||||
{type: 'way', id: '\\', role: 'to'},
|
||||
{type: 'node', id: 'b', role: 'via'}
|
||||
]})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).not.to.be.ok;
|
||||
});
|
||||
|
||||
it('returns \'conflicting_tags\' for two entities that have conflicting tags', function () {
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b'], tags: {highway: 'primary'}}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c'], tags: {highway: 'secondary'}})
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b'], tags: {highway: 'primary'}}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c'], tags: {highway: 'secondary'}})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).to.equal('conflicting_tags');
|
||||
});
|
||||
|
||||
it('takes tag reversals into account when calculating conflicts', function () {
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b'], tags: {'oneway': 'yes'}}),
|
||||
iD.Way({id: '=', nodes: ['c', 'b'], tags: {'oneway': '-1'}})
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b'], tags: {'oneway': 'yes'}}),
|
||||
iD.osmWay({id: '=', nodes: ['c', 'b'], tags: {'oneway': '-1'}})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).not.to.be.ok;
|
||||
});
|
||||
|
||||
it('returns falsy for exceptions to tag conflicts: missing tag', function () {
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b'], tags: {highway: 'primary'}}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c'], tags: {}})
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b'], tags: {highway: 'primary'}}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c'], tags: {}})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).not.to.be.ok;
|
||||
});
|
||||
|
||||
it('returns falsy for exceptions to tag conflicts: uninteresting tag', function () {
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b'], tags: {'tiger:cfcc': 'A41'}}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c'], tags: {'tiger:cfcc': 'A42'}})
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b'], tags: {'tiger:cfcc': 'A41'}}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c'], tags: {'tiger:cfcc': 'A42'}})
|
||||
]);
|
||||
|
||||
expect(iD.actionJoin(['-', '=']).disabled(graph)).not.to.be.ok;
|
||||
@@ -247,13 +247,13 @@ describe('iD.actionJoin', function () {
|
||||
it('joins a --> b ==> c', function () {
|
||||
// Expected result:
|
||||
// a --> b --> c
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']})
|
||||
]);
|
||||
|
||||
graph = iD.actionJoin(['-', '='])(graph);
|
||||
|
||||
@@ -264,35 +264,35 @@ describe('iD.actionJoin', function () {
|
||||
it('joins a <-- b <== c', function () {
|
||||
// Expected result:
|
||||
// a <-- b <-- c
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['b', 'a']}),
|
||||
iD.Way({id: '=', nodes: ['c', 'b']})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['b', 'a']}),
|
||||
iD.osmWay({id: '=', nodes: ['c', 'b']})
|
||||
]);
|
||||
|
||||
graph = iD.actionJoin(['-', '='])(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.eql(['c', 'b', 'a']);
|
||||
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c']);
|
||||
expect(graph.hasEntity('=')).to.be.undefined;
|
||||
});
|
||||
|
||||
it('joins a <-- b ==> c', function () {
|
||||
// Expected result:
|
||||
// a <-- b <-- c
|
||||
// tags on === reversed
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['b', 'a']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c'], tags: {'lanes:forward': 2}})
|
||||
]);
|
||||
// a --> b --> c
|
||||
// tags on --- reversed
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['b', 'a'], tags: {'lanes:forward': 2}}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']})
|
||||
]);
|
||||
|
||||
graph = iD.actionJoin(['-', '='])(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.eql(['c', 'b', 'a']);
|
||||
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c']);
|
||||
expect(graph.hasEntity('=')).to.be.undefined;
|
||||
expect(graph.entity('-').tags).to.eql({'lanes:backward': 2});
|
||||
});
|
||||
@@ -301,13 +301,13 @@ describe('iD.actionJoin', function () {
|
||||
// Expected result:
|
||||
// a --> b --> c
|
||||
// tags on === reversed
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['c', 'b'], tags: {'lanes:forward': 2}})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['c', 'b'], tags: {'lanes:forward': 2}})
|
||||
]);
|
||||
|
||||
graph = iD.actionJoin(['-', '='])(graph);
|
||||
|
||||
@@ -320,17 +320,17 @@ describe('iD.actionJoin', function () {
|
||||
// Expected result:
|
||||
// a --> b --> c --> d --> e
|
||||
// tags on === reversed
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Node({id: 'd'}),
|
||||
iD.Node({id: 'e'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['c', 'b'], tags: {'lanes:forward': 2}}),
|
||||
iD.Way({id: '+', nodes: ['d', 'c']}),
|
||||
iD.Way({id: '*', nodes: ['d', 'e'], tags: {'lanes:backward': 2}})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmNode({id: 'd'}),
|
||||
iD.osmNode({id: 'e'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['c', 'b'], tags: {'lanes:forward': 2}}),
|
||||
iD.osmWay({id: '+', nodes: ['d', 'c']}),
|
||||
iD.osmWay({id: '*', nodes: ['d', 'e'], tags: {'lanes:backward': 2}})
|
||||
]);
|
||||
|
||||
graph = iD.actionJoin(['-', '=', '+', '*'])(graph);
|
||||
|
||||
@@ -346,15 +346,15 @@ describe('iD.actionJoin', function () {
|
||||
// --- is new, === is existing, +++ is new
|
||||
// Expected result:
|
||||
// a ==> b ==> c ==> d
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Node({id: 'd'}),
|
||||
iD.Way({id: 'w-1', nodes: ['a', 'b']}),
|
||||
iD.Way({id: 'w1', nodes: ['b', 'c']}),
|
||||
iD.Way({id: 'w-2', nodes: ['c', 'd']})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmNode({id: 'd'}),
|
||||
iD.osmWay({id: 'w-1', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: 'w1', nodes: ['b', 'c']}),
|
||||
iD.osmWay({id: 'w-2', nodes: ['c', 'd']})
|
||||
]);
|
||||
|
||||
graph = iD.actionJoin(['w-1', 'w1', 'w-2'])(graph);
|
||||
|
||||
@@ -364,15 +364,15 @@ describe('iD.actionJoin', function () {
|
||||
});
|
||||
|
||||
it('merges tags', function () {
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Node({id: 'd'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b'], tags: {a: 'a', b: '-', c: 'c'}}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c'], tags: {a: 'a', b: '=', d: 'd'}}),
|
||||
iD.Way({id: '+', nodes: ['c', 'd'], tags: {a: 'a', b: '=', e: 'e'}})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmNode({id: 'd'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b'], tags: {a: 'a', b: '-', c: 'c'}}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c'], tags: {a: 'a', b: '=', d: 'd'}}),
|
||||
iD.osmWay({id: '+', nodes: ['c', 'd'], tags: {a: 'a', b: '=', e: 'e'}})
|
||||
]);
|
||||
|
||||
graph = iD.actionJoin(['-', '=', '+'])(graph);
|
||||
|
||||
@@ -380,19 +380,65 @@ describe('iD.actionJoin', function () {
|
||||
});
|
||||
|
||||
it('merges relations', function () {
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['b', 'c']}),
|
||||
iD.Relation({id: 'r1', members: [{id: '=', role: 'r1', type: 'way'}]}),
|
||||
iD.Relation({id: 'r2', members: [{id: '=', role: 'r2', type: 'way'}, {id: '-', role: 'r2', type: 'way'}]})
|
||||
]);
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'a'}),
|
||||
iD.osmNode({id: 'b'}),
|
||||
iD.osmNode({id: 'c'}),
|
||||
iD.osmWay({id: '-', nodes: ['a', 'b']}),
|
||||
iD.osmWay({id: '=', nodes: ['b', 'c']}),
|
||||
iD.osmRelation({id: 'r1', members: [
|
||||
{id: '=', role: 'r1', type: 'way'}
|
||||
]}),
|
||||
iD.osmRelation({id: 'r2', members: [
|
||||
{id: '=', role: 'r2', type: 'way'},
|
||||
{id: '-', role: 'r2', type: 'way'}
|
||||
]})
|
||||
]);
|
||||
|
||||
graph = iD.actionJoin(['-', '='])(graph);
|
||||
|
||||
expect(graph.entity('r1').members).to.eql([{id: '-', role: 'r1', type: 'way'}]);
|
||||
expect(graph.entity('r2').members).to.eql([{id: '-', role: 'r2', type: 'way'}]);
|
||||
});
|
||||
|
||||
it('preserves duplicate route segments in relations', function () {
|
||||
//
|
||||
// Situation:
|
||||
// a ---> b ===> c ~~~~> d join '-' and '='
|
||||
// Relation: ['-', '=', '~', '~', '=', '-']
|
||||
//
|
||||
// Expected result:
|
||||
// a ---> b ---> c ~~~~> d
|
||||
// Relation: ['-', '~', '~', '-']
|
||||
//
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({ id: 'a', loc: [0, 0] }),
|
||||
iD.osmNode({ id: 'b', loc: [1, 0] }),
|
||||
iD.osmNode({ id: 'c', loc: [2, 0] }),
|
||||
iD.osmNode({ id: 'd', loc: [3, 0] }),
|
||||
iD.osmWay({ id: '-', nodes: ['a', 'b'] }),
|
||||
iD.osmWay({ id: '=', nodes: ['b', 'c'] }),
|
||||
iD.osmWay({ id: '~', nodes: ['c', 'd'] }),
|
||||
iD.osmRelation({id: 'r', members: [
|
||||
{id: '-', role: 'forward', type: 'way'},
|
||||
{id: '=', role: 'forward', type: 'way'},
|
||||
{id: '~', role: 'forward', type: 'way'},
|
||||
{id: '~', role: 'forward', type: 'way'},
|
||||
{id: '=', role: 'forward', type: 'way'},
|
||||
{id: '-', role: 'forward', type: 'way'}
|
||||
]})
|
||||
]);
|
||||
|
||||
graph = iD.actionJoin(['-', '='])(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c']);
|
||||
expect(graph.entity('~').nodes).to.eql(['c', 'd']);
|
||||
expect(graph.entity('r').members).to.eql([
|
||||
{id: '-', role: 'forward', type: 'way'},
|
||||
{id: '~', role: 'forward', type: 'way'},
|
||||
{id: '~', role: 'forward', type: 'way'},
|
||||
{id: '-', role: 'forward', type: 'way'}
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,91 +1,101 @@
|
||||
describe('iD.osmIsSimpleMultipolygonOuterMember', function() {
|
||||
it('returns the parent relation of a simple multipolygon outer', function() {
|
||||
var outer = iD.Way({tags: {'natural':'wood'}}),
|
||||
relation = iD.Relation({tags: {type: 'multipolygon'},
|
||||
members: [{id: outer.id, role: 'outer'}]}),
|
||||
graph = iD.Graph([outer, relation]);
|
||||
var outer = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation(
|
||||
{tags: {type: 'multipolygon'}, members: [{id: outer.id, role: 'outer'}]}
|
||||
);
|
||||
var graph = iD.coreGraph([outer, relation]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.equal(relation);
|
||||
});
|
||||
|
||||
it('returns the parent relation of a simple multipolygon outer, assuming role outer if unspecified', function() {
|
||||
var outer = iD.Way({tags: {'natural':'wood'}}),
|
||||
relation = iD.Relation({tags: {type: 'multipolygon'},
|
||||
members: [{id: outer.id}]}),
|
||||
graph = iD.Graph([outer, relation]);
|
||||
var outer = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation(
|
||||
{tags: {type: 'multipolygon'}, members: [{id: outer.id}]}
|
||||
);
|
||||
var graph = iD.coreGraph([outer, relation]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.equal(relation);
|
||||
});
|
||||
|
||||
it('returns false if entity is not a way', function() {
|
||||
var outer = iD.Node({tags: {'natural':'wood'}}),
|
||||
relation = iD.Relation({tags: {type: 'multipolygon'},
|
||||
members: [{id: outer.id, role: 'outer'}]}),
|
||||
graph = iD.Graph([outer, relation]);
|
||||
var outer = iD.osmNode({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation(
|
||||
{tags: {type: 'multipolygon'}, members: [{id: outer.id, role: 'outer'}]}
|
||||
);
|
||||
var graph = iD.coreGraph([outer, relation]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if entity does not have interesting tags', function() {
|
||||
var outer = iD.Way({tags: {'tiger:reviewed':'no'}}),
|
||||
relation = iD.Relation({tags: {type: 'multipolygon'},
|
||||
members: [{id: outer.id, role: 'outer'}]}),
|
||||
graph = iD.Graph([outer, relation]);
|
||||
var outer = iD.osmWay({tags: {'tiger:reviewed':'no'}});
|
||||
var relation = iD.osmRelation(
|
||||
{tags: {type: 'multipolygon'}, members: [{id: outer.id, role: 'outer'}]}
|
||||
);
|
||||
var graph = iD.coreGraph([outer, relation]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if entity does not have a parent relation', function() {
|
||||
var outer = iD.Way({tags: {'natural':'wood'}}),
|
||||
graph = iD.Graph([outer]);
|
||||
var outer = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var graph = iD.coreGraph([outer]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if the parent is not a multipolygon', function() {
|
||||
var outer = iD.Way({tags: {'natural':'wood'}}),
|
||||
relation = iD.Relation({tags: {type: 'route'},
|
||||
members: [{id: outer.id, role: 'outer'}]}),
|
||||
graph = iD.Graph([outer, relation]);
|
||||
var outer = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation(
|
||||
{tags: {type: 'route'}, members: [{id: outer.id, role: 'outer'}]}
|
||||
);
|
||||
var graph = iD.coreGraph([outer, relation]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if the parent has interesting tags', function() {
|
||||
var outer = iD.Way({tags: {'natural':'wood'}}),
|
||||
relation = iD.Relation({tags: {natural: 'wood', type: 'multipolygon'},
|
||||
members: [{id: outer.id, role: 'outer'}]}),
|
||||
graph = iD.Graph([outer, relation]);
|
||||
var outer = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation(
|
||||
{tags: {natural: 'wood', type: 'multipolygon'}, members: [{id: outer.id, role: 'outer'}]}
|
||||
);
|
||||
var graph = iD.coreGraph([outer, relation]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.be.false;
|
||||
});
|
||||
|
||||
it('returns the parent relation of a simple multipolygon outer, ignoring uninteresting parent tags', function() {
|
||||
var outer = iD.Way({tags: {'natural':'wood'}}),
|
||||
relation = iD.Relation({tags: {'tiger:reviewed':'no', type: 'multipolygon'},
|
||||
members: [{id: outer.id, role: 'outer'}]}),
|
||||
graph = iD.Graph([outer, relation]);
|
||||
var outer = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation(
|
||||
{tags: {'tiger:reviewed':'no', type: 'multipolygon'}, members: [{id: outer.id, role: 'outer'}]}
|
||||
);
|
||||
var graph = iD.coreGraph([outer, relation]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.equal(relation);
|
||||
});
|
||||
|
||||
it('returns false if the parent has multiple outer ways', function() {
|
||||
var outer1 = iD.Way({tags: {'natural':'wood'}}),
|
||||
outer2 = iD.Way({tags: {'natural':'wood'}}),
|
||||
relation = iD.Relation({tags: {type: 'multipolygon'},
|
||||
members: [{id: outer1.id, role: 'outer'}, {id: outer2.id, role: 'outer'}]}),
|
||||
graph = iD.Graph([outer1, outer2, relation]);
|
||||
var outer1 = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var outer2 = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation(
|
||||
{tags: {type: 'multipolygon'}, members: [{id: outer1.id, role: 'outer'}, {id: outer2.id, role: 'outer'}]}
|
||||
);
|
||||
var graph = iD.coreGraph([outer1, outer2, relation]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer1, graph)).to.be.false;
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer2, graph)).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if the parent has multiple outer ways, assuming role outer if unspecified', function() {
|
||||
var outer1 = iD.Way({tags: {'natural':'wood'}}),
|
||||
outer2 = iD.Way({tags: {'natural':'wood'}}),
|
||||
relation = iD.Relation({tags: {type: 'multipolygon'},
|
||||
members: [{id: outer1.id}, {id: outer2.id}]}),
|
||||
graph = iD.Graph([outer1, outer2, relation]);
|
||||
var outer1 = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var outer2 = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation(
|
||||
{tags: {type: 'multipolygon'}, members: [{id: outer1.id}, {id: outer2.id}]}
|
||||
);
|
||||
var graph = iD.coreGraph([outer1, outer2, relation]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer1, graph)).to.be.false;
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(outer2, graph)).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if the entity is not an outer', function() {
|
||||
var inner = iD.Way({tags: {'natural':'wood'}}),
|
||||
relation = iD.Relation({tags: {type: 'multipolygon'},
|
||||
members: [{id: inner.id, role: 'inner'}]}),
|
||||
graph = iD.Graph([inner, relation]);
|
||||
var inner = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation(
|
||||
{tags: {type: 'multipolygon'}, members: [{id: inner.id, role: 'inner'}]}
|
||||
);
|
||||
var graph = iD.coreGraph([inner, relation]);
|
||||
expect(iD.osmIsSimpleMultipolygonOuterMember(inner, graph)).to.be.false;
|
||||
});
|
||||
});
|
||||
@@ -93,28 +103,28 @@ describe('iD.osmIsSimpleMultipolygonOuterMember', function() {
|
||||
|
||||
describe('iD.osmSimpleMultipolygonOuterMember', function() {
|
||||
it('returns the outer member of a simple multipolygon', function() {
|
||||
var inner = iD.Way(),
|
||||
outer = iD.Way({tags: {'natural':'wood'}}),
|
||||
relation = iD.Relation({tags: {type: 'multipolygon'}, members: [
|
||||
{id: outer.id, role: 'outer'},
|
||||
{id: inner.id, role: 'inner'}]
|
||||
}),
|
||||
graph = iD.Graph([inner, outer, relation]);
|
||||
var inner = iD.osmWay();
|
||||
var outer = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation({tags: {type: 'multipolygon'}, members: [
|
||||
{id: outer.id, role: 'outer'},
|
||||
{id: inner.id, role: 'inner'}]
|
||||
});
|
||||
var graph = iD.coreGraph([inner, outer, relation]);
|
||||
|
||||
expect(iD.osmSimpleMultipolygonOuterMember(inner, graph)).to.equal(outer);
|
||||
expect(iD.osmSimpleMultipolygonOuterMember(outer, graph)).to.equal(outer);
|
||||
});
|
||||
|
||||
it('returns falsy for a complex multipolygon', function() {
|
||||
var inner = iD.Way(),
|
||||
outer1 = iD.Way({tags: {'natural':'wood'}}),
|
||||
outer2 = iD.Way({tags: {'natural':'wood'}}),
|
||||
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]);
|
||||
var inner = iD.osmWay();
|
||||
var outer1 = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var outer2 = iD.osmWay({tags: {'natural':'wood'}});
|
||||
var relation = iD.osmRelation({tags: {type: 'multipolygon'}, members: [
|
||||
{id: outer1.id, role: 'outer'},
|
||||
{id: outer2.id, role: 'outer'},
|
||||
{id: inner.id, role: 'inner'}]
|
||||
});
|
||||
var graph = iD.coreGraph([inner, outer1, outer2, relation]);
|
||||
|
||||
expect(iD.osmSimpleMultipolygonOuterMember(inner, graph)).not.to.be.ok;
|
||||
expect(iD.osmSimpleMultipolygonOuterMember(outer1, graph)).not.to.be.ok;
|
||||
@@ -122,12 +132,12 @@ describe('iD.osmSimpleMultipolygonOuterMember', function() {
|
||||
});
|
||||
|
||||
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]);
|
||||
var way = iD.osmWay({id: 'w'});
|
||||
var relation = iD.osmRelation({id: 'r', tags: {type: 'multipolygon'}, members: [
|
||||
{id: 'o', role: 'outer'},
|
||||
{id: 'w', role: 'inner'}]
|
||||
});
|
||||
var graph = iD.coreGraph([way, relation]);
|
||||
|
||||
expect(iD.osmSimpleMultipolygonOuterMember(way, graph)).not.to.be.ok;
|
||||
});
|
||||
@@ -135,69 +145,280 @@ describe('iD.osmSimpleMultipolygonOuterMember', function() {
|
||||
|
||||
|
||||
describe('iD.osmJoinWays', function() {
|
||||
function getIDs(objects) {
|
||||
return objects.map(function(node) { return node.id; });
|
||||
}
|
||||
|
||||
it('returns an array of members with nodes properties', function() {
|
||||
var node = iD.Node({loc: [0, 0]}),
|
||||
way = iD.Way({nodes: [node.id]}),
|
||||
member = {id: way.id, type: 'way'},
|
||||
graph = iD.Graph([node, way]),
|
||||
result = iD.osmJoinWays([member], graph);
|
||||
var node = iD.osmNode({id: 'a', loc: [0, 0]});
|
||||
var way = iD.osmWay({id: '-', nodes: ['a']});
|
||||
var member = {id: '-', type: 'way'};
|
||||
var graph = iD.coreGraph([node, way]);
|
||||
|
||||
var result = iD.osmJoinWays([member], graph);
|
||||
|
||||
expect(result.length).to.equal(1);
|
||||
expect(result[0].nodes.length).to.equal(1);
|
||||
expect(result[0].nodes[0]).to.equal(node);
|
||||
expect(result.actions).to.eql([]);
|
||||
expect(getIDs(result[0].nodes)).to.eql(['a']);
|
||||
expect(result[0].length).to.equal(1);
|
||||
expect(result[0][0]).to.equal(member);
|
||||
expect(result[0][0]).to.eql(member);
|
||||
});
|
||||
|
||||
it('returns the members in the correct order', function() {
|
||||
// a<===b--->c~~~>d
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a', loc: [0, 0]}),
|
||||
iD.Node({id: 'b', loc: [0, 0]}),
|
||||
iD.Node({id: 'c', loc: [0, 0]}),
|
||||
iD.Node({id: 'd', loc: [0, 0]}),
|
||||
iD.Way({id: '=', nodes: ['b', 'a']}),
|
||||
iD.Way({id: '-', nodes: ['b', 'c']}),
|
||||
iD.Way({id: '~', nodes: ['c', 'd']}),
|
||||
iD.Relation({id: 'r', members: [
|
||||
{id: '-', type: 'way'},
|
||||
{id: '~', type: 'way'},
|
||||
{id: '=', type: 'way'}
|
||||
]})
|
||||
]);
|
||||
it('joins ways', function() {
|
||||
//
|
||||
// a ---> b ===> c
|
||||
//
|
||||
var a = iD.osmNode({id: 'a', loc: [0, 0]});
|
||||
var b = iD.osmNode({id: 'b', loc: [1, 0]});
|
||||
var c = iD.osmNode({id: 'c', loc: [2, 0]});
|
||||
var w1 = iD.osmWay({id: '-', nodes: ['a', 'b']});
|
||||
var w2 = iD.osmWay({id: '=', nodes: ['b', 'c']});
|
||||
var graph = iD.coreGraph([a, b, c, w1, w2]);
|
||||
|
||||
var result = iD.osmJoinWays(graph.entity('r').members, graph);
|
||||
var ids = result[0].map(function (w) { return w.id; });
|
||||
expect(ids).to.have.ordered.members(['=', '-', '~']);
|
||||
var result = iD.osmJoinWays([w1, w2], graph);
|
||||
expect(result.length).to.equal(1);
|
||||
expect(result.actions).to.eql([]);
|
||||
expect(getIDs(result[0].nodes)).to.eql(['a', 'b', 'c']);
|
||||
expect(result[0].length).to.equal(2);
|
||||
expect(result[0][0]).to.eql(w1);
|
||||
expect(result[0][1]).to.eql(w2);
|
||||
});
|
||||
|
||||
it('joins relation members', function() {
|
||||
//
|
||||
// a ---> b ===> c
|
||||
// r: ['-', '=']
|
||||
//
|
||||
var a = iD.osmNode({id: 'a', loc: [0, 0]});
|
||||
var b = iD.osmNode({id: 'b', loc: [1, 0]});
|
||||
var c = iD.osmNode({id: 'c', loc: [2, 0]});
|
||||
var w1 = iD.osmWay({id: '-', nodes: ['a', 'b']});
|
||||
var w2 = iD.osmWay({id: '=', nodes: ['b', 'c']});
|
||||
var r = iD.osmRelation({id: 'r', members: [
|
||||
{id: '-', type: 'way'},
|
||||
{id: '=', type: 'way'}
|
||||
]});
|
||||
var graph = iD.coreGraph([a, b, c, w1, w2, r]);
|
||||
|
||||
var result = iD.osmJoinWays(r.members, graph);
|
||||
expect(result.length).to.equal(1);
|
||||
expect(result.actions).to.eql([]);
|
||||
expect(getIDs(result[0].nodes)).to.eql(['a', 'b', 'c']);
|
||||
expect(result[0].length).to.equal(2);
|
||||
expect(result[0][0]).to.eql({id: '-', type: 'way'});
|
||||
expect(result[0][1]).to.eql({id: '=', type: 'way'});
|
||||
});
|
||||
|
||||
it('returns joined members in the correct order', function() {
|
||||
//
|
||||
// a <=== b ---> c ~~~> d
|
||||
// r: ['-', '~', '=']
|
||||
//
|
||||
var a = iD.osmNode({id: 'a', loc: [0, 0]});
|
||||
var b = iD.osmNode({id: 'b', loc: [1, 0]});
|
||||
var c = iD.osmNode({id: 'c', loc: [2, 0]});
|
||||
var d = iD.osmNode({id: 'd', loc: [3, 0]});
|
||||
var w1 = iD.osmWay({id: '-', nodes: ['b', 'c']});
|
||||
var w2 = iD.osmWay({id: '=', nodes: ['b', 'a']});
|
||||
var w3 = iD.osmWay({id: '~', nodes: ['c', 'd']});
|
||||
var r = iD.osmRelation({id: 'r', members: [
|
||||
{id: '-', type: 'way'},
|
||||
{id: '~', type: 'way'},
|
||||
{id: '=', type: 'way'}
|
||||
]});
|
||||
var graph = iD.coreGraph([a, b, c, d, w1, w2, w3, r]);
|
||||
|
||||
var result = iD.osmJoinWays(r.members, graph);
|
||||
expect(result.length).to.equal(1);
|
||||
expect(result.actions.length).to.equal(1);
|
||||
expect(getIDs(result[0].nodes)).to.eql(['a', 'b', 'c', 'd']);
|
||||
expect(result[0].length).to.equal(3);
|
||||
expect(result[0][0]).to.eql({id: '=', type: 'way'});
|
||||
expect(result[0][1]).to.eql({id: '-', type: 'way'});
|
||||
expect(result[0][2]).to.eql({id: '~', type: 'way'});
|
||||
});
|
||||
|
||||
it('reverses member tags of reversed segements', function() {
|
||||
// a --> b <== c
|
||||
// Expected result:
|
||||
// a --> b --> c
|
||||
// tags on === reversed
|
||||
var graph = iD.Graph([
|
||||
iD.Node({id: 'a'}),
|
||||
iD.Node({id: 'b'}),
|
||||
iD.Node({id: 'c'}),
|
||||
iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
iD.Way({id: '=', nodes: ['c', 'b'], tags: {'oneway': 'yes', 'lanes:forward': 2}})
|
||||
]);
|
||||
//
|
||||
// Source:
|
||||
// a ---> b <=== c
|
||||
// Result:
|
||||
// a ---> b ===> c (and === reversed)
|
||||
//
|
||||
var a = iD.osmNode({id: 'a', loc: [0, 0]});
|
||||
var b = iD.osmNode({id: 'b', loc: [1, 0]});
|
||||
var c = iD.osmNode({id: 'c', loc: [2, 0]});
|
||||
var w1 = iD.osmWay({id: '-', nodes: ['a', 'b']});
|
||||
var w2 = iD.osmWay({id: '=', nodes: ['c', 'b'], tags: {'oneway': 'yes', 'lanes:forward': 2}});
|
||||
var graph = iD.coreGraph([a, b, c, w1, w2]);
|
||||
|
||||
var result = iD.osmJoinWays([graph.entity('-'), graph.entity('=')], graph);
|
||||
var result = iD.osmJoinWays([w1, w2], graph);
|
||||
expect(result.length).to.equal(1);
|
||||
expect(result.actions.length).to.equal(1);
|
||||
expect(getIDs(result[0].nodes)).to.eql(['a', 'b', 'c']);
|
||||
expect(result[0].length).to.equal(2);
|
||||
expect(result[0][0]).to.eql(w1);
|
||||
expect(result[0][1]).to.be.an.instanceof(iD.osmWay);
|
||||
expect(result[0][1].nodes).to.eql(['b', 'c']);
|
||||
expect(result[0][1].tags).to.eql({'oneway': '-1', 'lanes:backward': 2});
|
||||
});
|
||||
|
||||
it('reverses the initial segment to preserve member order', function() {
|
||||
//
|
||||
// Source:
|
||||
// a <--- b ===> c
|
||||
// Result:
|
||||
// a ---> b ===> c (and --- reversed)
|
||||
//
|
||||
var a = iD.osmNode({id: 'a', loc: [0, 0]});
|
||||
var b = iD.osmNode({id: 'b', loc: [1, 0]});
|
||||
var c = iD.osmNode({id: 'c', loc: [2, 0]});
|
||||
var w1 = iD.osmWay({id: '-', nodes: ['b', 'a'], tags: {'oneway': 'yes', 'lanes:forward': 2}});
|
||||
var w2 = iD.osmWay({id: '=', nodes: ['b', 'c']});
|
||||
var graph = iD.coreGraph([a, b, c, w1, w2]);
|
||||
|
||||
var result = iD.osmJoinWays([w1, w2], graph);
|
||||
expect(result.length).to.equal(1);
|
||||
expect(result.actions.length).to.equal(1);
|
||||
expect(getIDs(result[0].nodes)).to.eql(['a', 'b', 'c']);
|
||||
expect(result[0].length).to.equal(2);
|
||||
expect(result[0][0]).to.be.an.instanceof(iD.osmWay);
|
||||
expect(result[0][0].nodes).to.eql(['a', 'b']);
|
||||
expect(result[0][0].tags).to.eql({'oneway': '-1', 'lanes:backward': 2});
|
||||
expect(result[0][1]).to.eql(w2);
|
||||
});
|
||||
|
||||
|
||||
it('ignores non-way members', function() {
|
||||
var node = iD.Node({loc: [0, 0]}),
|
||||
member = {id: 'n', type: 'node'},
|
||||
graph = iD.Graph([node]);
|
||||
var node = iD.osmNode({loc: [0, 0]});
|
||||
var member = {id: 'n', type: 'node'};
|
||||
var graph = iD.coreGraph([node]);
|
||||
expect(iD.osmJoinWays([member], graph)).to.eql([]);
|
||||
});
|
||||
|
||||
it('ignores incomplete members', function() {
|
||||
var member = {id: 'w', type: 'way'},
|
||||
graph = iD.Graph();
|
||||
var member = {id: 'w', type: 'way'};
|
||||
var graph = iD.coreGraph();
|
||||
expect(iD.osmJoinWays([member], graph)).to.eql([]);
|
||||
});
|
||||
|
||||
it('returns multiple arrays for disjoint ways', function() {
|
||||
//
|
||||
// b
|
||||
// / \
|
||||
// a c d ---> e ===> f
|
||||
//
|
||||
var a = iD.osmNode({id: 'a', loc: [0, 0]});
|
||||
var b = iD.osmNode({id: 'b', loc: [1, 1]});
|
||||
var c = iD.osmNode({id: 'c', loc: [2, 0]});
|
||||
var d = iD.osmNode({id: 'd', loc: [5, 0]});
|
||||
var e = iD.osmNode({id: 'e', loc: [6, 0]});
|
||||
var f = iD.osmNode({id: 'f', loc: [7, 0]});
|
||||
var w1 = iD.osmWay({id: '/', nodes: ['a', 'b']});
|
||||
var w2 = iD.osmWay({id: '\\', nodes: ['b', 'c']});
|
||||
var w3 = iD.osmWay({id: '-', nodes: ['d', 'e']});
|
||||
var w4 = iD.osmWay({id: '=', nodes: ['e', 'f']});
|
||||
var graph = iD.coreGraph([a, b, c, d, e, f, w1, w2, w3, w4]);
|
||||
|
||||
var result = iD.osmJoinWays([w1, w2, w3, w4], graph);
|
||||
|
||||
expect(result.length).to.equal(2);
|
||||
expect(result.actions).to.eql([]);
|
||||
|
||||
expect(result[0].length).to.equal(2);
|
||||
expect(getIDs(result[0].nodes)).to.eql(['a', 'b', 'c']);
|
||||
expect(result[0][0]).to.eql(w1);
|
||||
expect(result[0][1]).to.eql(w2);
|
||||
|
||||
expect(result[1].length).to.equal(2);
|
||||
expect(getIDs(result[1].nodes)).to.eql(['d', 'e', 'f']);
|
||||
expect(result[1][0]).to.eql(w3);
|
||||
expect(result[1][1]).to.eql(w4);
|
||||
});
|
||||
|
||||
it('returns multiple arrays for disjoint relations', function() {
|
||||
//
|
||||
// b
|
||||
// / \
|
||||
// a c d ---> e ===> f
|
||||
//
|
||||
// r: ['/', '\', '-', '=']
|
||||
//
|
||||
var a = iD.osmNode({id: 'a', loc: [0, 0]});
|
||||
var b = iD.osmNode({id: 'b', loc: [1, 1]});
|
||||
var c = iD.osmNode({id: 'c', loc: [2, 0]});
|
||||
var d = iD.osmNode({id: 'd', loc: [5, 0]});
|
||||
var e = iD.osmNode({id: 'e', loc: [6, 0]});
|
||||
var f = iD.osmNode({id: 'f', loc: [7, 0]});
|
||||
var w1 = iD.osmWay({id: '/', nodes: ['a', 'b']});
|
||||
var w2 = iD.osmWay({id: '\\', nodes: ['b', 'c']});
|
||||
var w3 = iD.osmWay({id: '-', nodes: ['d', 'e']});
|
||||
var w4 = iD.osmWay({id: '=', nodes: ['e', 'f']});
|
||||
var r = iD.osmRelation({id: 'r', members: [
|
||||
{id: '/', type: 'way'},
|
||||
{id: '\\', type: 'way'},
|
||||
{id: '-', type: 'way'},
|
||||
{id: '=', type: 'way'}
|
||||
]});
|
||||
var graph = iD.coreGraph([a, b, c, d, e, f, w1, w2, w3, w4, r]);
|
||||
var result = iD.osmJoinWays(r.members, graph);
|
||||
|
||||
expect(result.length).to.equal(2);
|
||||
expect(result.actions).to.eql([]);
|
||||
|
||||
expect(result[0].length).to.equal(2);
|
||||
expect(getIDs(result[0].nodes)).to.eql(['a', 'b', 'c']);
|
||||
expect(result[0][0]).to.eql({id: '/', type: 'way'});
|
||||
expect(result[0][1]).to.eql({id: '\\', type: 'way'});
|
||||
|
||||
expect(result[1].length).to.equal(2);
|
||||
expect(getIDs(result[1].nodes)).to.eql(['d', 'e', 'f']);
|
||||
expect(result[1][0]).to.eql({id: '-', type: 'way'});
|
||||
expect(result[1][1]).to.eql({id: '=', type: 'way'});
|
||||
});
|
||||
|
||||
it('understands doubled-back relation members', function() {
|
||||
//
|
||||
// e
|
||||
// / \
|
||||
// a <=== b ---> c ~~~> d
|
||||
//
|
||||
// r: ['=', '-', '~', '\', '/', '-', '=']
|
||||
//
|
||||
var a = iD.osmNode({id: 'a', loc: [0, 0]});
|
||||
var b = iD.osmNode({id: 'b', loc: [1, 0]});
|
||||
var c = iD.osmNode({id: 'c', loc: [2, 0]});
|
||||
var d = iD.osmNode({id: 'd', loc: [4, 0]});
|
||||
var e = iD.osmNode({id: 'e', loc: [3, 1]});
|
||||
var w1 = iD.osmWay({id: '=', nodes: ['b', 'a']});
|
||||
var w2 = iD.osmWay({id: '-', nodes: ['b', 'c']});
|
||||
var w3 = iD.osmWay({id: '~', nodes: ['c', 'd']});
|
||||
var w4 = iD.osmWay({id: '\\', nodes: ['d', 'e']});
|
||||
var w5 = iD.osmWay({id: '/', nodes: ['c', 'e']});
|
||||
var r = iD.osmRelation({id: 'r', members: [
|
||||
{id: '=', type: 'way'},
|
||||
{id: '-', type: 'way'},
|
||||
{id: '~', type: 'way'},
|
||||
{id: '\\', type: 'way'},
|
||||
{id: '/', type: 'way'},
|
||||
{id: '-', type: 'way'},
|
||||
{id: '=', type: 'way'}
|
||||
]});
|
||||
var graph = iD.coreGraph([a, b, c, d, e, w1, w2, w3, w4, w5, r]);
|
||||
|
||||
var result = iD.osmJoinWays(r.members, graph);
|
||||
expect(result.length).to.equal(1);
|
||||
expect(result.actions.length).to.equal(3);
|
||||
|
||||
expect(getIDs(result[0].nodes)).to.eql(['a', 'b', 'c', 'd', 'e', 'c', 'b', 'a']);
|
||||
expect(result[0].length).to.equal(7);
|
||||
expect(result[0][0]).to.eql({id: '=', type: 'way'});
|
||||
expect(result[0][1]).to.eql({id: '-', type: 'way'});
|
||||
expect(result[0][2]).to.eql({id: '~', type: 'way'});
|
||||
expect(result[0][3]).to.eql({id: '\\', type: 'way'});
|
||||
expect(result[0][4]).to.eql({id: '/', type: 'way'});
|
||||
expect(result[0][5]).to.eql({id: '-', type: 'way'});
|
||||
expect(result[0][6]).to.eql({id: '=', type: 'way'});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -258,24 +258,37 @@ describe('iD.osmRelation', function () {
|
||||
|
||||
it('replaces a member which doesn\'t already exist', function () {
|
||||
var r = iD.Relation({members: [{id: 'a', role: 'a'}]});
|
||||
expect(r.replaceMember({id: 'a'}, {id: 'b', type: 'node'}).members).to.eql([{id: 'b', role: 'a', type: 'node'}]);
|
||||
expect(r.replaceMember({id: 'a'}, {id: 'b', type: 'node'}).members)
|
||||
.to.eql([{id: 'b', role: 'a', type: 'node'}]);
|
||||
});
|
||||
|
||||
it('preserves the existing role', function () {
|
||||
var r = iD.Relation({members: [{id: 'a', role: 'a', type: 'node'}]});
|
||||
expect(r.replaceMember({id: 'a'}, {id: 'b', type: 'node'}).members).to.eql([{id: 'b', role: 'a', type: 'node'}]);
|
||||
expect(r.replaceMember({id: 'a'}, {id: 'b', type: 'node'}).members)
|
||||
.to.eql([{id: 'b', role: 'a', type: 'node'}]);
|
||||
});
|
||||
|
||||
it('uses the replacement type', function () {
|
||||
var r = iD.Relation({members: [{id: 'a', role: 'a', type: 'node'}]});
|
||||
expect(r.replaceMember({id: 'a'}, {id: 'b', type: 'way'}).members).to.eql([{id: 'b', role: 'a', type: 'way'}]);
|
||||
expect(r.replaceMember({id: 'a'}, {id: 'b', type: 'way'}).members)
|
||||
.to.eql([{id: 'b', role: 'a', type: 'way'}]);
|
||||
});
|
||||
|
||||
it('removes members if replacing them would produce duplicates', function () {
|
||||
var r = iD.Relation({members: [
|
||||
{id: 'a', role: 'b', type: 'node'},
|
||||
{id: 'b', role: 'b', type: 'node'}]});
|
||||
expect(r.replaceMember({id: 'a'}, {id: 'b', type: 'node'}).members).to.eql([{id: 'b', role: 'b', type: 'node'}]);
|
||||
{id: 'b', role: 'b', type: 'node'}
|
||||
]});
|
||||
expect(r.replaceMember({id: 'a'}, {id: 'b', type: 'node'}).members)
|
||||
.to.eql([{id: 'b', role: 'b', type: 'node'}]);
|
||||
});
|
||||
it('keeps duplicate members if `keepDuplicates = true`', function () {
|
||||
var r = iD.Relation({members: [
|
||||
{id: 'a', role: 'b', type: 'node'},
|
||||
{id: 'b', role: 'b', type: 'node'}
|
||||
]});
|
||||
expect(r.replaceMember({id: 'a'}, {id: 'b', type: 'node'}, true).members)
|
||||
.to.eql([{id: 'b', role: 'b', type: 'node'}, {id: 'b', role: 'b', type: 'node'}]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user