mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-27 16:03:52 +00:00
iD.actions.Join
This commit is contained in:
@@ -81,6 +81,7 @@
|
||||
<script src="js/id/actions/delete_relation.js"></script>
|
||||
<script src="js/id/actions/delete_way.js"></script>
|
||||
<script src='js/id/actions/disconnect.js'></script>
|
||||
<script src='js/id/actions/join.js'></script>
|
||||
<script src='js/id/actions/move_node.js'></script>
|
||||
<script src='js/id/actions/move_way.js'></script>
|
||||
<script src='js/id/actions/circularize.js'></script>
|
||||
|
||||
65
js/id/actions/join.js
Normal file
65
js/id/actions/join.js
Normal file
@@ -0,0 +1,65 @@
|
||||
// Join ways at the end node they share.
|
||||
//
|
||||
// This is the inverse of `iD.actions.Split`.
|
||||
//
|
||||
// Reference:
|
||||
// https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
|
||||
// https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
|
||||
//
|
||||
iD.actions.Join = function(idA, idB) {
|
||||
var action = function(graph) {
|
||||
var a = graph.entity(idA),
|
||||
b = graph.entity(idB),
|
||||
nodes, tags;
|
||||
|
||||
if (a.first() === b.first()) {
|
||||
// a <-- b ==> c
|
||||
// Expected result:
|
||||
// a <-- b <-- c
|
||||
nodes = b.nodes.slice().reverse().concat(a.nodes.slice(1));
|
||||
|
||||
} else if (a.first() === b.last()) {
|
||||
// a <-- b <== c
|
||||
// Expected result:
|
||||
// a <-- b <-- c
|
||||
nodes = b.nodes.concat(a.nodes.slice(1));
|
||||
|
||||
} else if (a.last() === b.first()) {
|
||||
// a --> b ==> c
|
||||
// Expected result:
|
||||
// a --> b --> c
|
||||
nodes = a.nodes.concat(b.nodes.slice(1));
|
||||
|
||||
} else if (a.last() === b.last()) {
|
||||
// a --> b <== c
|
||||
// Expected result:
|
||||
// a --> b --> c
|
||||
nodes = a.nodes.concat(b.nodes.slice().reverse().slice(1));
|
||||
}
|
||||
|
||||
graph.parentRelations(b)
|
||||
.forEach(function (parent) {
|
||||
var memberA = parent.memberById(idA),
|
||||
memberB = parent.memberById(idB);
|
||||
if (!memberA) {
|
||||
graph = graph.replace(parent.addMember({id: idA, role: memberB.role}));
|
||||
}
|
||||
});
|
||||
|
||||
graph = graph.replace(a.mergeTags(b.tags).update({nodes: nodes}));
|
||||
graph = iD.actions.DeleteWay(idB)(graph);
|
||||
|
||||
return graph;
|
||||
};
|
||||
|
||||
action.enabled = function(graph) {
|
||||
var a = graph.entity(idA),
|
||||
b = graph.entity(idB);
|
||||
return a.first() === b.first() ||
|
||||
a.first() === b.last() ||
|
||||
a.last() === b.first() ||
|
||||
a.last() === b.last();
|
||||
};
|
||||
|
||||
return action;
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
// Split a way at the given node.
|
||||
//
|
||||
// This is the inverse of `iD.actions.Join`.
|
||||
//
|
||||
// For testing convenience, accepts an ID to assign to the new way.
|
||||
// Normally, this will be undefined and the way will automatically
|
||||
// be assigned a new ID.
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
<script src="../js/id/actions/delete_relation.js"></script>
|
||||
<script src="../js/id/actions/delete_way.js"></script>
|
||||
<script src='../js/id/actions/disconnect.js'></script>
|
||||
<script src='../js/id/actions/join.js'></script>
|
||||
<script src='../js/id/actions/move_node.js'></script>
|
||||
<script src='../js/id/actions/move_way.js'></script>
|
||||
<script src='../js/id/actions/noop.js'></script>
|
||||
@@ -147,6 +148,7 @@
|
||||
<script src="spec/actions/delete_relation.js"></script>
|
||||
<script src="spec/actions/delete_way.js"></script>
|
||||
<script src='spec/actions/disconnect.js'></script>
|
||||
<script src="spec/actions/join.js"></script>
|
||||
<script src="spec/actions/move_node.js"></script>
|
||||
<script src="spec/actions/move_way.js"></script>
|
||||
<script src="spec/actions/noop.js"></script>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<script src="spec/actions/delete_relation.js"></script>
|
||||
<script src="spec/actions/delete_way.js"></script>
|
||||
<script src='spec/actions/disconnect.js'></script>
|
||||
<script src="spec/actions/join.js"></script>
|
||||
<script src="spec/actions/move_node.js"></script>
|
||||
<script src="spec/actions/move_way.js"></script>
|
||||
<script src="spec/actions/noop.js"></script>
|
||||
|
||||
172
test/spec/actions/join.js
Normal file
172
test/spec/actions/join.js
Normal file
@@ -0,0 +1,172 @@
|
||||
describe("iD.actions.Join", function () {
|
||||
describe("#enabled", function () {
|
||||
it("returns true for ways that share an end/start node", function () {
|
||||
// a --> b ==> c
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
'=': iD.Way({id: '=', nodes: ['b', 'c']})
|
||||
});
|
||||
|
||||
expect(iD.actions.Join('-', '=').enabled(graph)).to.be.true;
|
||||
});
|
||||
|
||||
it("returns true for ways that share a start/end node", function () {
|
||||
// a <-- b <== c
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'-': iD.Way({id: '-', nodes: ['b', 'a']}),
|
||||
'=': iD.Way({id: '=', nodes: ['c', 'b']})
|
||||
});
|
||||
|
||||
expect(iD.actions.Join('-', '=').enabled(graph)).to.be.true;
|
||||
});
|
||||
|
||||
it("returns true for ways that share a start/start node", function () {
|
||||
// a <-- b ==> c
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'-': iD.Way({id: '-', nodes: ['b', 'a']}),
|
||||
'=': iD.Way({id: '=', nodes: ['b', 'c']})
|
||||
});
|
||||
|
||||
expect(iD.actions.Join('-', '=').enabled(graph)).to.be.true;
|
||||
});
|
||||
|
||||
it("returns true for ways that share an end/end node", function () {
|
||||
// a --> b <== c
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
'=': iD.Way({id: '=', nodes: ['c', 'b']})
|
||||
});
|
||||
|
||||
expect(iD.actions.Join('-', '=').enabled(graph)).to.be.true;
|
||||
});
|
||||
|
||||
it("returns false for ways that don't share the necessary nodes", function () {
|
||||
// a -- b -- c
|
||||
// |
|
||||
// d
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'd': iD.Node({id: 'd'}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b', 'c']}),
|
||||
'=': iD.Way({id: '=', nodes: ['b', 'd']})
|
||||
});
|
||||
|
||||
expect(iD.actions.Join('-', '=').enabled(graph)).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
it("joins a --> b ==> c", function () {
|
||||
// Expected result:
|
||||
// a --> b --> c
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
'=': iD.Way({id: '=', nodes: ['b', 'c']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Join('-', '=')(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c']);
|
||||
expect(graph.entity('=')).to.be.undefined;
|
||||
});
|
||||
|
||||
it("joins a <-- b <== c", function () {
|
||||
// Expected result:
|
||||
// a <-- b <-- c
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'-': iD.Way({id: '-', nodes: ['b', 'a']}),
|
||||
'=': iD.Way({id: '=', nodes: ['c', 'b']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Join('-', '=')(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.eql(['c', 'b', 'a']);
|
||||
expect(graph.entity('=')).to.be.undefined;
|
||||
});
|
||||
|
||||
it("joins a <-- b ==> c", function () {
|
||||
// Expected result:
|
||||
// a <-- b <-- c
|
||||
// tags on === reversed
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'-': iD.Way({id: '-', nodes: ['b', 'a']}),
|
||||
'=': iD.Way({id: '=', nodes: ['b', 'c']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Join('-', '=')(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.eql(['c', 'b', 'a']);
|
||||
expect(graph.entity('=')).to.be.undefined;
|
||||
});
|
||||
|
||||
it("joins a --> b <== c", function () {
|
||||
// Expected result:
|
||||
// a --> b --> c
|
||||
// tags on === reversed
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
'=': iD.Way({id: '=', nodes: ['c', 'b']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Join('-', '=')(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c']);
|
||||
expect(graph.entity('=')).to.be.undefined;
|
||||
});
|
||||
|
||||
it("merges tags", function () {
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b'], tags: {a: 'a', b: '-', c: 'c'}}),
|
||||
'=': iD.Way({id: '=', nodes: ['b', 'c'], tags: {a: 'a', b: '=', d: 'd'}})
|
||||
});
|
||||
|
||||
graph = iD.actions.Join('-', '=')(graph);
|
||||
|
||||
expect(graph.entity('-').tags).to.eql({a: 'a', b: '-; =', c: 'c', d: 'd'});
|
||||
});
|
||||
|
||||
it("merges relations", function () {
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a'}),
|
||||
'b': iD.Node({id: 'b'}),
|
||||
'c': iD.Node({id: 'c'}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b']}),
|
||||
'=': iD.Way({id: '=', nodes: ['b', 'c']}),
|
||||
'r1': iD.Relation({id: 'r1', members: [{id: '=', role: 'r1'}]}),
|
||||
'r2': iD.Relation({id: 'r2', members: [{id: '=', role: 'r1'}, {id: '-', role: 'r2'}]})
|
||||
});
|
||||
|
||||
graph = iD.actions.Join('-', '=')(graph);
|
||||
|
||||
expect(graph.entity('r1').members).to.eql([{id: '-', role: 'r1'}]);
|
||||
expect(graph.entity('r2').members).to.eql([{id: '-', role: 'r2'}]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user