Ignore:
Timestamp:
2019-12-09T09:47:20+01:00 (4 years ago)
Author:
GerdP
Message:

fix #18367 and #18385: CombineWayAction (C) refuses to combine ways or silently reverses ways
Changes:

  • try first to combine the ways with the method Multipolygon.joinWays() If that method returns a single line string we can use it, else use the result of NodeGraph.buildSpanningPathNoRemove(). Both methods will not add or remove segments
  • if ways are combined execute checks for overlapping segments or self-intersection and show a notification popup right after the command was added to the UndoRedoHandler
  • The code which handles reversed ways needed changes. In the unpatched version it sometimes claims wrongly that ways were reversed, in special cases it sometimes silently reverted ways. The old code did not handle the case properly that a node can appear more than once. I really hope that I got it right now.
  • Fix some sonarlint issues
  • let NodeGraph routines return an ArrayList instead of a LinkedList (improves performance a bit)
  • Add unit tests
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/osm/NodeGraph.java

    r15559 r15574  
    1212import java.util.LinkedHashMap;
    1313import java.util.LinkedHashSet;
    14 import java.util.LinkedList;
    1514import java.util.List;
    1615import java.util.Map;
     
    1817import java.util.Optional;
    1918import java.util.Set;
    20 import java.util.Stack;
    2119import java.util.TreeMap;
    2220
     
    249247    }
    250248
    251     protected List<Node> buildPathFromNodePairs(Stack<NodePair> path) {
    252         List<Node> ret = new LinkedList<>();
    253         for (NodePair pair: path) {
     249    protected List<Node> buildPathFromNodePairs(Deque<NodePair> path) {
     250        List<Node> ret = new ArrayList<>(path.size() + 1);
     251        for (NodePair pair : path) {
    254252            ret.add(pair.getA());
    255253        }
    256         ret.add(path.peek().getB());
     254        ret.add(path.peekLast().getB());
    257255        return ret;
    258256    }
     
    264262     *
    265263     * @param startNode the start node
    266      * @return the spanning path; null, if no path is found
     264     * @return the spanning path; empty list if no path is found
    267265     */
    268266    protected List<Node> buildSpanningPath(Node startNode) {
    269267        if (startNode != null) {
    270             // do not simply replace `Stack` by `ArrayDeque` because of different iteration behaviour, see #11957
    271             Stack<NodePair> path = new Stack<>();
     268            Deque<NodePair> path = new ArrayDeque<>();
    272269            Set<NodePair> dupCheck = new HashSet<>();
    273             Stack<NodePair> nextPairs = new Stack<>();
     270            Deque<NodePair> nextPairs = new ArrayDeque<>();
    274271            nextPairs.addAll(getOutboundPairs(startNode));
    275272            while (!nextPairs.isEmpty()) {
    276                 NodePair cur = nextPairs.pop();
     273                NodePair cur = nextPairs.removeLast();
    277274                if (!dupCheck.contains(cur) && !dupCheck.contains(cur.swap())) {
    278                     while (!path.isEmpty() && !path.peek().isPredecessorOf(cur)) {
    279                         dupCheck.remove(path.pop());
     275                    while (!path.isEmpty() && !path.peekLast().isPredecessorOf(cur)) {
     276                        dupCheck.remove(path.removeLast());
    280277                    }
    281                     path.push(cur);
     278                    path.addLast(cur);
    282279                    dupCheck.add(cur);
    283                     if (isSpanningWay(path)) return buildPathFromNodePairs(path);
    284                     nextPairs.addAll(getOutboundPairs(path.peek()));
     280                    if (isSpanningWay(path))
     281                        return buildPathFromNodePairs(path);
     282                    nextPairs.addAll(getOutboundPairs(path.peekLast()));
    285283                }
    286284            }
     
    324322     * any duplicated edge was removed.
    325323     *
    326      * @return the path; null, if no path was found or duplicated edges were found
    327      * @since 15555
     324     * @return List of nodes that build the path; an empty list if no path or duplicated edges were found
     325     * @since 15573 (return value not null)
    328326     */
    329327    public List<Node> buildSpanningPathNoRemove() {
    330         if (edges.size() != addedEdges)
    331             return null;
    332         return buildSpanningPath();
     328        List<Node> path = null;
     329        if (edges.size() == addedEdges)
     330            path = buildSpanningPath();
     331        return path == null ? Collections.emptyList() : path;
    333332    }
    334333
Note: See TracChangeset for help on using the changeset viewer.