Ticket #4190: follow-way.diff

File follow-way.diff, 9.2 KB (added by Pekka Lampila <pekka.lampila@…>, 3 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        /*