Ignore:
Timestamp:
2012-01-20T00:49:33+01:00 (13 years ago)
Author:
joshdoe
Message:

utilsplugin2: Replace geometry command now replaces a node with a way #7277

File:
1 edited

Legend:

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

    r26885 r27505  
    1818
    1919/**
    20  * Replaces already existing way with the other, fresh created. Select both ways and push the button.
     20 * Replaces already existing object (id>0) with a new object (id<0).
    2121 *
    2222 * @author Zverik
     
    2727
    2828    public ReplaceGeometryAction() {
    29         super(TITLE, "dumbutils/replacegeometry", tr("Replace geometry of selected way with a new one"),
     29        super(TITLE, "dumbutils/replacegeometry", tr("Replace geometry of selected object with a new one"),
    3030                Shortcut.registerShortcut("tools:replacegeometry", tr("Tool: {0}", TITLE), KeyEvent.VK_G,
    3131                Shortcut.GROUP_HOTKEY, Shortcut.SHIFT_DEFAULT), true);
     
    3333
    3434    @Override
    35     public void actionPerformed( ActionEvent e ) {
    36         if( getCurrentDataSet() == null ) return;
     35    public void actionPerformed(ActionEvent e) {
     36        if (getCurrentDataSet() == null) {
     37            return;
     38        }
     39
    3740        // There must be two ways selected: one with id > 0 and one new.
    38         List<Way> selection = OsmPrimitive.getFilteredList(getCurrentDataSet().getSelected(), Way.class);
    39         if( selection.size() != 2 ) {
     41        List<OsmPrimitive> selection = new ArrayList(getCurrentDataSet().getSelected());
     42        if (selection.size() != 2) {
    4043            JOptionPane.showMessageDialog(Main.parent,
    41                     tr("This tool replaces geometry of one way with another, and requires two ways to be selected."),
     44                    tr("This tool replaces geometry of one object with another, and so requires exactly two objects to be selected."),
    4245                    TITLE, JOptionPane.INFORMATION_MESSAGE);
    4346            return;
    4447        }
     48
     49        OsmPrimitive firstObject = selection.get(0);
     50        OsmPrimitive secondObject = selection.get(1);
     51
     52        if (firstObject instanceof Way && secondObject instanceof Way) {
     53            replaceWayWithWay(Arrays.asList((Way) firstObject, (Way) secondObject));
     54        } else if (firstObject instanceof Node && secondObject instanceof Way) {
     55            replaceNodeWithWay((Node) firstObject, (Way) secondObject);
     56        } else if (secondObject instanceof Node && firstObject instanceof Way) {
     57            replaceNodeWithWay((Node) secondObject, (Way) firstObject);
     58        } else {
     59            JOptionPane.showMessageDialog(Main.parent,
     60                    tr("This tool can only replace a node with a way, or a way with a way."),
     61                    TITLE, JOptionPane.INFORMATION_MESSAGE);
     62            return;
     63        }
     64    }
     65   
     66    public void replaceNodeWithWay(Node node, Way way) {
     67        if (!node.getReferrers().isEmpty()) {
     68            JOptionPane.showMessageDialog(Main.parent, tr("Node has referrers, cannot replace with way."), TITLE, JOptionPane.INFORMATION_MESSAGE);
     69            return;
     70        }
     71        Node nodeToReplace = null;
     72        // see if we need to replace a node in the replacement way
     73        if (!node.isNew()) {
     74            // Prepare a list of nodes that are not used anywhere except in the way
     75            Collection<Node> nodePool = getUnimportantNodes(way);
     76            nodeToReplace = findNearestNode(node, nodePool);
     77        }
     78       
     79        List<Command> commands = new ArrayList<Command>();
     80        AbstractMap<String, String> nodeTags = (AbstractMap<String, String>) node.getKeys();
     81       
     82        // replace sacrificial node in way with node that is being upgraded
     83        if (nodeToReplace != null) {
     84            List<Node> wayNodes = way.getNodes();
     85            int idx = wayNodes.indexOf(nodeToReplace);
     86            wayNodes.set(idx, node);
     87            if (idx == 0) {
     88                // node is at start/end of way
     89                wayNodes.set(wayNodes.size() - 1, node);
     90            }
     91            commands.add(new ChangeNodesCommand(way, wayNodes));
     92            commands.add(new MoveCommand(node, nodeToReplace.getCoor()));
     93            commands.add(new DeleteCommand(nodeToReplace));
     94           
     95            // delete tags from node
     96            if (!nodeTags.isEmpty()) {
     97                AbstractMap<String, String> nodeTagsToDelete = new HashMap<String, String>();
     98                for (String key : nodeTags.keySet()) {
     99                    nodeTagsToDelete.put(key, null);
     100                }
     101                commands.add(new ChangePropertyCommand(Arrays.asList(node), nodeTagsToDelete));
     102            }
     103        } else {
     104            // no node to replace, so just delete the original node
     105            commands.add(new DeleteCommand(node));
     106        }
     107
     108        // Copy tags from node
     109        // TODO: use merge tag conflict dialog instead
     110        commands.add(new ChangePropertyCommand(Arrays.asList(way), nodeTags));
     111       
     112        getCurrentDataSet().setSelected(way);
     113       
     114        Main.main.undoRedo.add(new SequenceCommand(
     115                tr("Replace geometry for way {0}", way.getDisplayName(DefaultNameFormatter.getInstance())),
     116                commands));
     117    }
     118   
     119    public void replaceWayWithWay(List<Way> selection) {
     120        boolean overrideNewCheck = false;
    45121        int idxNew = selection.get(0).isNew() ? 0 : 1;
    46         boolean overrideNewCheck = false;
    47         if( selection.get(1-idxNew).isNew() ) {
    48             // if both are new, select the one with all the DB nodes
    49             boolean areNewNodes = false;
    50             for( Node n : selection.get(0).getNodes() )
    51                 if( n.isNew() )
    52                     areNewNodes = true;
    53             idxNew = areNewNodes ? 0 : 1;
    54             overrideNewCheck = true;
    55             for( Node n : selection.get(1-idxNew).getNodes() )
    56                 if( n.isNew() )
    57                     overrideNewCheck = false;
    58         }
     122
     123        if( selection.get(1-idxNew).isNew() ) {
     124            // if both are new, select the one with all the DB nodes
     125            boolean areNewNodes = false;
     126            for (Node n : selection.get(0).getNodes()) {
     127                if (n.isNew()) {
     128                    areNewNodes = true;
     129                }
     130            }
     131            idxNew = areNewNodes ? 0 : 1;
     132            overrideNewCheck = true;
     133            for (Node n : selection.get(1 - idxNew).getNodes()) {
     134                if (n.isNew()) {
     135                    overrideNewCheck = false;
     136                }
     137            }
     138        }
    59139        Way geometry = selection.get(idxNew);
    60140        Way way = selection.get(1 - idxNew);
     
    67147
    68148        // Prepare a list of nodes that are not used anywhere except in the way
    69         Set<Node> nodePool = new HashSet<Node>();
    70         Area a = getCurrentDataSet().getDataSourceArea();
    71         for( Node node : way.getNodes() ) {
    72             List<OsmPrimitive> referrers = node.getReferrers();
    73             if( !node.isDeleted() && referrers.size() == 1 && referrers.get(0).equals(way)
    74                     && (node.isNewOrUndeleted() || a == null || a.contains(node.getCoor())) )
    75                 nodePool.add(node);
    76         }
     149        Collection<Node> nodePool = getUnimportantNodes(way);
    77150
    78151        // And the same for geometry, list nodes that can be freely deleted
     
    134207    }
    135208
     209    /**
     210     * Create a list of nodes that are not used anywhere except in the way.
     211     * @param way
     212     * @return
     213     */
     214    public Collection<Node> getUnimportantNodes(Way way) {
     215        Set<Node> nodePool = new HashSet<Node>();
     216        Area a = getCurrentDataSet().getDataSourceArea();
     217        for (Node n : way.getNodes()) {
     218            List<OsmPrimitive> referrers = n.getReferrers();
     219            if (!n.isDeleted() && referrers.size() == 1 && referrers.get(0).equals(way)
     220                    && (n.isNewOrUndeleted() || a == null || a.contains(n.getCoor()))) {
     221                nodePool.add(n);
     222            }
     223        }
     224        return nodePool;
     225    }
     226   
    136227    /**
    137228     * Find node from the collection which is nearest to <tt>node</tt>. Max distance is taken in consideration.
Note: See TracChangeset for help on using the changeset viewer.