Files
iD/test/spec/actions/split.js
2018-01-09 23:57:44 -05:00

678 lines
26 KiB
JavaScript

describe('iD.actionSplit', function () {
beforeEach(function () {
iD.areaKeys = iD.coreContext().presets().areaKeys();
});
describe('#disabled', function () {
it('returns falsy for a non-end node of a single way', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']})
]);
expect(iD.actionSplit('b').disabled(graph)).not.to.be.ok;
});
it('returns falsy for an intersection of two ways', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: '*'}),
iD.osmWay({id: '-', nodes: ['a', '*', 'b']}),
iD.osmWay({id: '|', nodes: ['c', '*', 'd']})
]);
expect(iD.actionSplit('*').disabled(graph)).not.to.be.ok;
});
it('returns falsy for an intersection of two ways with parent way specified', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: '*'}),
iD.osmWay({id: '-', nodes: ['a', '*', 'b']}),
iD.osmWay({id: '|', nodes: ['c', '*', 'd']})
]);
expect(iD.actionSplit('*').limitWays(['-']).disabled(graph)).not.to.be.ok;
});
it('returns falsy for a self-intersection', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c', 'a', 'd']})
]);
expect(iD.actionSplit('a').disabled(graph)).not.to.be.ok;
});
it('returns \'not_eligible\' for the first node of a single way', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmWay({id: '-', nodes: ['a', 'b']})
]);
expect(iD.actionSplit('a').disabled(graph)).to.equal('not_eligible');
});
it('returns \'not_eligible\' for the last node of a single way', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmWay({id: '-', nodes: ['a', 'b']})
]);
expect(iD.actionSplit('b').disabled(graph)).to.equal('not_eligible');
});
it('returns \'not_eligible\' for an intersection of two ways with non-parent way specified', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: '*'}),
iD.osmWay({id: '-', nodes: ['a', '*', 'b']}),
iD.osmWay({id: '|', nodes: ['c', '*', 'd']})
]);
expect(iD.actionSplit('*').limitWays(['-', '=']).disabled(graph)).to.equal('not_eligible');
});
});
describe('ways', function () {
it('creates a new way with the appropriate nodes', function () {
// Situation:
// a ---- b ---- c
//
// Split at b.
//
// Expected result:
// a ---- b ==== c
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']})
]);
graph = iD.actionSplit('b', ['='])(graph);
expect(graph.entity('-').nodes).to.eql(['a', 'b']);
expect(graph.entity('=').nodes).to.eql(['b', 'c']);
});
it('copies tags to the new way', function () {
var tags = {highway: 'residential'};
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c'], tags: tags})
]);
graph = iD.actionSplit('b', ['='])(graph);
// Immutable tags => should be shared by identity.
expect(graph.entity('-').tags).to.equal(tags);
expect(graph.entity('=').tags).to.equal(tags);
});
it('splits a way at a T-junction', function () {
// Situation:
// a ---- b ---- c
// |
// d
//
// Split at b.
//
// Expected result:
// a ---- b ==== 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', 'c']}),
iD.osmWay({id: '|', nodes: ['d', 'b']})
]);
graph = iD.actionSplit('b', ['='])(graph);
expect(graph.entity('-').nodes).to.eql(['a', 'b']);
expect(graph.entity('=').nodes).to.eql(['b', 'c']);
expect(graph.entity('|').nodes).to.eql(['d', 'b']);
});
it('splits multiple ways at an intersection', function () {
// Situation:
// c
// |
// a ---- * ---- b
// ¦
// d
//
// Split at b.
//
// Expected result:
// c
// |
// a ---- * ==== b
// ¦
// d
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: '*'}),
iD.osmWay({id: '-', nodes: ['a', '*', 'b']}),
iD.osmWay({id: '|', nodes: ['c', '*', 'd']})
]);
graph = iD.actionSplit('*', ['=', '¦'])(graph);
expect(graph.entity('-').nodes).to.eql(['a', '*']);
expect(graph.entity('=').nodes).to.eql(['*', 'b']);
expect(graph.entity('|').nodes).to.eql(['c', '*']);
expect(graph.entity('¦').nodes).to.eql(['*', 'd']);
});
it('splits the specified ways at an intersection', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: '*'}),
iD.osmWay({id: '-', nodes: ['a', '*', 'b']}),
iD.osmWay({id: '|', nodes: ['c', '*', 'd']})
]);
var g1 = iD.actionSplit('*', ['=']).limitWays(['-'])(graph);
expect(g1.entity('-').nodes).to.eql(['a', '*']);
expect(g1.entity('=').nodes).to.eql(['*', 'b']);
expect(g1.entity('|').nodes).to.eql(['c', '*', 'd']);
var g2 = iD.actionSplit('*', ['¦']).limitWays(['|'])(graph);
expect(g2.entity('-').nodes).to.eql(['a', '*', 'b']);
expect(g2.entity('|').nodes).to.eql(['c', '*']);
expect(g2.entity('¦').nodes).to.eql(['*', 'd']);
var g3 = iD.actionSplit('*', ['=', '¦']).limitWays(['-', '|'])(graph);
expect(g3.entity('-').nodes).to.eql(['a', '*']);
expect(g3.entity('=').nodes).to.eql(['*', 'b']);
expect(g3.entity('|').nodes).to.eql(['c', '*']);
expect(g3.entity('¦').nodes).to.eql(['*', 'd']);
});
it('splits self-intersecting ways', function () {
// Situation:
// b
// / |
// / |
// c - a -- d
//
// Split at a.
//
// Expected result:
// b
// / |
// / |
// c - a == d
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c', 'a', 'd']})
]);
graph = iD.actionSplit('a', ['='])(graph);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c', 'a']);
expect(graph.entity('=').nodes).to.eql(['a', 'd']);
});
it('splits a closed way at the given point and its antipode', function () {
// Situation:
// a ---- b
// | |
// d ---- c
//
// Split at a.
//
// Expected result:
// a ---- b
// || |
// d ==== c
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a', loc: [0,1]}),
iD.osmNode({id: 'b', loc: [1,1]}),
iD.osmNode({id: 'c', loc: [1,0]}),
iD.osmNode({id: 'd', loc: [0,0]}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
var g1 = iD.actionSplit('a', ['='])(graph);
expect(g1.entity('-').nodes).to.eql(['a', 'b', 'c']);
expect(g1.entity('=').nodes).to.eql(['c', 'd', 'a']);
var g2 = iD.actionSplit('b', ['='])(graph);
expect(g2.entity('-').nodes).to.eql(['b', 'c', 'd']);
expect(g2.entity('=').nodes).to.eql(['d', 'a', 'b']);
var g3 = iD.actionSplit('c', ['='])(graph);
expect(g3.entity('-').nodes).to.eql(['c', 'd', 'a']);
expect(g3.entity('=').nodes).to.eql(['a', 'b', 'c']);
var g4 = iD.actionSplit('d', ['='])(graph);
expect(g4.entity('-').nodes).to.eql(['d', 'a', 'b']);
expect(g4.entity('=').nodes).to.eql(['b', 'c', 'd']);
});
});
describe('relations', function () {
it('handles incomplete relations', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmRelation({id: 'r', members: [{id: '~', type: 'way'}, {id: '-', type: 'way'}]})
]);
graph = iD.actionSplit('b', ['='])(graph);
var ids = graph.entity('r').members.map(function(m) { return m.id; });
expect(ids).to.have.ordered.members(['~', '-', '=']);
});
describe('member ordering', function () {
it('adds the new way to parent relations (no connections)', function () {
// Situation:
// a ---- b ---- c
// Relation: [----]
//
// Split at b.
//
// Expected result:
// a ---- b ==== c
// Relation: [----, ====]
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmRelation({id: 'r', members: [{id: '-', type: 'way', role: 'forward'}]})
]);
graph = iD.actionSplit('b', ['='])(graph);
expect(graph.entity('r').members).to.eql([
{id: '-', type: 'way', role: 'forward'},
{id: '=', type: 'way', role: 'forward'}
]);
});
it('adds the new way to parent relations (forward order)', function () {
// Situation:
// a ---- b ---- c ~~~~ d
// Relation: [----, ~~~~]
//
// Split at b.
//
// Expected result:
// a ---- b ==== c ~~~~ d
// Relation: [----, ====, ~~~~]
//
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: ['c', 'd']}),
iD.osmRelation({id: 'r', members: [{id: '-', type: 'way'}, {id: '~', type: 'way'}]})
]);
graph = iD.actionSplit('b', ['='])(graph);
var ids = graph.entity('r').members.map(function(m) { return m.id; });
expect(ids).to.have.ordered.members(['-', '=', '~']);
});
it('adds the new way to parent relations (reverse order)', function () {
// Situation:
// a ---- b ---- c ~~~~ d
// Relation: [~~~~, ----]
//
// Split at b.
//
// Expected result:
// a ---- b ==== c ~~~~ d
// Relation: [~~~~, ====, ----]
//
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: ['c', 'd']}),
iD.osmRelation({id: 'r', members: [{id: '~', type: 'way'}, {id: '-', type: 'way'}]})
]);
graph = iD.actionSplit('b', ['='])(graph);
var ids = graph.entity('r').members.map(function(m) { return m.id; });
expect(ids).to.have.ordered.members(['~', '=', '-']);
});
it('adds the new way to parent relations (unsplit way belongs multiple times)', function () {
// Situation:
// a ---- b ---- c ~~~~ d
// Relation: [~~~~, ----, ~~~~]
//
// Split at b.
//
// Expected result:
// a ---- b ==== c ~~~~ d
// Relation: [~~~~, ====, ----, ====, ~~~~]
//
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: ['c', 'd']}),
iD.osmRelation({id: 'r', members: [
{id: '~', type: 'way'},
{id: '-', type: 'way'},
{id: '~', type: 'way'}
]})
]);
graph = iD.actionSplit('b', ['='])(graph);
var ids = graph.entity('r').members.map(function(m) { return m.id; });
expect(ids).to.have.ordered.members(['~', '=', '-', '=', '~']);
});
it('adds the new way to parent relations (split way belongs multiple times)', function () {
// Situation:
// a ---- b ---- c ~~~~ d
// Relation: [----, ~~~~, ----]
//
// Split at b.
//
// Expected result:
// a ---- b ==== c ~~~~ d
// Relation: [----, ====, ~~~~, ====, ----]
//
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: ['c', 'd']}),
iD.osmRelation({id: 'r', members: [
{id: '-', type: 'way'},
{id: '~', type: 'way'},
{id: '-', type: 'way'}
]})
]);
graph = iD.actionSplit('b', ['='])(graph);
var ids = graph.entity('r').members.map(function(m) { return m.id; });
expect(ids).to.have.ordered.members(['-', '=', '~', '=', '-']);
});
});
describe('type = multipolygon', function () {
it('splits an area by converting it to a multipolygon', function () {
// Situation:
// a ---- b
// | |
// d ---- c
//
// Split at a.
//
// Expected result:
// a ---- b
// || |
// d ==== c
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a', loc: [0,1]}),
iD.osmNode({id: 'b', loc: [1,1]}),
iD.osmNode({id: 'c', loc: [1,0]}),
iD.osmNode({id: 'd', loc: [0,0]}),
iD.osmWay({id: '-', tags: {building: 'yes'}, nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionSplit('a', ['='])(graph);
expect(graph.entity('-').tags).to.eql({});
expect(graph.entity('=').tags).to.eql({});
expect(graph.parentRelations(graph.entity('-'))).to.have.length(1);
var relation = graph.parentRelations(graph.entity('-'))[0];
expect(relation.tags).to.eql({type: 'multipolygon', building: 'yes'});
expect(relation.members).to.eql([
{id: '-', role: 'outer', type: 'way'},
{id: '=', role: 'outer', type: 'way'}
]);
});
it('splits only the line of a node shared by a line and an area', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a', loc: [0,1]}),
iD.osmNode({id: 'b', loc: [1,1]}),
iD.osmNode({id: 'c', loc: [1,0]}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmWay({id: '=', nodes: ['a', 'b', 'c', 'a'], tags: {area: 'yes'}})
]);
graph = iD.actionSplit('b', ['~'])(graph);
expect(graph.entity('-').nodes).to.eql(['a', 'b']);
expect(graph.entity('~').nodes).to.eql(['b', 'c']);
expect(graph.entity('=').nodes).to.eql(['a', 'b', 'c', 'a']);
expect(graph.parentRelations(graph.entity('='))).to.have.length(0);
});
it('converts simple multipolygon to a proper multipolygon', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({'id': '-', nodes: ['a', 'b', 'c'], tags: {natural: 'water'}}),
iD.osmRelation({id: 'r', members: [{id: '-', type: 'way', role: 'outer'}], tags: {type: 'multipolygon'}})
]);
graph = iD.actionSplit('b', ['='])(graph);
expect(graph.entity('-').tags).to.eql({});
expect(graph.entity('r').tags).to.eql({type: 'multipolygon', natural: 'water'});
var ids = graph.entity('r').members.map(function(m) { return m.id; });
expect(ids).to.have.ordered.members(['-', '=']);
});
});
['restriction', 'restriction:bus'].forEach(function (type) {
describe('type = ' + type, function () {
it('updates a restriction\'s \'from\' role', function () {
// Situation:
// a ----> b ----> c ~~~~ d
// A restriction from ---- to ~~~~ via c.
//
// Split at b.
//
// Expected result:
// a ----> b ====> c ~~~~ d
// A restriction from ==== to ~~~~ via c.
//
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: ['c', 'd']}),
iD.osmRelation({id: 'r', tags: {type: type}, members: [
{id: '-', role: 'from', type: 'way'},
{id: '~', role: 'to', type: 'way'},
{id: 'c', role: 'via', type: 'node'}
]})
]);
graph = iD.actionSplit('b', ['='])(graph);
expect(graph.entity('r').members).to.eql([
{id: '=', role: 'from', type: 'way'},
{id: '~', role: 'to', type: 'way'},
{id: 'c', role: 'via', type: 'node'}
]);
});
it('updates a restriction\'s \'to\' role', function () {
// Situation:
// a ----> b ----> c ~~~~ d
// A restriction from ~~~~ to ---- via c.
//
// Split at b.
//
// Expected result:
// a ----> b ====> c ~~~~ d
// A restriction from ~~~~ to ==== via c.
//
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: ['c', 'd']}),
iD.osmRelation({id: 'r', tags: {type: type}, members: [
{id: '~', role: 'from', type: 'way'},
{id: '-', role: 'to', type: 'way'},
{id: 'c', role: 'via', type: 'node'}
]})
]);
graph = iD.actionSplit('b', ['='])(graph);
expect(graph.entity('r').members).to.eql([
{id: '~', role: 'from', type: 'way'},
{id: '=', role: 'to', type: 'way'},
{id: 'c', role: 'via', type: 'node'}
]);
});
it('updates both \'to\' and \'from\' roles for u-turn restrictions', function () {
// Situation:
// a ----> b ----> c ~~~~ d
// A restriction from ---- to ---- via c.
//
// Split at b.
//
// Expected result:
// a ----> b ====> c ~~~~ d
// A restriction from ==== to ==== via c.
//
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: ['c', 'd']}),
iD.osmRelation({id: 'r', tags: {type: type}, members: [
{id: '-', role: 'from', type: 'way'},
{id: '-', role: 'to', type: 'way'},
{id: 'c', role: 'via', type: 'node'}
]})
]);
graph = iD.actionSplit('b', ['='])(graph);
expect(graph.entity('r').members).to.eql([
{id: '=', role: 'from', type: 'way'},
{id: '=', role: 'to', type: 'way'},
{id: 'c', role: 'via', type: 'node'}
]);
});
it('leaves unaffected restrictions unchanged', function () {
// Situation:
// a <---- b <---- c ~~~~ d
// A restriction from ---- to ~~~~ via c.
//
// Split at b.
//
// Expected result:
// a <==== b <---- c ~~~~ d
// A restriction from ---- to ~~~~ via c.
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'd'}),
iD.osmWay({id: '-', nodes: ['c', 'b', 'a']}),
iD.osmWay({id: '~', nodes: ['c', 'd']}),
iD.osmRelation({id: 'r', tags: {type: type}, members: [
{id: '-', role: 'from', type: 'way'},
{id: '~', role: 'to', type: 'way'},
{id: 'c', role: 'via', type: 'node'}
]})
]);
graph = iD.actionSplit('b', ['='])(graph);
expect(graph.entity('r').members).to.eql([
{id: '-', role: 'from', type: 'way'},
{id: '~', role: 'to', type: 'way'},
{id: 'c', role: 'via', type: 'node'}
]);
});
});
});
});
});