Ticket #20041: 20041.2.patch

File 20041.2.patch, 9.9 KB (added by GerdP, 5 years ago)
  • src/org/openstreetmap/josm/actions/AlignInCircleAction.java

     
    2727import org.openstreetmap.josm.data.osm.Node;
    2828import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2929import org.openstreetmap.josm.data.osm.Way;
     30import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
     31import org.openstreetmap.josm.data.validation.tests.SelfIntersectingWay;
    3032import org.openstreetmap.josm.gui.Notification;
    3133import org.openstreetmap.josm.tools.Geometry;
    3234import org.openstreetmap.josm.tools.Shortcut;
     
    5456    }
    5557
    5658    /**
    57      * Create a {@link MoveCommand} to move a node to a PolarCoor.
     59     * Add a {@link MoveCommand} to move a node to a PolarCoor if there is a significant move.
    5860     * @param n Node to move
    5961     * @param coor polar coordinate where to move the node
    60      * @return new MoveCommand
    61      * @since 13107
     62     * @param cmds list of commands
     63     * @since xxx
    6264     */
    63     public static MoveCommand createMoveCommand(Node n, PolarCoor coor) {
     65    public static void addMoveCommandIfNeeded(Node n, PolarCoor coor, List<Command> cmds) {
    6466        EastNorth en = coor.toEastNorth();
    65         return new MoveCommand(n, en.east() - n.getEastNorth().east(), en.north() - n.getEastNorth().north());
     67        double deltaEast = en.east() - n.getEastNorth().east();
     68        double deltaNorth = en.north() - n.getEastNorth().north();
     69        if (Math.abs(deltaEast) > 5e-6 || Math.abs(deltaNorth) > 5e-6) {
     70            cmds.add(new MoveCommand(n, deltaEast, deltaNorth));
     71        }
    6672    }
    6773
    6874    /**
     
    112118        if (ways.size() == 1 && !ways.get(0).isClosed()) {
    113119            // Case 1
    114120            Way w = ways.get(0);
     121            SelfIntersectingWay test = new SelfIntersectingWay();
     122            test.startTest(null);
     123            test.visit(w);
     124            test.endTest();
     125            if (!test.getErrors().isEmpty()) {
     126                showInvalidSelection(tr("Self-intersecting way"));
     127                return;
     128            }
     129
    115130            fixNodes.add(w.firstNode());
    116131            fixNodes.add(w.lastNode());
    117132            fixNodes.addAll(nodes);
     
    151166            fixNodes.addAll(collectNodesWithExternReferrers(ways));
    152167            nodes = collectNodesAnticlockwise(ways);
    153168            if (nodes.size() < 4) {
    154                 new Notification(
    155                         tr("Not enough nodes in selected ways."))
    156                 .setIcon(JOptionPane.INFORMATION_MESSAGE)
    157                 .setDuration(Notification.TIME_SHORT)
    158                 .show();
     169                showInvalidSelection(tr("Not enough nodes in selected ways."));
    159170                return;
    160171            }
    161172        } else if (ways.isEmpty() && nodes.size() > 3) {
     
    163174            fixNodes.addAll(nodes);
    164175            // No need to reorder nodes since all are fix
    165176        } else {
    166             // Invalid action
    167             new Notification(
    168                     tr("Please select at least four nodes."))
    169                     .setIcon(JOptionPane.INFORMATION_MESSAGE)
    170                     .setDuration(Notification.TIME_SHORT)
    171                     .show();
     177            showInvalidSelection(null);
    172178            return;
    173179        }
    174180
     181        if (!actionAllowed(nodes)) return;
     182
    175183        if (center == null) {
    176184            // Compute the center of nodes
    177185            center = Geometry.getCenter(nodes);
    178186            if (center == null) {
    179                 new Notification(tr("Cannot determine center of selected nodes."))
    180                     .setIcon(JOptionPane.INFORMATION_MESSAGE)
    181                     .setDuration(Notification.TIME_SHORT)
    182                     .show();
     187                showInvalidSelection(tr("Cannot determine center of selected nodes."));
    183188                return;
    184189            }
    185190        }
     
    194199            radius = radius / nodes.size();
    195200        }
    196201
    197         if (!actionAllowed(nodes)) return;
     202        List<Command> cmds = new LinkedList<>();
    198203
    199         Collection<Command> cmds = new LinkedList<>();
    200 
    201204        // Move each node to that distance from the center.
    202205        // Nodes that are not "fix" will be adjust making regular arcs.
    203206        int nodeCount = nodes.size();
     
    216219            }
    217220            Node first = nodes.get(i % nodeCount);
    218221            PolarCoor pcFirst = new PolarCoor(radius, PolarCoor.computeAngle(first.getEastNorth(), center), center);
    219             cmds.add(createMoveCommand(first, pcFirst));
     222            addMoveCommandIfNeeded(first, pcFirst, cmds);
    220223            if (j > i + 1) {
    221224                double delta;
    222225                if (j == i + nodeCount) {
     
    230233                }
    231234                for (int k = i+1; k < j; k++) {
    232235                    PolarCoor p = new PolarCoor(radius, pcFirst.angle + (k-i)*delta, center);
    233                     cmds.add(createMoveCommand(nodes.get(k % nodeCount), p));
     236                    addMoveCommandIfNeeded(nodes.get(k % nodeCount), p, cmds);
    234237                }
    235238            }
    236239            i = j; // Update start point for next iteration
    237240        }
     241        if (cmds.isEmpty()) {
     242            showInvalidSelection(null);
     243        } else {
     244            UndoRedoHandler.getInstance().add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
     245        }
     246    }
    238247
    239         UndoRedoHandler.getInstance().add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
     248    private static void showInvalidSelection(String message) {
     249        if (message == null)
     250            message = tr("Selection could not be used to align in circle.");
     251        // Invalid action
     252        new Notification(message)
     253                .setIcon(JOptionPane.INFORMATION_MESSAGE)
     254                .setDuration(Notification.TIME_SHORT)
     255                .show();
    240256    }
    241257
    242258    /**
     
    254270     * @return Nodes anticlockwise ordered
    255271     */
    256272    private static List<Node> collectNodesAnticlockwise(List<Way> ways) {
    257         List<Node> nodes = new ArrayList<>();
    258         Node firstNode = ways.get(0).firstNode();
    259         Node lastNode = null;
    260         Way lastWay = null;
    261         while (firstNode != lastNode) {
    262             if (lastNode == null) lastNode = firstNode;
    263             for (Way way: ways) {
    264                 if (way == lastWay) continue;
    265                 if (way.firstNode() == lastNode) {
    266                     List<Node> wayNodes = way.getNodes();
    267                     for (int i = 0; i < wayNodes.size() - 1; i++) {
    268                         nodes.add(wayNodes.get(i));
    269                     }
    270                     lastNode = way.lastNode();
    271                     lastWay = way;
    272                     break;
    273                 }
    274                 if (way.lastNode() == lastNode) {
    275                     List<Node> wayNodes = way.getNodes();
    276                     for (int i = wayNodes.size() - 1; i > 0; i--) {
    277                         nodes.add(wayNodes.get(i));
    278                     }
    279                     lastNode = way.firstNode();
    280                     lastWay = way;
    281                     break;
    282                 }
    283             }
    284         }
    285         // Check if nodes are in anticlockwise order
    286         int nc = nodes.size();
    287         double area = 0;
    288         for (int i = 0; i < nc; i++) {
    289             EastNorth p1 = nodes.get(i).getEastNorth();
    290             EastNorth p2 = nodes.get((i+1) % nc).getEastNorth();
    291             area += p1.east()*p2.north() - p2.east()*p1.north();
    292         }
    293         if (area < 0)
     273        List<Node> nodes = new ArrayList<>(Multipolygon.joinWays(ways).iterator().next().getNodes());
     274        if (Geometry.isClockwise(nodes))
    294275            Collections.reverse(nodes);
     276        nodes.remove(nodes.size() - 1);
    295277        return nodes;
    296278    }
    297279
     
    308290                    .setIcon(JOptionPane.WARNING_MESSAGE)
    309291                    .setDuration(Notification.TIME_SHORT)
    310292                    .show();
    311         return true;
     293        return !outside;
    312294    }
    313295
    314296    @Override
     
    323305    }
    324306
    325307    /**
    326      * Determines if ways can be joined into a polygon.
     308     * Determines if ways can be joined into a single polygon.
    327309     * @param ways The ways collection to check
    328      * @return true if all ways can be joined into a polygon
     310     * @return true if all ways can be joined into a single polygon
    329311     */
    330312    private static boolean checkWaysArePolygon(Collection<Way> ways) {
     313        if (Multipolygon.joinWays(ways).size() != 1)
     314            return false;
    331315        // For each way, nodes strictly between first and last should't be reference by an other way
    332316        for (Way way: ways) {
    333317            for (Node node: way.getNodes()) {
     
    337321                }
    338322            }
    339323        }
    340         // Test if ways can be joined
    341         Way currentWay = null;
    342         Node startNode = null, endNode = null;
    343         int used = 0;
    344         while (true) {
    345             Way nextWay = null;
    346             for (Way w: ways) {
    347                 if (w.isClosed()) return ways.size() == 1;
    348                 if (w == currentWay) continue;
    349                 if (currentWay == null) {
    350                     nextWay = w;
    351                     startNode = w.firstNode();
    352                     endNode = w.lastNode();
    353                     break;
    354                 }
    355                 if (w.firstNode() == endNode) {
    356                     nextWay = w;
    357                     endNode = w.lastNode();
    358                     break;
    359                 }
    360                 if (w.lastNode() == endNode) {
    361                     nextWay = w;
    362                     endNode = w.firstNode();
    363                     break;
    364                 }
    365             }
    366             if (nextWay == null) return false;
    367             used += 1;
    368             currentWay = nextWay;
    369             if (endNode == startNode) return used == ways.size();
    370         }
     324        return true;
    371325    }
     326
    372327}