Ticket #9223: bug9223-v4-dialog.patch

File bug9223-v4-dialog.patch, 11.8 KB (added by Balaitous, 10 years ago)

open dialog if nodes are outside of download area

  • src/org/openstreetmap/josm/actions/AlignInCircleAction.java

     
    44import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
    55import static org.openstreetmap.josm.tools.I18n.tr;
    66
     7import java.awt.GridBagLayout;
    78import java.awt.event.ActionEvent;
    89import java.awt.event.KeyEvent;
    910import java.math.BigDecimal;
     
    1415import java.util.List;
    1516import java.util.Set;
    1617
     18import javax.swing.JLabel;
    1719import javax.swing.JOptionPane;
     20import javax.swing.JPanel;
    1821
    1922import org.openstreetmap.josm.Main;
    2023import org.openstreetmap.josm.command.Command;
     
    2427import org.openstreetmap.josm.data.osm.Node;
    2528import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2629import org.openstreetmap.josm.data.osm.Way;
     30import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
    2731import org.openstreetmap.josm.gui.Notification;
    2832import org.openstreetmap.josm.tools.Geometry;
    2933import org.openstreetmap.josm.tools.Shortcut;
     
    8892            return new EastNorth(radius * Math.cos(angle - azimuth) + origin.east(), radius * Math.sin(angle - azimuth)
    8993                    + origin.north());
    9094        }
     95
     96        /**
     97         * Create a MoveCommand to move a node to this PolarCoor.
     98         * @param n Node to move
     99         * @return new MoveCommand
     100         */
     101        public MoveCommand createMoveCommand(Node n) {
     102            EastNorth en = toEastNorth();
     103            return new MoveCommand(n, en.east() - n.getEastNorth().east(), en.north() - n.getEastNorth().north());
     104        }
    91105    }
    92106
    93107    @Override
     
    112126
    113127        // special case if no single nodes are selected and exactly one way is:
    114128        // then use the way's nodes
    115         if ((nodes.size() <= 2) && (ways.size() == 1)) {
    116             Way way = ways.get(0);
    117 
     129        if ((nodes.size() <= 2) && checkWaysArePolygon(ways)) {
    118130            // some more special combinations:
    119131            // When is selected node that is part of the way, then make a regular polygon, selected
    120132            // node doesn't move.
     
    123135            // When one way and one node is selected, set center to position of that node.
    124136            // When one more node, part of the way, is selected, set the radius equal to the
    125137            // distance between two nodes.
    126             if (nodes.size() > 0) {
    127                 if (nodes.size() == 1 && way.containsNode(nodes.get(0)) && allowRegularPolygon(way.getNodes())) {
     138            if (nodes.size() == 1 && ways.size() == 1) {
     139                // Regular polygons are allowed only if there is just one way
     140                // Should be remove regular are now default for all nodes with no more than 1 referrer.
     141                Way way = ways.get(0);
     142                if (nodes.size() == 1 && way.containsNode(nodes.get(0)) && allowRegularPolygon(way.getNodes()))
    128143                    regular = true;
    129                 } else if (nodes.size() >= 2) {
    130                     center = nodes.get(way.containsNode(nodes.get(0)) ? 1 : 0).getEastNorth();
    131                     if (nodes.size() == 2) {
     144            }
     145            if (nodes.size() >= 1) {
     146                boolean[] isContained = new boolean[nodes.size()];
     147                for(int i = 0; i < nodes.size(); i++) {
     148                    Node n = nodes.get(i);
     149                    isContained[i] = false;
     150                    for(Way way: ways)
     151                        if(way.containsNode(n)) {
     152                            isContained[i] = true;
     153                            break;
     154                        }
     155                }
     156                if(nodes.size() == 1) {
     157                    if(!isContained[0])
     158                        center = nodes.get(0).getEastNorth();
     159                } else {
     160                    if(!isContained[0] && !isContained[1]) {
     161                        // 2 nodes outside of way, can't choose one as center
     162                        new Notification(
     163                                tr("Please select only one node as center."))
     164                                .setIcon(JOptionPane.INFORMATION_MESSAGE)
     165                                .setDuration(Notification.TIME_SHORT)
     166                                .show();
     167                        return;
     168                    } else if (!isContained[0] || !isContained[1]) {
     169                        // 1 node inside and 1 outside, outside is center, inside node define radius
     170                        center = nodes.get(isContained[0] ? 1 : 0).getEastNorth();
    132171                        radius = distance(nodes.get(0).getEastNorth(), nodes.get(1).getEastNorth());
     172                    } else {
     173                        // 2 nodes inside, define diameter
     174                        EastNorth en0 = nodes.get(0).getEastNorth();
     175                        EastNorth en1 = nodes.get(1).getEastNorth();
     176                        center = new EastNorth((en0.east() + en1.east()) / 2, (en0.north() + en1.north()) / 2);
     177                        radius = distance(en0, en1) / 2;
    133178                    }
    134179                }
    135                 nodes.clear();
    136180            }
     181            nodes.clear();
    137182
    138             for (Node n : way.getNodes()) {
    139                 if (!nodes.contains(n)) {
    140                     nodes.add(n);
     183            for(Way way: ways)
     184                for (Node n : way.getNodes()) {
     185                    if (!nodes.contains(n)) {
     186                        nodes.add(n);
     187                    }
    141188                }
    142             }
    143189        }
    144190
    145191        if (nodes.size() < 4) {
     
    223269                cmds.add(new MoveCommand(n, no.east() - n.getEastNorth().east(), no.north() - n.getEastNorth().north()));
    224270                pc.angle += angle;
    225271            }
    226         } else { // Move each node to that distance from the centre.
    227             for (Node n : nodes) {
    228                 pc = new PolarCoor(n.getEastNorth(), center, 0);
    229                 pc.radius = radius;
    230                 EastNorth no = pc.toEastNorth();
    231                 cmds.add(new MoveCommand(n, no.east() - n.getEastNorth().east(), no.north() - n.getEastNorth().north()));
     272        } else { // Move each node to that distance from the center.
     273            int nodeCount = nodes.size();
     274            // Search first fixed node
     275            int startPosition = 0;
     276            for(startPosition = 0; startPosition < nodeCount; startPosition++)
     277                if(isFixNode(nodes.get(startPosition % nodeCount), sel)) break;
     278            int i = startPosition; // Start position for current arc
     279            int j; // End position for current arc
     280            while(i < startPosition + nodeCount) {
     281                for(j = i + 1; j < startPosition + nodeCount; j++)
     282                    if(isFixNode(nodes.get(j % nodeCount), sel)) break;
     283                Node first = nodes.get(i % nodeCount);
     284                PolarCoor pcFirst = new PolarCoor(first.getEastNorth(), center, 0);
     285                pcFirst.radius = radius;
     286                cmds.add(pcFirst.createMoveCommand(first));
     287                if(j > i + 1) {
     288                    double delta;
     289                    if(j == i + nodeCount) {
     290                        delta = 2 * Math.PI / nodeCount;
     291                    } else {
     292                        PolarCoor pcLast = new PolarCoor(nodes.get(j % nodeCount).getEastNorth(), center, 0);
     293                        delta = pcLast.angle - pcFirst.angle;
     294                        if(delta < 0) // Assume each PolarCoor.angle is in range ]-pi; pi]
     295                            delta +=  2*Math.PI;
     296                        delta /= j - i;
     297                    }
     298                    for(int k = i+1; k < j; k++) {
     299                        PolarCoor p = new PolarCoor(radius, pcFirst.angle + (k-i)*delta, center, 0);
     300                        cmds.add(p.createMoveCommand(nodes.get(k % nodeCount)));
     301                    }
     302                }
     303                i = j; // Update start point for next iteration
    232304            }
    233305        }
     306       
     307        if(!actionAllowed(nodes)) return;
    234308
    235309        Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
    236310        Main.map.repaint();
    237311    }
    238312
     313    /**
     314     * Check if one or more nodes are outside of download area
     315     * @param nodes Nodes to check
     316     * @return true if action can be done
     317     */
     318    private boolean actionAllowed(Collection<Node> nodes) {
     319        boolean outside = false;
     320        for(Node n: nodes)
     321            if(n.isOutsideDownloadArea()) {
     322                outside = true;
     323                break;
     324            }
     325        if(outside) {
     326            JPanel msg = new JPanel(new GridBagLayout());
     327            msg.add(new JLabel("<html>" +
     328                    tr("One or more nodes involved in this action are outside of the downloaded area.") +
     329                    "<br/>" +
     330                    tr("Are you really sure to continue?") +
     331                    "</html>"));
     332            return ConditionalOptionPaneUtil.showConfirmationDialog(
     333                    "alignincircle_outside_nodes",
     334                    Main.parent,
     335                    msg,
     336                    tr("The selected area is incomplete. Continue?"),
     337                    JOptionPane.YES_NO_OPTION,
     338                    JOptionPane.QUESTION_MESSAGE,
     339                    JOptionPane.YES_OPTION);
     340        }
     341        return true;
     342    }
     343   
     344    /**
     345     * Test if angle of a node can be change.
     346     * @param n Node
     347     * @param sel Selection which action is apply
     348     * @return true is this node does't have a fix angle
     349     */
     350    private boolean isFixNode(Node n, Collection<OsmPrimitive> sel) {
     351        List<OsmPrimitive> referrers = n.getReferrers();
     352        if(referrers.isEmpty()) return false;
     353        if(sel.contains(n) || referrers.size() > 1 || !sel.contains(referrers.get(0))) return true;
     354        return false;
     355    }
     356   
    239357    @Override
    240358    protected void updateEnabledState() {
    241359        setEnabled(getCurrentDataSet() != null && !getCurrentDataSet().getSelected().isEmpty());
     
    261379        }
    262380        return true;
    263381    }
     382
     383    /**
     384     * Determines if ways can be joined into a polygon.
     385     * @param ways The ways collection to check
     386     * @return true if all ways can be joined into a polygon
     387     */
     388    protected static boolean checkWaysArePolygon(Collection<Way> ways) {
     389        // For each way, nodes strictly between first and last should't be reference by an other way
     390        for(Way way: ways) {
     391            for(Node node: way.getNodes()) {
     392                if(node == way.firstNode() || node == way.lastNode()) continue;
     393                for(Way wayOther: ways) {
     394                    if(way == wayOther) continue;
     395                    if(node.getReferrers().contains(wayOther)) return false;
     396                }
     397            }
     398        }
     399        // Test if ways can be joined
     400        Way currentWay = null;
     401        Node startNode = null, endNode = null;
     402        int used = 0;
     403        while(true) {
     404            Way nextWay = null;
     405            for(Way w: ways) {
     406                if(w.firstNode() == w.lastNode()) return ways.size() == 1;
     407                if(w == currentWay) continue;
     408                if(currentWay == null) {
     409                    nextWay = w;
     410                    startNode = w.firstNode();
     411                    endNode = w.lastNode();
     412                    break;
     413                }
     414                if(w.firstNode() == endNode) {
     415                    nextWay = w;
     416                    endNode = w.lastNode();
     417                    break;
     418                }
     419                if(w.lastNode() == endNode) {
     420                    nextWay = w;
     421                    endNode = w.firstNode();
     422                    break;
     423                }
     424            }
     425            if(nextWay == null) return false;
     426            used += 1;
     427            currentWay = nextWay;
     428            if(endNode == startNode) return used == ways.size();
     429        }
     430    }
    264431}