Ticket #4190: follow-way.diff

File follow-way.diff, 9.2 KB (added by Pekka Lampila <pekka.lampila@…>, 16 years ago)

The patch

  • src/org/openstreetmap/josm/actions/mapmode/DrawAction.java

    diff --git a/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java b/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
    index f09724b..cf84939 100644
    a b public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh  
    8787    private Color selectedColor;
    8888
    8989    private Node currentBaseNode;
     90    private Node currentMouseNode;
    9091    private EastNorth currentMouseEastNorth;
    9192
    9293    public DrawAction(MapFrame mapFrame) {
    public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh  
    331332        ArrayList<Way> reuseWays = new ArrayList<Way>(),
    332333        replacedWays = new ArrayList<Way>();
    333334        boolean newNode = false;
     335        int numNodes = 0; // only for shift click on a node
    334336        Node n = null;
    335337
    336338        if (!ctrl) {
    public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh  
    432434        boolean wayIsFinishedTemp = wayIsFinished;
    433435        wayIsFinished = false;
    434436
    435         // don't draw lines if shift is held
    436         if (selection.size() > 0 && !shift) {
     437        // don't draw lines if shift is held, except when a node was clicked
     438        if (selection.size() > 0 && (!shift || !newNode)) {
    437439            Node selectedNode = null;
    438440            Way selectedWay = null;
    439441
    public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh  
    515517                }
    516518
    517519                // Add new node to way
    518                 if (way.getNode(way.getNodesCount() - 1) == n0) {
    519                     way.addNode(n);
     520                if (shift) {
     521                    boolean end = (way.getNode(way.getNodesCount() - 1) == n0);
     522                    for (Node node : getFollowWayNodes(n0, n)) {
     523                        if (end) {
     524                            way.addNode(node);
     525                        } else {
     526                            way.addNode(0, node);
     527                        }
     528                        numNodes++;
     529                    }
    520530                } else {
    521                     way.addNode(0, n);
     531                    if (way.getNode(way.getNodesCount() - 1) == n0) {
     532                        way.addNode(n);
     533                    } else {
     534                        way.addNode(0, n);
     535                    }
    522536                }
    523537
    524538                extendedWay = true;
    public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh  
    542556            newSelection.clear();
    543557            newSelection.add(n);
    544558        } else if (!newNode) {
    545             title = tr("Connect existing way to node");
     559            if (numNodes <= 1) {
     560                title = tr("Connect existing way to node");
     561            } else {
     562                title = tr("Connect existing way to {0} nodes", numNodes);
     563            }
    546564        } else if (reuseWays.isEmpty()) {
    547565            title = tr("Add a new node to an existing way");
    548566        } else {
    public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh  
    671689
    672690        Node selectedNode = null;
    673691        Way selectedWay = null;
    674         Node currentMouseNode = null;
    675692        mouseOnExistingNode = null;
    676693        mouseOnExistingWays = new HashSet<Way>();
    677694
    public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh  
    681698
    682699        if (!ctrl && mousePos != null) {
    683700            currentMouseNode = mv.getNearestNode(mousePos);
     701        } else {
     702            currentMouseNode = null;
    684703        }
    685704
    686705        // We need this for highlighting and we'll only do so if we actually want to re-use
    public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh  
    786805        return way;
    787806    }
    788807
     808    private List<Node> getFollowWayNodes(Node startNode, Node endNode) {
     809        // get list of ways that have both the start node and the end node
     810        Collection<Way> allWays = getCurrentDataSet().getWays();
     811        Collection<Way> sourceWays = new LinkedList<Way>();
     812        for (Way way : allWays) {
     813                Collection<Node> wayNodes = way.getNodes();
     814                if(wayNodes.contains(startNode) && wayNodes.contains(endNode))
     815                        sourceWays.add(way);
     816        }
     817
     818        // if no ways are found, we'll just link directly to the end node
     819        if (sourceWays.size() == 0) {
     820            List<Node> nodes = new LinkedList<Node>();
     821            nodes.add(endNode);
     822            return nodes;
     823        }
     824
     825        // create a list of possible routes between the nodes
     826        Collection<List<Node>> routes = new LinkedList<List<Node>>();
     827
     828        for (Way way : sourceWays) {
     829            // find the node indexes in the way
     830            List<Node> wayNodes = way.getNodes();
     831            int startIndex = wayNodes.indexOf(startNode);
     832            int endIndex = wayNodes.indexOf(endNode);
     833
     834            if (startIndex > endIndex) {
     835                int tmp = startIndex;
     836                startIndex = endIndex;
     837                endIndex = tmp;
     838            }
     839
     840            routes.add(wayNodes.subList(startIndex, endIndex + 1));
     841
     842            if (way.isClosed()) {
     843                List<Node> route = new LinkedList<Node>();
     844                route.addAll(wayNodes.subList(endIndex, wayNodes.size()));
     845                route.addAll(wayNodes.subList(1, startIndex + 1));
     846                routes.add(route);
     847            }
     848        }
     849
     850        // find the shortest route
     851        List<Node> bestRoute = null;
     852        double shortestDistance = -1;
     853
     854        for (List<Node> route : routes) {
     855                double distance = 0;
     856                Node previous = route.get(0);
     857                for (Node node : route) {
     858                        distance += previous.getEastNorth().distance(node.getEastNorth());
     859                        previous = node;
     860                }
     861                if (bestRoute == null || distance < shortestDistance) {
     862                        bestRoute = route;
     863                        shortestDistance = distance;
     864                }
     865        }
     866
     867        if (bestRoute.get(0) != startNode)
     868            Collections.reverse(bestRoute);
     869
     870        return bestRoute.subList(1, bestRoute.size());
     871    }
     872
    789873    private static void pruneSuccsAndReverse(List<Integer> is) {
    790874        //if (is.size() < 2) return;
    791875
    public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh  
    877961        return a * d - b * c;
    878962    }
    879963
    880     public void paint(Graphics2D g, MapView mv, Bounds box) {
    881         if (!drawHelperLine || wayIsFinished || shift) return;
    882 
    883         // sanity checks
    884         if (Main.map.mapView == null) return;
    885         if (mousePos == null) return;
    886 
    887         // don't draw line if we don't know where from or where to
    888         if (currentBaseNode == null || currentMouseEastNorth == null) return;
    889 
    890         // don't draw line if mouse is outside window
    891         if (!Main.map.mapView.getBounds().contains(mousePos)) return;
    892 
     964    private void drawHelperLine(Graphics2D g, MapView mv, Point p1, Point p2, boolean startline) {
    893965        Graphics2D g2 = g;
    894966        g2.setColor(selectedColor);
    895967        g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
    896968        GeneralPath b = new GeneralPath();
    897         Point p1=mv.getPoint(currentBaseNode);
    898         Point p2=mv.getPoint(currentMouseEastNorth);
    899969
    900970        double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
    901971
    902972        b.moveTo(p1.x,p1.y); b.lineTo(p2.x, p2.y);
    903973
    904974        // if alt key is held ("start new way"), draw a little perpendicular line
    905         if (alt) {
     975        if (startline) {
    906976            b.moveTo((int)(p1.x + 8*Math.cos(t+PHI)), (int)(p1.y + 8*Math.sin(t+PHI)));
    907977            b.lineTo((int)(p1.x + 8*Math.cos(t-PHI)), (int)(p1.y + 8*Math.sin(t-PHI)));
    908978        }
    public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh  
    911981        g2.setStroke(new BasicStroke(1));
    912982    }
    913983
     984    public void paint(Graphics2D g, MapView mv, Bounds box) {
     985        if (!drawHelperLine || wayIsFinished || (shift && (ctrl || Main.map.mapView.getNearestNode(mousePos) == null))) return;
     986
     987        // sanity checks
     988        if (Main.map.mapView == null) return;
     989        if (mousePos == null) return;
     990
     991        // don't draw line if we don't know where from or where to
     992        if (currentBaseNode == null || currentMouseEastNorth == null) return;
     993
     994        // don't draw line if mouse is outside window
     995        if (!Main.map.mapView.getBounds().contains(mousePos)) return;
     996
     997        if (shift && currentBaseNode != currentMouseNode) {
     998            List<Node> nodes = getFollowWayNodes(currentBaseNode, currentMouseNode);
     999            drawHelperLine(g, mv, mv.getPoint(currentBaseNode), mv.getPoint(nodes.get(0)), alt);
     1000
     1001            Node previousNode = null;
     1002            for (Node node : nodes) {
     1003                if (previousNode != null)
     1004                    drawHelperLine(g, mv, mv.getPoint(previousNode), mv.getPoint(node), false);
     1005                previousNode = node;
     1006            }
     1007        } else {
     1008            drawHelperLine(g, mv, mv.getPoint(currentBaseNode), mv.getPoint(currentMouseEastNorth), alt);
     1009        }
     1010    }
     1011
    9141012    @Override public String getModeHelpText() {
    9151013        String rv = "";
    9161014        /*