Changeset 25862 in osm


Ignore:
Timestamp:
2011-04-17T13:35:54+02:00 (14 years ago)
Author:
zverik
Message:

replace grometry now preserves node history as well

File:
1 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/dumbutils/src/dumbutils/ReplaceGeometryAction.java

    r25859 r25862  
    11package dumbutils;
    22
     3import java.awt.geom.Point2D;
    34import java.awt.geom.Area;
    45import org.openstreetmap.josm.data.osm.Node;
     
    2324class ReplaceGeometryAction extends JosmAction {
    2425    private static final String TITLE = "Replace geometry";
     26    private static final double MAX_NODE_REPLACEMENT_DISTANCE = 3e-4;
    2527
    2628    public ReplaceGeometryAction() {
     
    4850        }
    4951
    50         // Now do the replacement
    51         List<Command> commands = new ArrayList<Command>();
    52         Way result = new Way(way);
    53         result.setNodes(geometry.getNodes());
    54         // Copy tags from temporary way (source etc.)
    55         for( String key : geometry.keySet() )
    56             result.put(key, geometry.get(key));
    57         commands.add(new ChangeCommand(way, result));
    58         commands.add(new DeleteCommand(geometry));
    59 
    60         // Check if there are unconnected nodes, delete them
    61         Set<Node> nodesToDelete = new HashSet<Node>();
     52        // Prepare a list of nodes that are not used anywhere except in the way
     53        Set<Node> nodePool = new HashSet<Node>();
    6254        Area a = getCurrentDataSet().getDataSourceArea();
    6355        for( Node node : way.getNodes() ) {
     
    6557            if( !node.isDeleted() && referrers.size() == 1 && referrers.get(0).equals(way)
    6658                    && (node.isNewOrUndeleted() || a.contains(node.getCoor())) )
    67                 nodesToDelete.add(node);
     59                nodePool.add(node);
    6860        }
    69         if( !nodesToDelete.isEmpty() )
    70             commands.add(new DeleteCommand(nodesToDelete));
     61
     62        // And the same for geometry, list nodes that can be freely deleted
     63        Set<Node> geometryPool = new HashSet<Node>();
     64        for( Node node : geometry.getNodes() ) {
     65            List<OsmPrimitive> referrers = node.getReferrers();
     66            if( node.isNew() && !node.isDeleted() && referrers.size() == 1
     67                    && referrers.get(0).equals(geometry) && !way.containsNode(node) )
     68                geometryPool.add(node);
     69        }
     70
     71        // Find new nodes that are closest to the old ones, remove matching old ones from the pool
     72        Map<Node, Node> nodeAssoc = new HashMap<Node, Node>();
     73        for( Node n : geometryPool ) {
     74            Node nearest = findNearestNode(n, nodePool);
     75            if( nearest != null ) {
     76                nodeAssoc.put(n, nearest);
     77                nodePool.remove(nearest);
     78            }
     79        }
     80
     81        // Now that we have replacement list, move all unused new nodes to nodePool (and delete them afterwards)
     82        for( Node n : geometryPool )
     83            if( nodeAssoc.containsKey(n) )
     84                nodePool.add(n);
     85
     86        // And prepare a list of nodes with all the replacements
     87        List<Node> geometryNodes = geometry.getNodes();
     88        for( int i = 0; i < geometryNodes.size(); i++ )
     89            if( nodeAssoc.containsKey(geometryNodes.get(i)) )
     90                geometryNodes.set(i, nodeAssoc.get(geometryNodes.get(i)));
     91
     92        // Now do the replacement
     93        List<Command> commands = new ArrayList<Command>();
     94        commands.add(new ChangeNodesCommand(way, geometryNodes));
     95
     96        // Move old nodes to new positions
     97        for( Node node : nodeAssoc.keySet() )
     98            commands.add(new MoveCommand(nodeAssoc.get(node), node.getCoor()));
     99
     100        // Copy tags from temporary way (source etc.)
     101        for( String key : geometry.keySet() )
     102            commands.add(new ChangePropertyCommand(way, key, geometry.get(key)));
     103
     104        // And delete odl geometry way
     105        commands.add(new DeleteCommand(geometry));
     106
     107        // Delete nodes that are not used anymore
     108        if( !nodePool.isEmpty() )
     109            commands.add(new DeleteCommand(nodePool));
    71110
    72111        // Two items in undo stack: change original way and delete geometry way
    73112        Main.main.undoRedo.add(new SequenceCommand(
    74                 tr("Replace geometry of way {0}", way.getDisplayName(DefaultNameFormatter.getInstance())),
     113                tr("Replace geometry for way {0}", way.getDisplayName(DefaultNameFormatter.getInstance())),
    75114                commands));
     115    }
     116
     117    /**
     118     * Find node from the collection which is nearest to <tt>node</tt>. Max distance is taken in consideration.
     119     * @return null if there is no such node.
     120     */
     121    private Node findNearestNode( Node node, Collection<Node> nodes ) {
     122        if( nodes.contains(node) )
     123            return node;
     124       
     125        Node nearest = null;
     126        double distance = MAX_NODE_REPLACEMENT_DISTANCE;
     127        Point2D coor = node.getCoor();
     128        for( Node n : nodes ) {
     129            double d = n.getCoor().distance(coor);
     130            if( d < distance ) {
     131                distance = d;
     132                nearest = n;
     133            }
     134        }
     135        return nearest;
    76136    }
    77137}
Note: See TracChangeset for help on using the changeset viewer.