Skip to content

Directional nodes: map Rotate updates direction / camera:direction#957

Open
tordans wants to merge 1 commit into
bryceco:masterfrom
tordans:cursor/directional-node-rotate-704f
Open

Directional nodes: map Rotate updates direction / camera:direction#957
tordans wants to merge 1 commit into
bryceco:masterfrom
tordans:cursor/directional-node-rotate-704f

Conversation

@tordans
Copy link
Copy Markdown
Contributor

@tordans tordans commented May 31, 2026

Problem

Mappers who tag standalone POIs with a technical bearing (direction=* or camera:direction=* in degrees, cardinals, or ranges—see OsmNode+Direction.swift) can preview the aim on the map as a direction wedge, but adjusting it today means opening the POI editor and using the compass flow (DirectionViewController via PresetValueTextField).

Area rotation is already map-native: choose Rotate, use the cyan arc overlay and rotation gesture, and geometry updates in place. Nodes without a selected parent way only get Duplicate; Rotate on a node inside a way still rotates the whole way. Standalone nodes with a direction tag had no equivalent “aim on the map” workflow.

Goal: For a standalone selected node whose direction or camera:direction value OsmNode.direction can parse, show Rotate in the edit menu and enter the same rotation overlay/gesture as areas—but write the tag (bearing in degrees, same convention as compass capture and the map wedge) instead of moving the node. Complements DirectionViewController; does not replace it.

Out of scope (this PR): Nodes that only infer direction from highway forward/backward on a way; nodes that are members of a way (way rotation unchanged).


Implementation notes (by Cursor)

When Rotate appears

  • In EditorMapLayer.editActionsAvailable(), standalone nodes (selectedNode only) append .ROTATE when technicalDirectionTagKey != nil.
  • technicalDirectionTagKey is added on OsmNode and only matches direction / camera:direction values that directionFromString can parse (so direction=forward on a highway=stop node does not qualify).

Direction-edit rotate mode

  • MapView.startObjectRotation() detects standalone + technical direction and calls EditorMapLayer.rotateDirectionBegin() (undo grouping + stored initial bearing/tag key).
  • Same cyan rotation overlay and UIRotationGestureRecognizer as geometry rotation.
  • rotateDirectionContinue(delta:) applies total gesture rotation to the initial bearing, writes degrees via mapData.setTags, calls setNeedsLayout() and didUpdateObject() for live wedge preview.
  • Tag key preserved: existing direction vs camera:direction; numeric output like compass UI (MeasureDirectionViewModel). Arc spans (90-120) keep their width when rotated.
  • endObjectRotation() finishes direction undo via rotateDirectionFinish().
  • Direction-rotate session state (directionRotateTagKey, directionRotateInitialBearing) lives on the main EditorMapLayer class—not in the +Edit extension (Swift disallows stored properties in extensions).

Fallback behavior

  • No parsable direction tag: Rotate is not listed for standalone nodes (same as today). Choosing Rotate on an in-way node without a standalone direction context still requires a way/multipolygon (unchanged error path).

Testing notes (@tordans)

  1. Build Go Map!! scheme on device or simulator (Linux CI cannot run Xcode here).
  2. Unit tests: Run GoMapTestsOsmNode_DirectionTestCase (new cases for technicalDirectionTagKey, range formatting, highway forward exclusion).
  3. Happy path
    • Select a standalone node with direction=90 or camera:direction=180 (e.g. bench, surveillance, viewpoint). – Only tested direction, camera:direction assumed to also work
    • Confirm Rotate appears in the edit toolbar / More sheet.
    • Tap Rotate → cyan arc overlay at node; two-finger rotate → wedge and tag value update live; release → undo group; tag is integer degrees.
  4. Tag key
    • Node with only camera:direction → rotation updates that key, not direction.
  5. Range (optional): direction=90-120 → after rotate, still a range with same angular width.
  6. Regression
    • Closed way / multipolygon: Rotate still moves geometry.
    • Node in way (no standalone selection): Rotate still rotates way, not tag-only.
    • Standalone node without direction tag: no Rotate.
    • highway=stop + direction=forward: no Rotate on standalone (no technical direction). – Not tested (yet)
  7. Sign / feel: Verify wedge rotation direction matches finger rotation; report if inverted (implementation uses negated gesture delta to align with geometry rotate).
BeforeAfter
rotate-node--before.min.mov
rotate-node--after.min.mov

Ping openstreetmap/iD#12104 and especially openstreetmap/iD#12341 where this idea comes from.

Standalone nodes with a parsable direction or camera:direction tag now
expose Rotate in the edit menu. Rotation uses the same overlay and pinch
gesture as areas but writes bearing degrees to the tag instead of moving
geometry, with live direction wedge preview on the map.

fix: move direction-rotate state out of extension (Swift compile error)
Co-Authored-By: Tobias <t@tobiasjordans.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants