mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-12 16:52:50 +00:00
Add straighten way operation and action
This commit is contained in:
@@ -63,6 +63,13 @@ en:
|
||||
line: Squared the corners of a line.
|
||||
area: Squared the corners of an area.
|
||||
not_closed: This can't be made square because it's not a loop.
|
||||
straighten:
|
||||
title: Straighten
|
||||
description: Straighten this line.
|
||||
key: S
|
||||
annotation: Straightened the line.
|
||||
is_closed: This can't be straightened because it's a loop.
|
||||
too_bendy: This can't be straightened because it's too bendy.
|
||||
delete:
|
||||
title: Delete
|
||||
description: Remove this from the map.
|
||||
|
||||
@@ -146,6 +146,7 @@
|
||||
<script src='js/id/actions/rotate_way.js'></script>
|
||||
<script src='js/id/actions/circularize.js'></script>
|
||||
<script src='js/id/actions/orthogonalize.js'></script>
|
||||
<script src='js/id/actions/straighten.js'></script>
|
||||
<script src='js/id/actions/noop.js'></script>
|
||||
<script src='js/id/actions/reverse.js'></script>
|
||||
<script src='js/id/actions/split.js'></script>
|
||||
@@ -179,6 +180,7 @@
|
||||
<script src='js/id/operations/continue.js'></script>
|
||||
<script src='js/id/operations/circularize.js'></script>
|
||||
<script src='js/id/operations/orthogonalize.js'></script>
|
||||
<script src='js/id/operations/straighten.js'></script>
|
||||
<script src='js/id/operations/delete.js'></script>
|
||||
<script src='js/id/operations/disconnect.js'></script>
|
||||
<script src='js/id/operations/merge.js'></script>
|
||||
|
||||
75
js/id/actions/straighten.js
Normal file
75
js/id/actions/straighten.js
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
|
||||
*/
|
||||
|
||||
iD.actions.Straighten = function(wayId, projection) {
|
||||
function positionAlongWay(n, s, e) {
|
||||
return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1]))/
|
||||
(Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
|
||||
}
|
||||
|
||||
var action = function(graph) {
|
||||
var way = graph.entity(wayId),
|
||||
nodes = graph.childNodes(way),
|
||||
points = nodes.map(function(n) { return projection(n.loc); }),
|
||||
startPoint = points[0],
|
||||
endPoint = points[points.length-1],
|
||||
toDelete = [],
|
||||
i;
|
||||
|
||||
for (i = 1; i < points.length-1; i++) {
|
||||
var node = nodes[i],
|
||||
point = points[i];
|
||||
|
||||
if (graph.parentWays(node).length > 1 || (node.tags && Object.keys(node.tags).length)) {
|
||||
var u = positionAlongWay(point, startPoint, endPoint),
|
||||
p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
|
||||
p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
|
||||
|
||||
graph = graph.replace(graph.entity(node.id)
|
||||
.move(projection.invert([p0, p1])));
|
||||
} else {
|
||||
// safe to delete
|
||||
if (toDelete.indexOf(node) == -1) {
|
||||
toDelete.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < toDelete.length; i++) {
|
||||
graph = iD.actions.DeleteNode(toDelete[i].id)(graph);
|
||||
}
|
||||
|
||||
return graph;
|
||||
};
|
||||
|
||||
action.disabled = function(graph) {
|
||||
if (graph.entity(wayId).isClosed()) {
|
||||
return 'is_closed';
|
||||
}
|
||||
|
||||
// check way isn't too bendy
|
||||
var way = graph.entity(wayId),
|
||||
nodes = graph.childNodes(way),
|
||||
points = nodes.map(function(n) { return projection(n.loc); }),
|
||||
startPoint = points[0],
|
||||
endPoint = points[points.length-1],
|
||||
threshold = 0.2 * Math.sqrt(Math.pow(startPoint[0] - endPoint[0], 2) + Math.pow(startPoint[1] - endPoint[1], 2)),
|
||||
i;
|
||||
|
||||
for (i = 1; i < points.length-1; i++) {
|
||||
var point = points[i],
|
||||
u = positionAlongWay(point, startPoint, endPoint),
|
||||
p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
|
||||
p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
|
||||
dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
|
||||
|
||||
// to bendy if point is off by 20% of total start/end distance in projected space
|
||||
if (dist > threshold) {
|
||||
return 'too_bendy';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return action;
|
||||
};
|
||||
33
js/id/operations/straighten.js
Normal file
33
js/id/operations/straighten.js
Normal file
@@ -0,0 +1,33 @@
|
||||
iD.operations.Straighten = function(selectedIDs, context) {
|
||||
var entityId = selectedIDs[0],
|
||||
action = iD.actions.Straighten(entityId, context.projection);
|
||||
|
||||
var operation = function() {
|
||||
var annotation = t('operations.straighten.annotation');
|
||||
context.perform(action, annotation);
|
||||
};
|
||||
|
||||
operation.available = function() {
|
||||
return selectedIDs.length === 1 &&
|
||||
context.entity(entityId).type === 'way' &&
|
||||
_.uniq(context.entity(entityId).nodes).length > 2;
|
||||
};
|
||||
|
||||
operation.disabled = function() {
|
||||
return action.disabled(context.graph());
|
||||
};
|
||||
|
||||
operation.tooltip = function() {
|
||||
var disable = operation.disabled();
|
||||
return disable ?
|
||||
t('operations.straighten.' + disable) :
|
||||
t('operations.straighten.description');
|
||||
};
|
||||
|
||||
operation.id = "straighten";
|
||||
operation.keys = [t('operations.straighten.key')];
|
||||
operation.title = "title";
|
||||
operation.description = "description";
|
||||
|
||||
return operation;
|
||||
};
|
||||
@@ -128,6 +128,7 @@
|
||||
<script src='../js/id/actions/rotate_way.js'></script>
|
||||
<script src='../js/id/actions/circularize.js'></script>
|
||||
<script src='../js/id/actions/orthogonalize.js'></script>
|
||||
<script src='../js/id/actions/straighten.js'></script>
|
||||
<script src='../js/id/actions/noop.js'></script>
|
||||
<script src='../js/id/actions/reverse.js'></script>
|
||||
<script src='../js/id/actions/split.js'></script>
|
||||
@@ -160,6 +161,7 @@
|
||||
<script src='../js/id/operations/continue.js'></script>
|
||||
<script src='../js/id/operations/circularize.js'></script>
|
||||
<script src='../js/id/operations/orthogonalize.js'></script>
|
||||
<script src='../js/id/operations/straighten.js'></script>
|
||||
<script src='../js/id/operations/delete.js'></script>
|
||||
<script src='../js/id/operations/disconnect.js'></script>
|
||||
<script src='../js/id/operations/merge.js'></script>
|
||||
@@ -203,6 +205,7 @@
|
||||
<script src="spec/actions/change_tags.js"></script>
|
||||
<script src='spec/actions/circularize.js'></script>
|
||||
<script src='spec/actions/orthogonalize.js'></script>
|
||||
<script src='spec/actions/straighten.js'></script>
|
||||
<script src='spec/actions/connect.js'></script>
|
||||
<script src='spec/actions/delete_member.js'></script>
|
||||
<script src="spec/actions/delete_multiple.js"></script>
|
||||
|
||||
44
test/spec/actions/straighten.js
Normal file
44
test/spec/actions/straighten.js
Normal file
@@ -0,0 +1,44 @@
|
||||
describe("iD.actions.Straighten", function () {
|
||||
var projection = d3.geo.mercator();
|
||||
|
||||
it("deletes empty nodes", function() {
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a', loc: [0, 0]}),
|
||||
'b': iD.Node({id: 'b', loc: [2, 0], tags: {}}),
|
||||
'c': iD.Node({id: 'c', loc: [2, 2]}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b', 'c']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Straighten('-', projection)(graph);
|
||||
|
||||
expect(graph.hasEntity('b')).to.be.undefined;
|
||||
});
|
||||
|
||||
it("does not delete tagged nodes", function() {
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a', loc: [0, 0]}),
|
||||
'b': iD.Node({id: 'b', loc: [2, 0], tags: {foo: 'bar'}}),
|
||||
'c': iD.Node({id: 'c', loc: [2, 2]}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b', 'c']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Straighten('-', projection)(graph);
|
||||
|
||||
expect(graph.entity('-').nodes.sort()).to.eql(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it("does not delete nodes connected to other ways", function() {
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a', loc: [0, 0]}),
|
||||
'b': iD.Node({id: 'b', loc: [2, 0]}),
|
||||
'c': iD.Node({id: 'c', loc: [2, 2]}),
|
||||
'd': iD.Node({id: 'd', loc: [0, 2]}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd']}),
|
||||
'=': iD.Way({id: '=', nodes: ['b']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Straighten('-', projection)(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.have.length(3);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user