Ignore:
Timestamp:
2024-02-21T08:25:24+01:00 (11 months ago)
Author:
GerdP
Message:

fix #23505: incorrect number of modified ways in command, improve performance, fix memory leak

  • collect modifed ways to avoid two change commands per way
  • use ChangeNodesCommand instead of ChangeCommand to avoid memory leak
  • use core code to check if nodes are outside downloaded area
  • store selected ways in HashSet to avoid multiple sequential searches in averageNearbyNodes()
File:
1 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/simplifyarea/src/org/openstreetmap/josm/plugins/simplifyarea/SimplifyAreaAction.java

    r35978 r36209  
    1414import java.util.HashMap;
    1515import java.util.HashSet;
     16import java.util.LinkedHashSet;
    1617import java.util.List;
    1718import java.util.Map;
     
    2223
    2324import org.openstreetmap.josm.actions.JosmAction;
    24 import org.openstreetmap.josm.command.ChangeCommand;
     25import org.openstreetmap.josm.command.ChangeNodesCommand;
    2526import org.openstreetmap.josm.command.Command;
    2627import org.openstreetmap.josm.command.DeleteCommand;
    2728import org.openstreetmap.josm.command.MoveCommand;
    2829import org.openstreetmap.josm.command.SequenceCommand;
    29 import org.openstreetmap.josm.data.Bounds;
    3030import org.openstreetmap.josm.data.UndoRedoHandler;
    3131import org.openstreetmap.josm.data.coor.ILatLon;
     
    4141import org.openstreetmap.josm.tools.ImageProvider;
    4242import org.openstreetmap.josm.tools.Shortcut;
    43 import org.openstreetmap.josm.tools.Utils;
    4443
    4544public final class SimplifyAreaAction extends JosmAction {
     
    4948                Shortcut.registerShortcut("tools:simplifyArea", tr("More tools: {0}", tr("Simplify Area")), KeyEvent.VK_Y, Shortcut.CTRL_SHIFT),
    5049                true, "simplifyarea", true);
    51     }
    52 
    53     private List<Bounds> getCurrentEditBounds() {
    54         return MainApplication.getLayerManager().getEditLayer().data.getDataSourceBounds();
    55     }
    56 
    57     private static boolean isInBounds(final Node node, final List<Bounds> bounds) {
    58         for (final Bounds b : bounds) {
    59             if (b.contains(node)) {
    60                 return true;
    61             }
    62         }
    63         return false;
    6450    }
    6551
     
    9177    @Override
    9278    public void actionPerformed(final ActionEvent e) {
    93         final Collection<OsmPrimitive> selection = getLayerManager().getEditDataSet().getSelected();
    94 
    95         final List<Bounds> bounds = getCurrentEditBounds();
    96         for (final OsmPrimitive prim : selection) {
    97             if (prim instanceof Way && bounds.size() > 0) {
    98                 final Way way = (Way) prim;
    99                 // We check if each node of each way is at least in one download
    100                 // bounding box. Otherwise nodes may get deleted that are necessary by
    101                 // unloaded ways (see Ticket #1594)
    102                 for (final Node node : way.getNodes()) {
    103                     if (!isInBounds(node, bounds)) {
    104                         if (!confirmWayWithNodesOutsideBoundingBox()) {
    105                             return;
    106                         }
    107                         break;
    108                     }
    109                 }
    110             }
    111         }
    112         final Collection<Way> ways = Utils.filteredCollection(selection, Way.class);
     79        final Collection<Way> ways = new LinkedHashSet<>(getLayerManager().getEditDataSet().getSelectedWays());
     80        ways.removeIf(w -> !w.isUsable());
     81        int checkRes = Command.checkOutlyingOrIncompleteOperation(ways, null);
     82        if ((checkRes & Command.IS_OUTSIDE) != 0) {
     83            if (!confirmWayWithNodesOutsideBoundingBox())
     84                return;
     85        }
    11386        if (ways.isEmpty()) {
    11487            alertSelectAtLeastOneWay();
     
    147120
    148121        final Collection<Command> allCommands = new ArrayList<>();
     122        Map<Way, List<Node>> modifiedWays = new HashMap<>();
    149123
    150124        if (!nodesReallyToRemove.isEmpty()) {
     
    160134                        nodes.add(nodes.get(0));
    161135                    }
    162 
    163                     final Way newWay = new Way(way);
    164                     newWay.setNodes(nodes);
    165                     allCommands.add(new ChangeCommand(way, newWay));
     136                    allCommands.add(new ChangeNodesCommand(way, nodes));
     137                    modifiedWays.put(way, nodes);
    166138                }
    167139            }
     
    170142        }
    171143
    172         final Collection<Command> avgCommands = averageNearbyNodes(ways, nodesReallyToRemove);
     144        final Collection<Command> avgCommands = averageNearbyNodes(ways, nodesReallyToRemove, modifiedWays);
    173145        if (avgCommands != null && !avgCommands.isEmpty()) {
    174146            allCommands.add(new SequenceCommand(tr("average nearby nodes"), avgCommands));
     
    176148
    177149        if (!allCommands.isEmpty()) {
    178             final SequenceCommand rootCommand = new SequenceCommand(trn("Simplify {0} way", "Simplify {0} ways", allCommands.size(), allCommands.size()), allCommands);
     150            final SequenceCommand rootCommand = new SequenceCommand(trn("Simplify {0} way", "Simplify {0} ways", modifiedWays.size(), modifiedWays.size()), allCommands);
    179151            UndoRedoHandler.getInstance().add(rootCommand);
    180152            MainApplication.getMap().repaint();
     
    200172
    201173    // average nearby nodes
    202     private static Collection<Command> averageNearbyNodes(final Collection<Way> ways, final Collection<Node> nodesAlreadyDeleted) {
     174    private static Collection<Command> averageNearbyNodes(final Collection<Way> ways, final Collection<Node> nodesAlreadyDeleted, Map<Way, List<Node>> modifiedWays) {
    203175        final double mergeThreshold = Config.getPref().getDouble(SimplifyAreaPreferenceSetting.MERGE_THRESHOLD, 0.2);
    204176
     
    254226
    255227                    // test if both nodes have same parents
    256                     if (!referrers.containsAll(referrers2) || !referrers2.containsAll(referrers)) {
     228                    if (referrers.size() != referrers2.size() || !referrers2.containsAll(referrers)) {
    257229                        continue;
    258230                    }
     
    290262            if (nodesToDelete.removeAll(coordMap.keySet())) {
    291263                nodesToDelete2.addAll(nodesToDelete);
    292                 final Way newWay = new Way(way);
    293264                final List<Node> nodes = way.getNodes();
    294265                final boolean closed = nodes.get(0).equals(nodes.get(nodes.size() - 1));
     
    301272                }
    302273
    303                 newWay.setNodes(nodes);
    304274                if (!way.getNodes().equals(nodes)) {
    305                     commands.add(new ChangeCommand(way, newWay));
     275                    List<Node> nodes1 = modifiedWays.get(way);
     276                    if (nodes1 == null || !nodes.equals(nodes1)) {
     277                        commands.add(new ChangeNodesCommand(way, nodes));
     278                        modifiedWays.put(way, nodes);
     279                    }
    306280                }
    307281            }
     
    421395
    422396    public static double computeConvectAngle(final ILatLon coord1, final ILatLon coord2, final ILatLon coord3) {
    423         final double angle =  Math.abs(heading(coord2, coord3) - heading(coord1, coord2));
     397        final double angle = Math.abs(heading(coord2, coord3) - heading(coord1, coord2));
    424398        return Math.toDegrees(angle < Math.PI ? angle : 2 * Math.PI - angle);
    425399    }
     
    436410    }
    437411
    438     public static double R = 6378135;
     412    public static final double R = 6378135;
    439413
    440414    public static double crossTrackError(final ILatLon l1, final ILatLon l2, final ILatLon l3) {
Note: See TracChangeset for help on using the changeset viewer.