Changeset 8303 in josm for trunk/src/org/openstreetmap/josm


Ignore:
Timestamp:
2015-05-01T21:33:01+02:00 (9 years ago)
Author:
Balaitous
Message:

fix #7421 - Circle created from way heads always clockwise

  • If 3 nodes closed way is selected, keep way direction when creating circle;
  • Otherwise use left- and right-hand traffic database (r7193) to determine way direction;
  • Add a Geometry.isClockwise(List<Node>) method;
  • Fix some sonar issue
  • Add test case
Location:
trunk/src/org/openstreetmap/josm
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/CreateCircleAction.java

    r8285 r8303  
    1010import java.util.Arrays;
    1111import java.util.Collection;
     12import java.util.Collections;
    1213import java.util.Comparator;
    1314import java.util.LinkedList;
     
    2829import org.openstreetmap.josm.gui.Notification;
    2930import org.openstreetmap.josm.tools.Geometry;
     31import org.openstreetmap.josm.tools.RightAndLefthandTraffic;
    3032import org.openstreetmap.josm.tools.Shortcut;
    3133
     
    115117        @Override
    116118        public int compare(PolarNode pc1, PolarNode pc2) {
    117             if(pc1.a < pc2.a)
    118                 return -1;
    119             else if(pc1.a == pc2.a)
    120                 return 0;
    121             else
    122                 return 1;
     119            return Double.compare(pc1.a, pc2.a);
    123120        }
    124121    }
     
    137134
    138135        Collection<OsmPrimitive> sel = getCurrentDataSet().getSelected();
    139         List<Node> nodes = new LinkedList<>();
     136        List<Node> nodes = OsmPrimitive.getFilteredList(sel, Node.class);
     137        List<Way> ways = OsmPrimitive.getFilteredList(sel, Way.class);
     138
    140139        Way existingWay = null;
    141 
    142         for (OsmPrimitive osm : sel)
    143             if (osm instanceof Node) {
    144                 nodes.add((Node)osm);
    145             }
    146140
    147141        // special case if no single nodes are selected and exactly one way is:
    148142        // then use the way's nodes
    149         if (nodes.isEmpty() && (sel.size() == 1)) {
    150             for (OsmPrimitive osm : sel)
    151                 if (osm instanceof Way) {
    152                     existingWay = ((Way)osm);
    153                     for (Node n : ((Way)osm).getNodes())
    154                     {
    155                         if(!nodes.contains(n)) {
    156                             nodes.add(n);
    157                         }
    158                     }
     143        if (nodes.isEmpty() && (ways.size() == 1)) {
     144            existingWay = ways.get(0);
     145            for (Node n : existingWay.getNodes()) {
     146                if(!nodes.contains(n)) {
     147                    nodes.add(n);
    159148                }
     149            }
    160150        }
    161151
     
    210200
    211201        // build a way for the circle
    212         List<Node> wayToAdd = new ArrayList<>();
     202        List<Node> nodesToAdd = new ArrayList<>();
    213203        for(int i = 0; i < nodes.size(); i++) {
    214             wayToAdd.add(angles[i].node);
     204            nodesToAdd.add(angles[i].node);
    215205            double delta = angles[(i+1) % nodes.size()].a - angles[i].a;
    216206            if(delta < 0)
     
    226216                }
    227217                Node n = new Node(ll);
    228                 wayToAdd.add(n);
     218                nodesToAdd.add(n);
    229219                cmds.add(new AddCommand(n));
    230220            }
    231221        }
    232         wayToAdd.add(wayToAdd.get(0)); // close the circle
     222        nodesToAdd.add(nodesToAdd.get(0)); // close the circle
     223        if (existingWay != null && existingWay.getNodesCount() >= 3) {
     224            nodesToAdd = orderNodesByWay(nodesToAdd, existingWay);
     225        } else {
     226            nodesToAdd = orderNodesByTrafficHand(nodesToAdd);
     227        }
    233228        if (existingWay == null) {
    234229            Way newWay = new Way();
    235             newWay.setNodes(wayToAdd);
     230            newWay.setNodes(nodesToAdd);
    236231            cmds.add(new AddCommand(newWay));
    237232        } else {
    238233            Way newWay = new Way(existingWay);
    239             newWay.setNodes(wayToAdd);
     234            newWay.setNodes(nodesToAdd);
    240235            cmds.add(new ChangeCommand(existingWay, newWay));
    241236        }
     
    243238        Main.main.undoRedo.add(new SequenceCommand(tr("Create Circle"), cmds));
    244239        Main.map.repaint();
     240    }
     241
     242    /**
     243     * Order nodes according to left/right hand traffic.
     244     * @param nodes Nodes list to be ordered.
     245     * @return Modified nodes list ordered according hand traffic.
     246     */
     247    private List<Node> orderNodesByTrafficHand(List<Node> nodes) {
     248        boolean rightHandTraffic = true;
     249        for (Node n: nodes) {
     250            if (!RightAndLefthandTraffic.isRightHandTraffic(n.getCoor())) {
     251                rightHandTraffic = false;
     252                break;
     253            }
     254        }
     255        if (rightHandTraffic == Geometry.isClockwise(nodes)) {
     256            Collections.reverse(nodes);
     257        }
     258        return nodes;
     259    }
     260
     261    /**
     262     * Order nodes according to way direction.
     263     * @param nodes Nodes list to be ordered.
     264     * @param way Way used to determine direction.
     265     * @return Modified nodes list with same direction as way.
     266     */
     267    private List<Node> orderNodesByWay(List<Node> nodes, Way way) {
     268        List<Node> wayNodes = way.getNodes();
     269        if (!way.isClosed()) {
     270            wayNodes.add(wayNodes.get(0));
     271        }
     272        if (Geometry.isClockwise(wayNodes) != Geometry.isClockwise(nodes)) {
     273            Collections.reverse(nodes);
     274        }
     275        return nodes;
    245276    }
    246277
  • trunk/src/org/openstreetmap/josm/tools/Geometry.java

    r8127 r8303  
    688688     */
    689689    public static boolean isClockwise(Way w) {
    690         if (!w.isClosed()) {
     690        return isClockwise(w.getNodes());
     691    }
     692
     693    /**
     694     * Determines whether path from nodes list is oriented clockwise.
     695     * @see #isClockwise(Way)
     696     * @param nodes Nodes list to be checked.
     697     * @return true if and only if way is oriented clockwise.
     698     * @throws IllegalArgumentException if way is not closed (see {@link Way#isClosed}).
     699     */
     700    public static boolean isClockwise(List<Node> nodes) {
     701        double area2 = 0.;
     702        int nodesCount = nodes.size();
     703        if (nodesCount < 3 || nodes.get(0) != nodes.get(nodesCount - 1)) {
    691704            throw new IllegalArgumentException("Way must be closed to check orientation.");
    692705        }
    693706
    694         double area2 = 0.;
    695         int nodesCount = w.getNodesCount();
    696 
    697707        for (int node = 1; node <= /*sic! consider last-first as well*/ nodesCount; node++) {
    698             LatLon coorPrev = w.getNode(node - 1).getCoor();
    699             LatLon coorCurr = w.getNode(node % nodesCount).getCoor();
     708            LatLon coorPrev = nodes.get(node - 1).getCoor();
     709            LatLon coorCurr = nodes.get(node % nodesCount).getCoor();
    700710            area2 += coorPrev.lon() * coorCurr.lat();
    701711            area2 -= coorCurr.lon() * coorPrev.lat();
Note: See TracChangeset for help on using the changeset viewer.