Changeset 34724 in osm for applications


Ignore:
Timestamp:
2018-11-18T07:26:59+01:00 (6 years ago)
Author:
gerdp
Message:

see #16948josm comment 15 and following

  • show different cursor when snapping to a line instead of a node
  • snap before mouse click, don't snap to nodes or lines which are not near to the cursor
  • prevent hang when drawing a very small rectangle
  • snap also circular buildings
Location:
applications/editors/josm/plugins/buildings_tools/src/org/openstreetmap/josm/plugins/buildings_tools
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/buildings_tools/src/org/openstreetmap/josm/plugins/buildings_tools/Building.java

    r34721 r34724  
    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;
     
    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;
     
    5051    private AngleSnap angleSnap = new AngleSnap();
    5152    private Double drawingAngle;
     53    private final static double EQUAL_NODE_DIST_TOLERANCE = 1e-6;
    5254
    5355    public void clearAngleSnap() {
     
    103105    public void setBase(EastNorth base) {
    104106        en[0] = base;
    105         updMetrics();
    106     }
    107 
    108     public void setBase(Node base) {
    109         en[0] = latlon2eastNorth(base.getCoor());
    110107        updMetrics();
    111108    }
     
    145142    }
    146143
    147     public void setLengthWidth(double length, double width) {
     144    private void setLengthWidth(double length, double width) {
    148145        this.len = length;
    149146        this.width = width;
     
    231228
    232229    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;
     230        MapView mv = MainApplication.getMap().mapView;
     231        Node n = mv.getNearestNode(mv.getPoint(eastNorth2latlon(pos)), OsmPrimitive::isSelectable);
     232        if (n == null)
     233            return null;
     234        return n.getEastNorth().distance(pos) <= EQUAL_NODE_DIST_TOLERANCE ? n : null;
    247235    }
    248236
     
    326314        }
    327315
     316        snapBuildings(w, nodes, addNodesCmd);
    328317        if (addNodesCmd.size() > 0) {
    329318            Command addNodes = new SequenceCommand(tr("Add nodes for building"), addNodesCmd);
     
    332321
    333322        // Nodes must be selected for create circle action
    334         for (int i = 0; i < 2; i++) {
    335             if (created[i]) {
    336                 ds.addSelected(nodes[i]);
    337             }
    338         }
     323        ds.addSelected(w.getNodes());
    339324
    340325        CreateCircleAction action = new CreateCircleAction();
     
    342327        action.actionPerformed(null);
    343328
     329        // restore selection
    344330        ds.clearSelection();
    345331        ds.addSelected(selectedPrimitives);
     
    403389
    404390        if (snap) {
    405             // calculate BBox which is slightly larger than the new building
    406             BBox searchBox = new BBox();
    407             final double maxDist = 0.001;
    408             List<Node> wayNodes = w.getNodes();
    409             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));
    413             }
    414             // find the ways which might be snapped to the new building
    415             List<Way> others = ds.searchWays(searchBox);
    416             // add nodes of existing buildings to the new one
    417             others.removeIf(o -> o.get("building") == null || !o.isUsable());
    418             for (Way other : others) {
    419                 snapToWay(wayNodes, other.getNodes(), maxDist);
    420                 w.setNodes(wayNodes);
    421             }
    422             // add new nodes to existing buildings
    423             for (Way other : others) {
    424                 List<Node> otherNodes = other.getNodes();
    425                 snapToWay(otherNodes, Arrays.asList(nodes), maxDist);
    426                 if (otherNodes.size() != other.getNodesCount()) {
    427                     Way newWay = new Way(other);
    428                     newWay.setNodes(otherNodes);
    429                     cmds.add(new ChangeCommand(other, newWay));
    430                 }
    431             }
     391            snapBuildings(w, nodes, cmds);
    432392        }
    433393        Command c = new SequenceCommand(tr("Create building"), cmds);
     
    436396    }
    437397
     398    private void snapBuildings(Way w, Node[] nodes, Collection<Command> cmds) {
     399        // calculate BBox which is slightly larger than the new building
     400        List<Node> wayNodes = w.getNodes();
     401        // find the ways which might be snapped to the new building
     402        Set<Way> others = new LinkedHashSet<>();
     403        MapView mv = MainApplication.getMap().mapView;
     404        for (Node n : nodes) {
     405            Way w2 = mv.getNearestWay(mv.getPoint(n), OsmPrimitive::isSelectable);
     406            if (w2 != null && w2.get("building") != null)
     407                others.add(w2);
     408        }
     409        // add nodes of existing buildings to the new one
     410        for (Way other : others) {
     411            snapToWay(wayNodes, other.getNodes());
     412            w.setNodes(wayNodes);
     413        }
     414        // add new nodes to existing buildings
     415        for (Way other : others) {
     416            List<Node> otherNodes = other.getNodes();
     417            snapToWay(otherNodes, Arrays.asList(nodes));
     418            if (otherNodes.size() != other.getNodesCount()) {
     419                Way newWay = new Way(other);
     420                newWay.setNodes(otherNodes);
     421                cmds.add(new ChangeCommand(other, newWay));
     422            }
     423        }
     424
     425    }
     426
    438427    /**
    439      * Add all nodes in otherNodes to wayNodes that are within maxDist to the
    440      * segments described by wayNodes.
     428     * Add all nodes in otherNodes to wayNodes that are within snap distance to
     429     * the segments described by wayNodes.
    441430     *
    442431     * @param wayNodes
     
    444433     * @param otherNodes
    445434     *            other nodes
    446      * @param maxDist
    447      *            maximum distance as square of the euclidean distance between
    448      *            way segment and node
    449435     */
    450     private static void snapToWay(List<Node> wayNodes, Collection<Node> otherNodes, double maxDist) {
     436    private static void snapToWay(List<Node> wayNodes, Collection<Node> otherNodes) {
    451437        for (int i = 0; i < wayNodes.size(); i++) {
    452438            Node n0 = wayNodes.get(i);
     
    455441                if (n2 == n0 || n2 == n1)
    456442                    continue;
    457                 EastNorth x = Geometry.closestPointToSegment(n0.getEastNorth(), n1.getEastNorth(),
    458                         n2.getEastNorth());
    459                 if (x.distanceSq(n2.getEastNorth()) < maxDist) {
     443                EastNorth x = Geometry.closestPointToSegment(n0.getEastNorth(), n1.getEastNorth(), n2.getEastNorth());
     444                if (x.distance(n2.getEastNorth()) <= EQUAL_NODE_DIST_TOLERANCE && !wayNodes.contains(n2)) {
    460445                    wayNodes.add(i + 1, n2);
    461                     i--; // we may add multiple nodes to one segment, so repeat
    462                          // it
     446                    // we may add multiple nodes to one segment, so repeat it
     447                    i--;
    463448                    break;
    464449                }
  • applications/editors/josm/plugins/buildings_tools/src/org/openstreetmap/josm/plugins/buildings_tools/DrawBuildingAction.java

    r34721 r34724  
    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;
     
    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;
     
    5153    private final Cursor cursorCrosshair;
    5254    private final Cursor cursorJoinNode;
     55    private final Cursor cursorJoinWay;
    5356    private Cursor currCursor;
    5457    private Cursor customCursor;
     
    7275        cursorCrosshair = getCursor();
    7376        cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode");
     77        cursorJoinWay = ImageProvider.getCursor("crosshair", "joinway");
    7478        currCursor = cursorCrosshair;
    7579    }
     
    201205
    202206    private EastNorth getEastNorth() {
    203         Node n;
    204         if (ctrl) {
    205             n = null;
    206         } else {
    207             n = MainApplication.getMap().mapView.getNearestNode(mousePos, OsmPrimitive::isUsable);
    208         }
    209         if (n == null) {
    210             return latlon2eastNorth(MainApplication.getMap().mapView.getLatLon(mousePos.x, mousePos.y));
    211         } else {
    212             return latlon2eastNorth(n.getCoor());
    213         }
     207        if (!ctrl) {
     208            Node n = MainApplication.getMap().mapView.getNearestNode(mousePos, OsmPrimitive::isUsable);
     209            if (n != null)
     210                return latlon2eastNorth(n.getCoor());
     211            WaySegment ws = MainApplication.getMap().mapView.getNearestWaySegment(mousePos,
     212                    OsmPrimitive::isSelectable);
     213            if (ws != null && ws.way.get("building") != null) {
     214                EastNorth p1 = ws.getFirstNode().getEastNorth();
     215                EastNorth p2 = ws.getSecondNode().getEastNorth();
     216                EastNorth enX = Geometry.closestPointToSegment(p1, p2,
     217                        MainApplication.getMap().mapView.getEastNorth(mousePos.x, mousePos.y));
     218                if (enX != null) {
     219                    return enX;
     220                }
     221            }
     222        }
     223        return latlon2eastNorth(MainApplication.getMap().mapView.getLatLon(mousePos.x, mousePos.y));
    214224    }
    215225
     
    222232        EastNorth p = getEastNorth();
    223233        if (isRectDrawing()) {
    224                 building.setPlaceRect(p);
    225                 return shift ? Mode.DrawingAngFix : Mode.None;
     234            building.setPlaceRect(p);
     235            return shift ? Mode.DrawingAngFix : Mode.None;
    226236        } else if (ToolSettings.Shape.CIRCLE.equals(ToolSettings.getShape())) {
    227237            if (ToolSettings.getWidth() != 0) {
     
    291301        mousePos = e.getPoint();
    292302        drawStartPos = mousePos;
    293         if (ToolSettings.Shape.CIRCLE.equals(ToolSettings.getShape())) {
    294             building.setBase(latlon2eastNorth(MainApplication.getMap().mapView.getLatLon(mousePos.x, mousePos.y)));
    295         } else {
    296             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)));
    299             } else {
    300                 building.setBase(n);
    301             }
    302         }
     303        EastNorth en = getEastNorth();
     304        building.setBase(en);
    303305        mode = Mode.Drawing;
    304306        updateStatusLine();
     
    385387            return;
    386388        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());
    396         }
     389        if (!ctrl) {
     390            n = MainApplication.getMap().mapView.getNearestNode(mousePos, OsmPrimitive::isSelectable);
     391            if (n != null) {
     392                setCursor(cursorJoinNode);
     393                return;
     394            } else {
     395                Way w = MainApplication.getMap().mapView.getNearestWay(mousePos, OsmPrimitive::isSelectable);
     396                if (w != null && w.get("building") != null) {
     397                    setCursor(cursorJoinWay);
     398                    return;
     399                }
     400            }
     401        }
     402        if (customCursor != null && (!ctrl || isRectDrawing()))
     403            setCursor(customCursor);
     404        else
     405            setCursor(getCursor());
    397406
    398407    }
Note: See TracChangeset for help on using the changeset viewer.