From 779c862cead6e116c341fe76a1a52f075d400f69 Mon Sep 17 00:00:00 2001 From: Taylor Smock Date: Tue, 12 May 2020 16:13:37 -0600 Subject: [PATCH] Add a check and cleanup for overnoded ways Also switch layers to the appropriate data layer (for UI) for OverNodedWays/MissingConnectionTags. Signed-off-by: Taylor Smock --- .../cleanup/MissingConnectionTags.java | 33 ++++-- .../conflation/cleanup/OverNodedWays.java | 101 ++++++++++++++++++ .../commands/CreateConnectionsCommand.java | 2 + 3 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/cleanup/OverNodedWays.java diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/cleanup/MissingConnectionTags.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/cleanup/MissingConnectionTags.java index f449622..32a0652 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/cleanup/MissingConnectionTags.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/cleanup/MissingConnectionTags.java @@ -30,6 +30,8 @@ import org.openstreetmap.josm.data.validation.tests.CrossingWays; import org.openstreetmap.josm.data.validation.tests.DuplicateNode; import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil; import org.openstreetmap.josm.gui.MainApplication; +import org.openstreetmap.josm.gui.layer.AbstractOsmDataLayer; +import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.gui.progress.NullProgressMonitor; import org.openstreetmap.josm.gui.util.GuiHelper; import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.AbstractConflationCommand; @@ -45,7 +47,8 @@ import org.openstreetmap.josm.tools.Utils; * @author Taylor Smock */ public class MissingConnectionTags extends AbstractConflationCommand { - private double precision = Config.getPref().getDouble("validator.duplicatenodes.precision", 0.); + private double precision; + private static final String HIGHWAY = "highway"; public MissingConnectionTags(DataSet data) { super(data); @@ -64,11 +67,22 @@ public class MissingConnectionTags extends AbstractConflationCommand { @Override public String getKey() { // For now, we assume that only highways are at issue. - return "highway"; + return HIGHWAY; } @Override public Command getRealCommand() { + precision = Config.getPref().getDouble("validator.duplicatenodes.precision", 0.); + Layer current = MainApplication.getLayerManager().getActiveLayer(); + Collection ways = Utils.filteredCollection(possiblyAffectedPrimitives, Way.class); + if (!ways.isEmpty()) { + DataSet ds = this.getAffectedDataSet(); + Layer toSwitch = MainApplication.getLayerManager().getLayersOfType(AbstractOsmDataLayer.class).stream() + .filter(d -> ds.equals(d.getDataSet())).findAny().orElse(null); + if (toSwitch != null) { + MainApplication.getLayerManager().setActiveLayer(toSwitch); + } + } // precision is in meters precision = precision == 0 ? 1 : precision; String prefKey = "mapwithai.conflation.missingconflationtags"; @@ -79,6 +93,9 @@ public class MissingConnectionTags extends AbstractConflationCommand { fixErrors(prefKey, commands, findDuplicateNodes(possiblyAffectedPrimitives)); fixErrors(prefKey, commands, findCrossingWaysAtNodes(possiblyAffectedPrimitives)); ConditionalOptionPaneUtil.endBulkOperation(prefKey); + if (current != null) { + MainApplication.getLayerManager().setActiveLayer(current); + } GuiHelper.runInEDT(() -> getAffectedDataSet().setSelected(selection)); commands.forEach(Command::undoCommand); return commands.isEmpty() ? null : new SequenceCommand(tr("Perform missing conflation steps"), commands); @@ -149,7 +166,9 @@ public class MissingConnectionTags extends AbstractConflationCommand { way.getDataSet().searchWays(way.getBBox()).forEach(crossingWays::visit); crossingWays.endTest(); for (TestError error : crossingWays.getErrors()) { - if (seenFix.containsAll(error.getPrimitives())) { + if (seenFix.containsAll(error.getPrimitives()) + || error.getPrimitives().stream().filter(Way.class::isInstance).map(Way.class::cast) + .filter(w -> w.hasKey(HIGHWAY)).count() == 0L) { continue; } TestError.Builder fixError = TestError.builder(error.getTester(), error.getSeverity(), error.getCode()) @@ -164,11 +183,9 @@ public class MissingConnectionTags extends AbstractConflationCommand { } private Supplier createIntersectionCommandSupplier(TestError error, Way way) { - Collection nodes = Geometry - .addIntersections( - error.getPrimitives().stream().filter(Way.class::isInstance).map(Way.class::cast) - .filter(w -> w.hasKey("highway")).collect(Collectors.toList()), - false, new ArrayList<>()); + Collection nodes = Geometry.addIntersections(error.getPrimitives().stream().filter(Way.class::isInstance) + .map(Way.class::cast).filter(w -> w.hasKey(HIGHWAY)).collect(Collectors.toList()), false, + new ArrayList<>()); if (nodes.stream().anyMatch(n -> way.getNodes().stream().filter(MissingConnectionTags::noConflationKey) .anyMatch(wn -> n.getCoor().greatCircleDistance(wn.getCoor()) < precision))) { return () -> createIntersectionCommand(way, diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/cleanup/OverNodedWays.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/cleanup/OverNodedWays.java new file mode 100644 index 0000000..5d2e7a5 --- /dev/null +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/cleanup/OverNodedWays.java @@ -0,0 +1,101 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.cleanup; + +import static org.openstreetmap.josm.tools.I18n.tr; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import org.openstreetmap.josm.actions.AutoScaleAction; +import org.openstreetmap.josm.actions.SimplifyWayAction; +import org.openstreetmap.josm.command.Command; +import org.openstreetmap.josm.command.SequenceCommand; +import org.openstreetmap.josm.data.osm.DataSet; +import org.openstreetmap.josm.data.osm.Node; +import org.openstreetmap.josm.data.osm.OsmPrimitive; +import org.openstreetmap.josm.data.osm.Way; +import org.openstreetmap.josm.gui.MainApplication; +import org.openstreetmap.josm.gui.layer.AbstractOsmDataLayer; +import org.openstreetmap.josm.gui.layer.Layer; +import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.AbstractConflationCommand; +import org.openstreetmap.josm.spi.preferences.Config; +import org.openstreetmap.josm.tools.Utils; + +public class OverNodedWays extends AbstractConflationCommand { + + private double threshold; + private int acceptableRemovalPercentage; + + public OverNodedWays(DataSet data) { + super(data); + } + + @Override + public String getDescriptionText() { + return tr("Fix overnoded ways"); + } + + @Override + public Collection> getInterestedTypes() { + return Collections.singleton(Way.class); + } + + @Override + public String getKey() { + // Currently only interested in highways + return "highway"; + } + + @Override + public Command getRealCommand() { + threshold = Config.getPref().getDouble("mapwithai.conflation.simplifyway", 0.5); + acceptableRemovalPercentage = Config.getPref().getInt("mapwithai.conflation.simplifywaynodepercentagerequired", + 20); + Layer current = MainApplication.getLayerManager().getActiveLayer(); + Collection ways = Utils.filteredCollection(possiblyAffectedPrimitives, Way.class); + if (!ways.isEmpty()) { + DataSet ds = this.getAffectedDataSet(); + Layer toSwitch = MainApplication.getLayerManager().getLayersOfType(AbstractOsmDataLayer.class).stream() + .filter(d -> ds.equals(d.getDataSet())).findAny().orElse(null); + if (toSwitch != null) { + MainApplication.getLayerManager().setActiveLayer(toSwitch); + } + } + Collection commands = new ArrayList<>(); + for (Way way : ways) { + Command command = SimplifyWayAction.createSimplifyCommand(way, threshold); + if (command == null) { + continue; + } + int count = Utils.filteredCollection(new ArrayList<>(command.getParticipatingPrimitives()), Node.class) + .size(); + if ((count / (double) way.getNodesCount()) * 100 > this.acceptableRemovalPercentage) { + AutoScaleAction.zoomTo(Collections.singleton(way)); + double length = SimplifyWayAction.askSimplifyWays( + tr("You are about to simplify {0} way with a total length of {1}.", 1, way.getLength()), true); + commands.add(SimplifyWayAction.createSimplifyCommand(way, length)); + } + } + if (current != null) { + MainApplication.getLayerManager().setActiveLayer(current); + } + if (commands.size() == 1) { + return commands.iterator().next(); + } else if (!commands.isEmpty()) { + return new SequenceCommand(tr("Simplify ways"), commands); + } + return null; + } + + @Override + public boolean allowUndo() { + return false; + } + + @Override + public boolean keyShouldNotExistInOSM() { + return false; + } + +} diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/commands/CreateConnectionsCommand.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/commands/CreateConnectionsCommand.java index cae8e37..9534df0 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/commands/CreateConnectionsCommand.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/commands/CreateConnectionsCommand.java @@ -29,6 +29,7 @@ import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.Dupl import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.MergeAddressBuildings; import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.MergeBuildingAddress; import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.cleanup.MissingConnectionTags; +import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.cleanup.OverNodedWays; import org.openstreetmap.josm.tools.Logging; import org.openstreetmap.josm.tools.Utils; @@ -43,6 +44,7 @@ public class CreateConnectionsCommand extends Command { CONFLATION_COMMANDS.add(MergeAddressBuildings.class); CONFLATION_COMMANDS.add(MergeBuildingAddress.class); CONFLATION_COMMANDS.add(MissingConnectionTags.class); + CONFLATION_COMMANDS.add(OverNodedWays.class); } public CreateConnectionsCommand(DataSet data, Collection primitives) {