mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-12 16:52:50 +00:00
create 'follow' feature for drawing ways
This commit is contained in:
@@ -346,6 +346,19 @@ en:
|
||||
not_downloaded:
|
||||
single: This feature can't be moved because parts of it have not yet been downloaded.
|
||||
multiple: These features can't be moved because parts of them have not yet been downloaded.
|
||||
follow:
|
||||
key: F
|
||||
error:
|
||||
needs_more_initial_nodes: This line can't follow a way because it isn't connected to enough consecutive points along a way. Add another point manually to continue.
|
||||
intersection_of_mutiple_ways:
|
||||
line: This line can't follow a way because multiple lines are connected to the line's last two points. Add another vertex manually to continue.
|
||||
area: This line can't follow a way because multiple areas are connected to the line's last two points. Add another vertex manually to continue.
|
||||
generic: This line can't follow a way because multiple features are connected to the line's last two points. Add another vertex manually to continue.
|
||||
intersection_of_different_ways:
|
||||
line: This line can't follow a way because the line is only connected to the line at a single point. Add another point manually to continue.
|
||||
area: This line can't follow a way because the line is only connected to the area at a single point. Add another point manually to continue.
|
||||
generic: This line can't follow a way because the line is only connected to the way at a single point. Add another point manually to continue.
|
||||
unknown: This line can't follow a way.
|
||||
reflect:
|
||||
title:
|
||||
long: Flip Long
|
||||
@@ -783,7 +796,7 @@ en:
|
||||
map_data:
|
||||
title: Map Data
|
||||
description: Map Data
|
||||
key: F
|
||||
key: U
|
||||
data_layers: Data Layers
|
||||
layers:
|
||||
osm:
|
||||
@@ -2332,6 +2345,7 @@ en:
|
||||
split: "Split features at the selected points"
|
||||
reverse: "Reverse selected features"
|
||||
move: "Move selected features"
|
||||
follow: "Follow a line or area"
|
||||
nudge: "Nudge selected features"
|
||||
nudge_more: "Nudge selected features by a lot"
|
||||
scale: "Scale selected features"
|
||||
|
||||
@@ -283,6 +283,10 @@
|
||||
"shortcuts": ["operations.move.key"],
|
||||
"text": "shortcuts.editing.operations.move"
|
||||
},
|
||||
{
|
||||
"shortcuts": ["operations.follow.key"],
|
||||
"text": "shortcuts.editing.operations.follow"
|
||||
},
|
||||
{
|
||||
"modifiers": ["⇧"],
|
||||
"shortcuts": ["↓", "↑", "←", "→"],
|
||||
|
||||
2
dist/locales/en.min.json
vendored
2
dist/locales/en.min.json
vendored
File diff suppressed because one or more lines are too long
@@ -18,6 +18,7 @@ import { utilRebind } from '../util/rebind';
|
||||
import { utilKeybinding } from '../util';
|
||||
|
||||
export function behaviorDrawWay(context, wayID, mode, startGraph) {
|
||||
const keybinding = utilKeybinding('drawWay');
|
||||
|
||||
var dispatch = d3_dispatch('rejectedSelfIntersection');
|
||||
|
||||
@@ -412,6 +413,96 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {(typeof osmWay)[]} ways
|
||||
* @returns {"line" | "area" | "generic"}
|
||||
*/
|
||||
function getFeatureType(ways) {
|
||||
if (ways.every(way => way.isClosed())) return 'area';
|
||||
if (ways.every(way => !way.isClosed())) return 'line';
|
||||
return 'generic';
|
||||
}
|
||||
|
||||
/** see PR #8671 */
|
||||
function followMode() {
|
||||
if (_didResolveTempEdit) return;
|
||||
|
||||
try {
|
||||
|
||||
// get the last 2 added nodes.
|
||||
// check if they are both part of only oneway (the same one)
|
||||
// check if the ways that they're part of are the same way
|
||||
// find index of the last two nodes, to determine the direction to travel around the existing way
|
||||
// add the next node to the way we are drawing
|
||||
|
||||
// if we're drawing an area, the first node = last node.
|
||||
const isDrawingArea = _origWay.nodes[0] === _origWay.nodes.slice(-1)[0];
|
||||
|
||||
const [secondLastNodeId, lastNodeId] = _origWay.nodes.slice(isDrawingArea ? -3 : -2);
|
||||
|
||||
if (!lastNodeId || !secondLastNodeId || !startGraph.hasEntity(lastNodeId) || !startGraph.hasEntity(secondLastNodeId)) {
|
||||
context.ui().flash
|
||||
.duration(4000)
|
||||
.iconName('#iD-icon-no')
|
||||
.label(t('operations.follow.error.needs_more_initial_nodes'))();
|
||||
return;
|
||||
}
|
||||
|
||||
const lastNodesParents = startGraph.parentWays(startGraph.entity(lastNodeId));
|
||||
const secondLastNodesParents = startGraph.parentWays(startGraph.entity(secondLastNodeId));
|
||||
|
||||
const featureType = getFeatureType(lastNodesParents);
|
||||
|
||||
if (lastNodesParents.length !== 1 || secondLastNodesParents.length === 0) {
|
||||
context.ui().flash
|
||||
.duration(4000)
|
||||
.iconName('#iD-icon-no')
|
||||
.label(t(`operations.follow.error.intersection_of_mutiple_ways.${featureType}`))();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the last node's parent is also the parent of the second last node.
|
||||
// The last node must only have one parent, but the second last node can have
|
||||
// multiple parents.
|
||||
if (!secondLastNodesParents.some(n => n.id === lastNodesParents[0].id)) {
|
||||
context.ui().flash
|
||||
.duration(4000)
|
||||
.iconName('#iD-icon-no')
|
||||
.label(t(`operations.follow.error.intersection_of_different_ways.${featureType}`))();
|
||||
return;
|
||||
}
|
||||
|
||||
const way = lastNodesParents[0];
|
||||
|
||||
const indexOfLast = way.nodes.indexOf(lastNodeId);
|
||||
const indexOfSecondLast = way.nodes.indexOf(secondLastNodeId);
|
||||
|
||||
// for a closed way, the first/last node is the same so it appears twice in the array,
|
||||
// but indexOf always finds the first occurance. This is only an issue when following a way
|
||||
// in descending order
|
||||
const isDescendingPastZero = indexOfLast === way.nodes.length - 2 && indexOfSecondLast === 0;
|
||||
|
||||
let nextNodeIndex = indexOfLast + (indexOfLast > indexOfSecondLast && !isDescendingPastZero ? 1 : -1);
|
||||
// if we're following a closed way and we pass the first/last node, the next index will be -1
|
||||
if (nextNodeIndex === -1) nextNodeIndex = indexOfSecondLast === 1 ? way.nodes.length - 2 : 1;
|
||||
|
||||
const nextNode = startGraph.entity(way.nodes[nextNodeIndex]);
|
||||
|
||||
drawWay.addNode(nextNode, {
|
||||
geometry: { type: 'Point', coordinates: nextNode.loc },
|
||||
id: nextNode.id,
|
||||
properties: { target: true, entity: nextNode },
|
||||
});
|
||||
} catch (ex) {
|
||||
context.ui().flash
|
||||
.duration(4000)
|
||||
.iconName('#iD-icon-no')
|
||||
.label(t('operations.follow.error.unknown'))();
|
||||
}
|
||||
}
|
||||
|
||||
keybinding.on(t('operations.follow.key'), followMode);
|
||||
d3_select(document).call(keybinding);
|
||||
|
||||
// Finish the draw operation, removing the temporary edit.
|
||||
// If the way has enough nodes to be valid, it's selected.
|
||||
|
||||
Reference in New Issue
Block a user