Ticket #20041: 20041.patch

File 20041.patch, 7.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;
    3031import org.openstreetmap.josm.gui.Notification;
    3132import org.openstreetmap.josm.tools.Geometry;
    3233import org.openstreetmap.josm.tools.Shortcut;
     
    5455    }
    5556
    5657    /**
    57      * Create a {@link MoveCommand} to move a node to a PolarCoor.
     58     * Add a {@link MoveCommand} to move a node to a PolarCoor if there is a significant move.
    5859     * @param n Node to move
    5960     * @param coor polar coordinate where to move the node
    60      * @return new MoveCommand
    61      * @since 13107
     61     * @param cmds list of commands
     62     * @since xxx
    6263     */
    63     public static MoveCommand createMoveCommand(Node n, PolarCoor coor) {
     64    public static void addMoveCommandIfNeeded(Node n, PolarCoor coor, List<Command> cmds) {
    6465        EastNorth en = coor.toEastNorth();
    65         return new MoveCommand(n, en.east() - n.getEastNorth().east(), en.north() - n.getEastNorth().north());
     66        double deltaEast = en.east() - n.getEastNorth().east();
     67        double deltaNorth = en.north() - n.getEastNorth().north();
     68        if (Math.abs(deltaEast) > 5e-6 || Math.abs(deltaNorth) > 5e-6) {
     69            cmds.add(new MoveCommand(n, deltaEast, deltaNorth));
     70        }
    6671    }
    6772
    6873    /**
     
    163168            fixNodes.addAll(nodes);
    164169            // No need to reorder nodes since all are fix
    165170        } 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();
     171            showBadSelection();
    172172            return;
    173173        }
    174174
     175        if (!actionAllowed(nodes)) return;
     176
    175177        if (center == null) {
    176178            // Compute the center of nodes
    177179            center = Geometry.getCenter(nodes);
     
    194196            radius = radius / nodes.size();
    195197        }
    196198
    197         if (!actionAllowed(nodes)) return;
     199        List<Command> cmds = new LinkedList<>();
    198200
    199         Collection<Command> cmds = new LinkedList<>();
    200 
    201201        // Move each node to that distance from the center.
    202202        // Nodes that are not "fix" will be adjust making regular arcs.
    203203        int nodeCount = nodes.size();
     
    216216            }
    217217            Node first = nodes.get(i % nodeCount);
    218218            PolarCoor pcFirst = new PolarCoor(radius, PolarCoor.computeAngle(first.getEastNorth(), center), center);
    219             cmds.add(createMoveCommand(first, pcFirst));
     219            addMoveCommandIfNeeded(first, pcFirst, cmds);
    220220            if (j > i + 1) {
    221221                double delta;
    222222                if (j == i + nodeCount) {
     
    230230                }
    231231                for (int k = i+1; k < j; k++) {
    232232                    PolarCoor p = new PolarCoor(radius, pcFirst.angle + (k-i)*delta, center);
    233                     cmds.add(createMoveCommand(nodes.get(k % nodeCount), p));
     233                    addMoveCommandIfNeeded(nodes.get(k % nodeCount), p, cmds);
    234234                }
    235235            }
    236236            i = j; // Update start point for next iteration
    237237        }
     238        if (cmds.isEmpty()) {
     239            showBadSelection();
     240        } else {
     241            UndoRedoHandler.getInstance().add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
     242        }
     243    }
    238244
    239         UndoRedoHandler.getInstance().add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
     245    private void showBadSelection() {
     246        // Invalid action
     247        new Notification(
     248                tr("Selection could not be used to align in circle."))
     249                .setIcon(JOptionPane.INFORMATION_MESSAGE)
     250                .setDuration(Notification.TIME_SHORT)
     251                .show();
    240252    }
    241253
    242254    /**
     
    254266     * @return Nodes anticlockwise ordered
    255267     */
    256268    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)
     269        List<Node> nodes = new ArrayList<>(Multipolygon.joinWays(ways).iterator().next().getNodes());
     270        if (Geometry.isClockwise(nodes))
    294271            Collections.reverse(nodes);
     272        nodes.remove(nodes.size() - 1);
    295273        return nodes;
    296274    }
    297275
     
    323301    }
    324302
    325303    /**
    326      * Determines if ways can be joined into a polygon.
     304     * Determines if ways can be joined into a single polygon.
    327305     * @param ways The ways collection to check
    328      * @return true if all ways can be joined into a polygon
     306     * @return true if all ways can be joined into a single polygon
    329307     */
    330308    private static boolean checkWaysArePolygon(Collection<Way> ways) {
     309        if (Multipolygon.joinWays(ways).size() != 1)
     310            return false;
    331311        // For each way, nodes strictly between first and last should't be reference by an other way
    332312        for (Way way: ways) {
    333313            for (Node node: way.getNodes()) {
     
    337317                }
    338318            }
    339319        }
    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         }
     320        return true;
    371321    }
     322
    372323}