mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-14 13:18:15 +02:00
Enable the Split operation for multiple selected nodes (close #7990)
This commit is contained in:
+1
-1
@@ -2203,7 +2203,7 @@ en:
|
||||
merge: "Combine (merge) selected features"
|
||||
disconnect: "Disconnect selected features"
|
||||
extract: "Extract a point from a feature"
|
||||
split: "Split a line into two at the selected node"
|
||||
split: "Split features at the selected points"
|
||||
reverse: "Reverse selected features"
|
||||
move: "Move selected features"
|
||||
nudge: "Nudge selected features"
|
||||
|
||||
Vendored
+1
-1
@@ -2725,7 +2725,7 @@
|
||||
"merge": "Combine (merge) selected features",
|
||||
"disconnect": "Disconnect selected features",
|
||||
"extract": "Extract a point from a feature",
|
||||
"split": "Split a line into two at the selected node",
|
||||
"split": "Split features at the selected points",
|
||||
"reverse": "Reverse selected features",
|
||||
"move": "Move selected features",
|
||||
"nudge": "Nudge selected features",
|
||||
|
||||
+31
-14
@@ -3,7 +3,7 @@ import { geoSphericalDistance } from '../geo/geo';
|
||||
import { osmIsOldMultipolygonOuterMember } from '../osm/multipolygon';
|
||||
import { osmRelation } from '../osm/relation';
|
||||
import { osmWay } from '../osm/way';
|
||||
import { utilArrayIntersection, utilWrap } from '../util';
|
||||
import { utilArrayIntersection, utilWrap, utilArrayUniq } from '../util';
|
||||
|
||||
|
||||
// Split a way at the given node.
|
||||
@@ -20,13 +20,16 @@ import { utilArrayIntersection, utilWrap } from '../util';
|
||||
// Reference:
|
||||
// https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
|
||||
//
|
||||
export function actionSplit(nodeId, newWayIds) {
|
||||
export function actionSplit(nodeIds, newWayIds) {
|
||||
// accept single ID for backwards-compatiblity
|
||||
if (typeof nodeIds === 'string') nodeIds = [nodeIds];
|
||||
|
||||
var _wayIDs;
|
||||
// the strategy for picking which way will have a new version and which way is newly created
|
||||
var _keepHistoryOn = 'longest'; // 'longest', 'first'
|
||||
|
||||
// The IDs of the ways actually created by running this action
|
||||
var createdWayIDs = [];
|
||||
var _createdWayIDs = [];
|
||||
|
||||
function dist(graph, nA, nB) {
|
||||
var locA = graph.entity(nA).loc;
|
||||
@@ -91,7 +94,7 @@ export function actionSplit(nodeId, newWayIds) {
|
||||
return totalLength;
|
||||
}
|
||||
|
||||
function split(graph, wayA, newWayId) {
|
||||
function split(graph, nodeId, wayA, newWayId) {
|
||||
var wayB = osmWay({ id: newWayId, tags: wayA.tags }); // `wayB` is the NEW way
|
||||
var origNodes = wayA.nodes.slice();
|
||||
var nodesA;
|
||||
@@ -220,25 +223,30 @@ export function actionSplit(nodeId, newWayIds) {
|
||||
graph = graph.replace(wayB.update({ tags: {} }));
|
||||
}
|
||||
|
||||
createdWayIDs.push(wayB.id);
|
||||
_createdWayIDs.push(wayB.id);
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
var action = function(graph) {
|
||||
var candidates = action.ways(graph);
|
||||
createdWayIDs = [];
|
||||
for (var i = 0; i < candidates.length; i++) {
|
||||
graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
|
||||
_createdWayIDs = [];
|
||||
var newWayIndex = 0;
|
||||
for (var i = 0; i < nodeIds.length; i++) {
|
||||
var nodeId = nodeIds[i];
|
||||
var candidates = action.waysForNode(nodeId, graph);
|
||||
for (var j = 0; j < candidates.length; j++) {
|
||||
graph = split(graph, nodeId, candidates[j], newWayIds && newWayIds[newWayIndex]);
|
||||
newWayIndex += 1;
|
||||
}
|
||||
}
|
||||
return graph;
|
||||
};
|
||||
|
||||
action.getCreatedWayIDs = function() {
|
||||
return createdWayIDs;
|
||||
return _createdWayIDs;
|
||||
};
|
||||
|
||||
action.ways = function(graph) {
|
||||
action.waysForNode = function(nodeId, graph) {
|
||||
var node = graph.entity(nodeId);
|
||||
var parents = graph.parentWays(node);
|
||||
var hasLines = parents.some(function(parent) {
|
||||
@@ -266,11 +274,20 @@ export function actionSplit(nodeId, newWayIds) {
|
||||
});
|
||||
};
|
||||
|
||||
action.ways = function(graph) {
|
||||
return utilArrayUniq([].concat.apply([], nodeIds.map(function(nodeId) {
|
||||
return action.waysForNode(nodeId, graph);
|
||||
})));
|
||||
};
|
||||
|
||||
|
||||
action.disabled = function(graph) {
|
||||
var candidates = action.ways(graph);
|
||||
if (candidates.length === 0 || (_wayIDs && _wayIDs.length !== candidates.length)) {
|
||||
return 'not_eligible';
|
||||
for (var i = 0; i < nodeIds.length; i++) {
|
||||
var nodeId = nodeIds[i];
|
||||
var candidates = action.waysForNode(nodeId, graph);
|
||||
if (candidates.length === 0 || (_wayIDs && _wayIDs.length !== candidates.length)) {
|
||||
return 'not_eligible';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+23
-22
@@ -5,40 +5,42 @@ import { modeSelect } from '../modes/select';
|
||||
|
||||
|
||||
export function operationSplit(context, selectedIDs) {
|
||||
var vertices = selectedIDs
|
||||
.filter(function(id) { return context.graph().geometry(id) === 'vertex'; });
|
||||
var entityID = vertices[0];
|
||||
var action = actionSplit(entityID);
|
||||
var ways = [];
|
||||
var _vertexIds = selectedIDs.filter(function(id) {
|
||||
return context.graph().geometry(id) === 'vertex';
|
||||
});
|
||||
var _selectedWayIds = selectedIDs.filter(function(id) {
|
||||
var entity = context.graph().hasEntity(id);
|
||||
return entity && entity.type === 'way';
|
||||
});
|
||||
var _isAvailable = _vertexIds.length > 0 &&
|
||||
_vertexIds.length + _selectedWayIds.length === selectedIDs.length;
|
||||
var _action = actionSplit(_vertexIds);
|
||||
var _ways = [];
|
||||
|
||||
if (vertices.length === 1) {
|
||||
if (entityID && selectedIDs.length > 1) {
|
||||
var ids = selectedIDs.filter(function(id) { return id !== entityID; });
|
||||
action.limitWays(ids);
|
||||
}
|
||||
ways = action.ways(context.graph());
|
||||
if (_isAvailable) {
|
||||
if (_selectedWayIds.length) _action.limitWays(_selectedWayIds);
|
||||
_ways = _action.ways(context.graph());
|
||||
}
|
||||
|
||||
|
||||
var operation = function() {
|
||||
var difference = context.perform(action, operation.annotation());
|
||||
var difference = context.perform(_action, operation.annotation());
|
||||
context.enter(modeSelect(context, difference.extantIDs()));
|
||||
};
|
||||
|
||||
|
||||
operation.available = function() {
|
||||
return vertices.length === 1;
|
||||
return _isAvailable;
|
||||
};
|
||||
|
||||
|
||||
operation.disabled = function() {
|
||||
var reason = action.disabled(context.graph());
|
||||
var reason = _action.disabled(context.graph());
|
||||
if (reason) {
|
||||
return reason;
|
||||
} else if (selectedIDs.some(context.hasHiddenConnections)) {
|
||||
return 'connected_to_hidden';
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -47,18 +49,17 @@ export function operationSplit(context, selectedIDs) {
|
||||
var disable = operation.disabled();
|
||||
if (disable) {
|
||||
return t('operations.split.' + disable);
|
||||
} else if (ways.length === 1) {
|
||||
return t('operations.split.description.' + context.graph().geometry(ways[0].id));
|
||||
} else {
|
||||
return t('operations.split.description.multiple');
|
||||
} else if (_ways.length === 1) {
|
||||
return t('operations.split.description.' + context.graph().geometry(_ways[0].id));
|
||||
}
|
||||
return t('operations.split.description.multiple');
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return ways.length === 1 ?
|
||||
t('operations.split.annotation.' + context.graph().geometry(ways[0].id)) :
|
||||
t('operations.split.annotation.feature', { n: ways.length });
|
||||
return _ways.length === 1 ?
|
||||
t('operations.split.annotation.' + context.graph().geometry(_ways[0].id)) :
|
||||
t('operations.split.annotation.feature', { n: _ways.length });
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -164,10 +164,10 @@ export function osmIntersection(graph, startVertexId, maxDistance) {
|
||||
// actions can be replayed on the main graph exactly in the same order.
|
||||
// (It is unintuitive, but the order of ways returned from graph.parentWays()
|
||||
// is arbitrary, depending on how the main graph and vgraph were built)
|
||||
var splitAll = actionSplit(v.id).keepHistoryOn('first');
|
||||
var splitAll = actionSplit([v.id]).keepHistoryOn('first');
|
||||
if (!splitAll.disabled(vgraph)) {
|
||||
splitAll.ways(vgraph).forEach(function(way) {
|
||||
var splitOne = actionSplit(v.id).limitWays([way.id]).keepHistoryOn('first');
|
||||
var splitOne = actionSplit([v.id]).limitWays([way.id]).keepHistoryOn('first');
|
||||
actions.push(splitOne);
|
||||
vgraph = splitOne(vgraph);
|
||||
});
|
||||
|
||||
@@ -647,7 +647,7 @@ export function validationCrossingWays(context) {
|
||||
// just bound the structure at the existing end node
|
||||
if (!newNode) newNode = endNode;
|
||||
|
||||
var splitAction = actionSplit(newNode.id)
|
||||
var splitAction = actionSplit([newNode.id])
|
||||
.limitWays(resultWayIDs); // only split selected or created ways
|
||||
|
||||
// do the split
|
||||
|
||||
Reference in New Issue
Block a user