Ticket #16948: improve_snap.patch

File improve_snap.patch, 9.6 KB (added by GerdP, 7 years ago)
  • src/org/openstreetmap/josm/plugins/buildings_tools/Building.java

     
    1212import java.util.Arrays;
    1313import java.util.Collection;
    1414import java.util.Collections;
     15import java.util.LinkedHashSet;
    1516import java.util.LinkedList;
    1617import java.util.List;
    1718import java.util.Map.Entry;
     19import java.util.Set;
    1820
    1921import javax.swing.JOptionPane;
    2022
     
    2628import org.openstreetmap.josm.command.SequenceCommand;
    2729import org.openstreetmap.josm.data.UndoRedoHandler;
    2830import org.openstreetmap.josm.data.coor.EastNorth;
    29 import org.openstreetmap.josm.data.coor.LatLon;
    3031import org.openstreetmap.josm.data.osm.BBox;
    3132import org.openstreetmap.josm.data.osm.DataSet;
    3233import org.openstreetmap.josm.data.osm.Node;
     
    230231    }
    231232
    232233    private Node findNode(EastNorth pos) {
    233         DataSet ds = MainApplication.getLayerManager().getEditDataSet();
    234         LatLon l = eastNorth2latlon(pos);
    235         List<Node> nodes = ds.searchNodes(new BBox(l.lon() - 0.0000001, l.lat() - 0.0000001,
    236                 l.lon() + 0.0000001, l.lat() + 0.0000001));
    237         Node bestnode = null;
    238         double mindist = 0.0003;
    239         for (Node n : nodes) {
    240             double dist = n.getCoor().distanceSq(l);
    241             if (dist < mindist && n.isUsable()) {
    242                 bestnode = n;
    243                 mindist = dist;
    244             }
    245         }
    246         return bestnode;
     234        MapView mv = MainApplication.getMap().mapView;
     235        return mv.getNearestNode(mv.getPoint(pos), OsmPrimitive::isSelectable);
    247236    }
    248237
    249238    /**
     
    403392
    404393        if (snap) {
    405394            // calculate BBox which is slightly larger than the new building
    406             BBox searchBox = new BBox();
    407             final double maxDist = 0.001;
    408395            List<Node> wayNodes = w.getNodes();
     396            // find the ways which might be snapped to the new building
     397            Set<Way> others = new LinkedHashSet<>();
     398            MapView mv = MainApplication.getMap().mapView;
    409399            for (Node n : nodes) {
    410                 LatLon l = eastNorth2latlon(n.getEastNorth());
    411                 searchBox.add(new BBox(l.lon() - 0.0000001, l.lat() - 0.0000001,
    412                         l.lon() + 0.0000001, l.lat() + 0.0000001));
     400                Way w2 = mv.getNearestWay(mv.getPoint(n), OsmPrimitive::isSelectable);
     401                if (w2 != null && w2.get("building") != null)
     402                    others.add(w2);
    413403            }
    414             // find the ways which might be snapped to the new building
    415             List<Way> others = ds.searchWays(searchBox);
    416404            // add nodes of existing buildings to the new one
    417             others.removeIf(o -> o.get("building") == null || !o.isUsable());
    418405            for (Way other : others) {
    419                 snapToWay(wayNodes, other.getNodes(), maxDist);
     406                snapToWay(wayNodes, other.getNodes());
    420407                w.setNodes(wayNodes);
    421408            }
    422409            // add new nodes to existing buildings
    423410            for (Way other : others) {
    424411                List<Node> otherNodes = other.getNodes();
    425                 snapToWay(otherNodes, Arrays.asList(nodes), maxDist);
     412                snapToWay(otherNodes, Arrays.asList(nodes));
    426413                if (otherNodes.size() != other.getNodesCount()) {
    427414                    Way newWay = new Way(other);
    428415                    newWay.setNodes(otherNodes);
     
    436423    }
    437424
    438425    /**
    439      * Add all nodes in otherNodes to wayNodes that are within maxDist to the
    440      * segments described by wayNodes.
     426     * Add all nodes in otherNodes to wayNodes that are within snap distance to
     427     * the segments described by wayNodes.
    441428     *
    442429     * @param wayNodes
    443430     *            List of nodes that might be changed
    444431     * @param otherNodes
    445432     *            other nodes
    446      * @param maxDist
    447      *            maximum distance as square of the euclidean distance between
    448      *            way segment and node
    449433     */
    450     private static void snapToWay(List<Node> wayNodes, Collection<Node> otherNodes, double maxDist) {
     434    private static void snapToWay(List<Node> wayNodes, Collection<Node> otherNodes) {
     435        final double tolerance = MainApplication.getMap().mapView.getDist100Pixel() * 0.01
     436                * MapView.PROP_SNAP_DISTANCE.get();
     437
    451438        for (int i = 0; i < wayNodes.size(); i++) {
    452439            Node n0 = wayNodes.get(i);
    453440            Node n1 = wayNodes.get(i + 1 == wayNodes.size() ? 0 : i + 1);
     
    454441            for (Node n2 : otherNodes) {
    455442                if (n2 == n0 || n2 == n1)
    456443                    continue;
    457                 EastNorth x = Geometry.closestPointToSegment(n0.getEastNorth(), n1.getEastNorth(),
    458                         n2.getEastNorth());
    459                 if (x.distanceSq(n2.getEastNorth()) < maxDist) {
     444                EastNorth x = Geometry.closestPointToSegment(n0.getEastNorth(), n1.getEastNorth(), n2.getEastNorth());
     445                if (x.distance(n2.getEastNorth()) < tolerance && !wayNodes.contains(n2)) {
    460446                    wayNodes.add(i + 1, n2);
    461                     i--; // we may add multiple nodes to one segment, so repeat
    462                          // it
     447                    // we may add multiple nodes to one segment, so repeat it
     448                    i--;
    463449                    break;
    464450                }
    465451            }
  • src/org/openstreetmap/josm/plugins/buildings_tools/DrawBuildingAction.java

     
    2828import org.openstreetmap.josm.data.osm.Node;
    2929import org.openstreetmap.josm.data.osm.OsmPrimitive;
    3030import org.openstreetmap.josm.data.osm.Way;
     31import org.openstreetmap.josm.data.osm.WaySegment;
    3132import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
    3233import org.openstreetmap.josm.data.preferences.NamedColorProperty;
    3334import org.openstreetmap.josm.gui.MainApplication;
     
    3839import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    3940import org.openstreetmap.josm.gui.util.KeyPressReleaseListener;
    4041import org.openstreetmap.josm.gui.util.ModifierExListener;
     42import org.openstreetmap.josm.tools.Geometry;
    4143import org.openstreetmap.josm.tools.ImageProvider;
    4244import org.openstreetmap.josm.tools.Logging;
    4345import org.openstreetmap.josm.tools.Shortcut;
     
    5052
    5153    private final Cursor cursorCrosshair;
    5254    private final Cursor cursorJoinNode;
     55    private final Cursor cursorJoinWay;
    5356    private Cursor currCursor;
    5457    private Cursor customCursor;
    5558
     
    7174
    7275        cursorCrosshair = getCursor();
    7376        cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode");
     77        cursorJoinWay = ImageProvider.getCursor("crosshair", "joinway");
    7478        currCursor = cursorCrosshair;
    7579    }
    7680
     
    294298            building.setBase(latlon2eastNorth(MainApplication.getMap().mapView.getLatLon(mousePos.x, mousePos.y)));
    295299        } else {
    296300            Node n = MainApplication.getMap().mapView.getNearestNode(mousePos, OsmPrimitive::isUsable);
    297             if (n == null) {
    298                 building.setBase(latlon2eastNorth(MainApplication.getMap().mapView.getLatLon(mousePos.x, mousePos.y)));
     301            if (n != null) {
     302                building.setBase(n);
    299303            } else {
    300                 building.setBase(n);
     304                WaySegment ws = MainApplication.getMap().mapView.getNearestWaySegment(mousePos,
     305                        OsmPrimitive::isSelectable);
     306                if (ws != null && ws.way.get("building") != null) {
     307                    EastNorth p1 = ws.getFirstNode().getEastNorth();
     308                    EastNorth p2 = ws.getSecondNode().getEastNorth();
     309                    EastNorth enX = Geometry.closestPointToSegment(p1, p2,
     310                            MainApplication.getMap().mapView.getEastNorth(mousePos.x, mousePos.y));
     311                    if (enX != null) {
     312                        building.setBase(enX);
     313                    }
     314                } else {
     315                    building.setBase(
     316                            latlon2eastNorth(MainApplication.getMap().mapView.getLatLon(mousePos.x, mousePos.y)));
     317                }
    301318            }
    302319        }
    303320        mode = Mode.Drawing;
     
    384401        if (!MainApplication.isDisplayingMapView())
    385402            return;
    386403        Node n = null;
    387         if (!ctrl)
    388             n = MainApplication.getMap().mapView.getNearestNode(mousePos, OsmPrimitive::isUsable);
    389         if (n != null) {
    390             setCursor(cursorJoinNode);
    391         } else {
    392             if (customCursor != null && (!ctrl || isRectDrawing()))
    393                 setCursor(customCursor);
    394             else
    395                 setCursor(getCursor());
     404        if (!ctrl) {
     405            n = MainApplication.getMap().mapView.getNearestNode(mousePos, OsmPrimitive::isSelectable);
     406            if (n != null) {
     407                setCursor(cursorJoinNode);
     408                return;
     409            } else {
     410                Way w = MainApplication.getMap().mapView.getNearestWay(mousePos, OsmPrimitive::isSelectable);
     411                if (w != null && w.get("building") != null) {
     412                    setCursor(cursorJoinWay);
     413                    return;
     414                }
     415            }
    396416        }
     417        if (customCursor != null && (!ctrl || isRectDrawing()))
     418            setCursor(customCursor);
     419        else
     420            setCursor(getCursor());
    397421
    398422    }
    399423