Ticket #18367: 18367.patch

File 18367.patch, 4.8 KB (added by GerdP, 18 months ago)
  • src/org/openstreetmap/josm/actions/CombineWayAction.java

     
    3131import org.openstreetmap.josm.data.osm.OsmUtils;
    3232import org.openstreetmap.josm.data.osm.TagCollection;
    3333import org.openstreetmap.josm.data.osm.Way;
     34import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
     35import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.JoinedWay;
    3436import org.openstreetmap.josm.data.preferences.BooleanProperty;
     37import org.openstreetmap.josm.data.validation.Test;
     38import org.openstreetmap.josm.data.validation.tests.OverlappingWays;
     39import org.openstreetmap.josm.data.validation.tests.SelfIntersectingWay;
    3540import org.openstreetmap.josm.gui.ExtendedDialog;
    3641import org.openstreetmap.josm.gui.MainApplication;
    3742import org.openstreetmap.josm.gui.Notification;
     
    122127        }
    123128
    124129        // try to build a new way which includes all the combined ways
    125         NodeGraph graph = NodeGraph.createNearlyUndirectedGraphFromNodeWays(ways);
    126         List<Node> path = graph.buildSpanningPathNoRemove();
     130        List<Node> path = joinWithMultipolygonCode(ways);
    127131        if (path == null) {
     132            NodeGraph graph = NodeGraph.createNearlyUndirectedGraphFromNodeWays(ways);
     133            path = graph.buildSpanningPathNoRemove();
     134        }
     135        if (path == null) {
    128136            warnCombiningImpossible();
    129137            return null;
    130138        }
     
    138146        List<Way> unreversedWays = new LinkedList<>();
    139147        for (Way w: ways) {
    140148            // Treat zero or one-node ways as unreversed as Combine action action is a good way to fix them (see #8971)
    141             if (w.getNodesCount() < 2 || (path.indexOf(w.getNode(0)) + 1) == path.lastIndexOf(w.getNode(1))) {
     149            if (w.getNodesCount() < 2) {
    142150                unreversedWays.add(w);
    143151            } else {
    144                 reversedWays.add(w);
     152                boolean foundStartSegment = false;
     153                int last = path.lastIndexOf(w.getNode(0));
     154
     155                for (int i = path.indexOf(w.getNode(0)); i <= last; i++) {
     156                    if (path.get(i) == w.getNode(0) && i + 1 < path.size() && w.getNode(1) == path.get(i + 1)) {
     157                        foundStartSegment = true;
     158                        break;
     159                    }
     160                }
     161                if (foundStartSegment) {
     162                    unreversedWays.add(w);
     163                } else {
     164                    reversedWays.add(w);
     165                }
    145166            }
    146167        }
    147168        // reverse path if all ways have been reversed
     
    212233        return new Pair<>(targetWay, sequenceCommand);
    213234    }
    214235
     236    /**
     237     * Use {@link Multipolygon#joinWays(Collection)} to join ways.
     238     * @param ways the ways
     239     * @return List of nodes of the combined ways or null if ways could not be combined to a single way.
     240     * Result may contain overlapping segments.
     241     */
     242    private static List<Node> joinWithMultipolygonCode(Collection<Way> ways) {
     243        // sort so that old unclosed ways appear first
     244        LinkedList<Way> toJoin = new LinkedList<>(ways);
     245        toJoin.sort((o1, o2) -> {
     246            int d = Boolean.compare(o1.isNew(), o2.isNew());
     247            if (d == 0)
     248                d = Boolean.compare(o1.isClosed(), o2.isClosed());
     249            return d;
     250        });
     251        Collection<JoinedWay> list = Multipolygon.joinWays(toJoin);
     252        if (list.size() == 1) {
     253            // ways form a single line string
     254            return new ArrayList<>(list.iterator().next().getNodes());
     255        }
     256        return null;
     257    }
     258
    215259    @Override
    216260    public void actionPerformed(ActionEvent event) {
    217261        final DataSet ds = getLayerManager().getEditDataSet();
     
    237281
    238282        if (combineResult == null)
    239283            return;
     284
    240285        final Way selectedWay = combineResult.a;
    241286        UndoRedoHandler.getInstance().add(combineResult.b);
     287        Test test = new OverlappingWays();
     288        test.startTest(null);
     289        test.visit(combineResult.a);
     290        test.endTest();
     291        if (test.getErrors().isEmpty()) {
     292            test = new SelfIntersectingWay();
     293            test.startTest(null);
     294            test.visit(combineResult.a);
     295            test.endTest();
     296        }
     297        if (!test.getErrors().isEmpty()) {
     298            new Notification(test.getErrors().get(0).getMessage())
     299            .setIcon(JOptionPane.WARNING_MESSAGE)
     300            .show();
     301        }
    242302        if (selectedWay != null) {
    243303            GuiHelper.runInEDT(() -> ds.setSelected(selectedWay));
    244304        }
     
    261321        }
    262322        setEnabled(numWays >= 2);
    263323    }
     324
    264325}