UnjoinNode action (fixes #442)

This commit is contained in:
John Firebaugh
2013-01-23 10:03:05 -05:00
parent df06148355
commit 29d608970b
6 changed files with 135 additions and 1 deletions
+40
View File
@@ -0,0 +1,40 @@
// Unjoin the ways at the given node.
//
// For testing convenience, accepts an ID to assign to the (first) new node.
// Normally, this will be undefined and the way will automatically
// be assigned a new ID.
//
// Reference:
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
// https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
//
iD.actions.UnjoinNode = function(nodeId, newNodeId) {
var action = function(graph) {
if (!action.permitted(graph))
return graph;
var node = graph.entity(nodeId);
graph.parentWays(node).forEach(function(parent, i) {
if (i === 0)
return;
var index = parent.nodes.indexOf(nodeId),
newNode = iD.Node({id: newNodeId, loc: node.loc, tags: node.tags}),
nodes = parent.nodes.slice();
nodes.splice(index, 1, newNode.id);
graph = graph.replace(newNode);
graph = graph.replace(parent.update({nodes: nodes}));
});
return graph;
};
action.permitted = function(graph) {
return graph.parentWays(graph.entity(nodeId)).length >= 2;
};
return action;
};
+5
View File
@@ -85,6 +85,11 @@ iD.modes.Select = function(entity, initial) {
iD.actions.SplitWay(d.id),
'split a way');
}).on('unjoin', function(d) {
mode.history.perform(
iD.actions.UnjoinNode(d.id),
'unjoined ways');
}).on('remove', function() {
remove();
+10 -1
View File
@@ -1,6 +1,6 @@
iD.ui.inspector = function() {
var event = d3.dispatch('changeTags', 'reverseWay',
'update', 'remove', 'close', 'splitWay'),
'update', 'remove', 'close', 'splitWay', 'unjoin'),
taginfo = iD.taginfo(),
initial = false,
tagList;
@@ -58,8 +58,10 @@ iD.ui.inspector = function() {
function drawButtons(selection) {
var entity = selection.datum();
var inspectorButtonWrap = selection.append('div')
.attr('class','button-wrap joined fl');
var inspectorButton1 = inspectorButtonWrap.append('button')
.attr('class', 'apply col6 action')
.on('click', apply);
@@ -80,17 +82,24 @@ iD.ui.inspector = function() {
.attr('href', 'http://www.openstreetmap.org/browse/' + entity.type + '/' + entity.osmId())
.attr('target', '_blank')
.text('View on OSM');
if (entity.type === 'way') {
minorButtons.append('a')
.attr('href', '#')
.text('Reverse Direction')
.on('click', function() { event.reverseWay(entity); });
}
if (entity.geometry() === 'vertex') {
minorButtons.append('a')
.attr('href', '#')
.text('Split Way')
.on('click', function() { event.splitWay(entity); });
minorButtons.append('a')
.attr('href', '#')
.text('Unjoin')
.on('click', function() { event.unjoin(entity); });
}
}
+2
View File
@@ -79,6 +79,7 @@
<script src='../js/id/actions/remove_way_node.js'></script>
<script src='../js/id/actions/reverse_way.js'></script>
<script src='../js/id/actions/split_way.js'></script>
<script src='../js/id/actions/unjoin_node.js'></script>
<script src='../js/id/actions/update_relation_member.js'></script>
<script src='../js/id/behavior.js'></script>
@@ -140,6 +141,7 @@
<script src="spec/actions/remove_relation_member.js"></script>
<script src="spec/actions/reverse_way.js"></script>
<script src="spec/actions/split_way.js"></script>
<script src='spec/actions/unjoin_node.js'></script>
<script src="spec/actions/update_relation_member.js"></script>
<script src="spec/behavior/hover.js"></script>
+1
View File
@@ -44,6 +44,7 @@
<script src="spec/actions/remove_relation_member.js"></script>
<script src="spec/actions/reverse_way.js"></script>
<script src="spec/actions/split_way.js"></script>
<script src='spec/actions/unjoin_node.js'></script>
<script src="spec/actions/update_relation_member.js"></script>
<script src="spec/behavior/hover.js"></script>
+77
View File
@@ -0,0 +1,77 @@
describe("iD.actions.UnjoinNode", function () {
describe("#permitted", function () {
it("returns false for a node shared by less than two ways", function () {
var graph = iD.Graph({'a': iD.Node()});
expect(iD.actions.UnjoinNode('a').permitted(graph)).to.equal(false);
});
it("returns true for a node shared by two or more ways", 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: ['d', 'b']})
});
expect(iD.actions.UnjoinNode('b').permitted(graph)).to.equal(true);
});
});
it("replaces the node with a new node in all but the first way", function () {
// Situation:
// a ---- b ---- c
// |
// d
// Split at b.
//
// Expected result:
// a ---- b ---- c
//
// e
// |
// 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: ['d', 'b']})
});
graph = iD.actions.UnjoinNode('b', 'e')(graph);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c']);
expect(graph.entity('|').nodes).to.eql(['d', 'e']);
});
it("copies location and tags to the new nodes", function () {
var tags = {highway: 'traffic_signals'},
loc = [1, 2],
graph = iD.Graph({
'a': iD.Node({id: 'a'}),
'b': iD.Node({id: 'b', loc: loc, tags: tags}),
'c': iD.Node({id: 'c'}),
'd': iD.Node({id: 'd'}),
'-': iD.Way({id: '-', nodes: ['a', 'b', 'c']}),
'|': iD.Way({id: '|', nodes: ['d', 'b']})
});
graph = iD.actions.UnjoinNode('b', 'e')(graph);
// Immutable loc => should be shared by identity.
expect(graph.entity('b').loc).to.equal(loc);
expect(graph.entity('e').loc).to.equal(loc);
// Immutable tags => should be shared by identity.
expect(graph.entity('b').tags).to.equal(tags);
expect(graph.entity('e').tags).to.equal(tags);
});
});