source: josm/trunk/src/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyHelper.java@ 12630

Last change on this file since 12630 was 12630, checked in by Don-vip, 7 years ago

see #15182 - deprecate Main.map and Main.isDisplayingMapView(). Replacements: gui.MainApplication.getMap() / gui.MainApplication.isDisplayingMapView()

  • Property svn:eol-style set to native
File size: 5.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions.mapmode;
3
4import java.awt.Point;
5import java.util.Collection;
6import java.util.List;
7
8import org.openstreetmap.josm.data.coor.EastNorth;
9import org.openstreetmap.josm.data.osm.Node;
10import org.openstreetmap.josm.data.osm.OsmPrimitive;
11import org.openstreetmap.josm.data.osm.Way;
12import org.openstreetmap.josm.data.osm.WaySegment;
13import org.openstreetmap.josm.gui.MainApplication;
14import org.openstreetmap.josm.gui.MapView;
15import org.openstreetmap.josm.tools.Geometry;
16import org.openstreetmap.josm.tools.Pair;
17
18/**
19 * This static class contains functions used to find target way, node to move or
20 * segment to divide.
21 *
22 * @author Alexander Kachkaev <alexander@kachkaev.ru>, 2011
23 */
24final class ImproveWayAccuracyHelper {
25
26 private ImproveWayAccuracyHelper() {
27 // Hide default constructor for utils classes
28 }
29
30 /**
31 * Finds the way to work on. If the mouse is on the node, extracts one of
32 * the ways containing it. If the mouse is on the way, simply returns it.
33 *
34 * @param mv the current map view
35 * @param p the cursor position
36 * @return {@code Way} or {@code null} in case there is nothing under the cursor.
37 */
38 public static Way findWay(MapView mv, Point p) {
39 if (mv == null || p == null) {
40 return null;
41 }
42
43 Node node = mv.getNearestNode(p, OsmPrimitive::isSelectable);
44 Way candidate = null;
45
46 if (node != null) {
47 final Collection<OsmPrimitive> candidates = node.getReferrers();
48 for (OsmPrimitive refferer : candidates) {
49 if (refferer instanceof Way) {
50 candidate = (Way) refferer;
51 break;
52 }
53 }
54 if (candidate != null) {
55 return candidate;
56 }
57 }
58
59 return MainApplication.getMap().mapView.getNearestWay(p, OsmPrimitive::isSelectable);
60 }
61
62 /**
63 * Returns the nearest node to cursor. All nodes that are “behind” segments
64 * are neglected. This is to avoid way self-intersection after moving the
65 * candidateNode to a new place.
66 *
67 * @param mv the current map view
68 * @param w the way to check
69 * @param p the cursor position
70 * @return nearest node to cursor
71 */
72 public static Node findCandidateNode(MapView mv, Way w, Point p) {
73 if (mv == null || w == null || p == null) {
74 return null;
75 }
76
77 EastNorth pEN = mv.getEastNorth(p.x, p.y);
78
79 Double bestDistance = Double.MAX_VALUE;
80 Double currentDistance;
81 List<Pair<Node, Node>> wpps = w.getNodePairs(false);
82
83 Node result = null;
84
85 mainLoop:
86 for (Node n : w.getNodes()) {
87 EastNorth nEN = n.getEastNorth();
88
89 if (nEN == null) {
90 // Might happen if lat/lon for that point are not known.
91 continue;
92 }
93
94 currentDistance = pEN.distance(nEN);
95
96 if (currentDistance < bestDistance) {
97 // Making sure this candidate is not behind any segment.
98 for (Pair<Node, Node> wpp : wpps) {
99 if (!wpp.a.equals(n)
100 && !wpp.b.equals(n)
101 && Geometry.getSegmentSegmentIntersection(
102 wpp.a.getEastNorth(), wpp.b.getEastNorth(),
103 pEN, nEN) != null) {
104 continue mainLoop;
105 }
106 }
107 result = n;
108 bestDistance = currentDistance;
109 }
110 }
111
112 return result;
113 }
114
115 /**
116 * Returns the nearest way segment to cursor. The distance to segment ab is
117 * the length of altitude from p to ab (say, c) or the minimum distance from
118 * p to a or b if c is out of ab.
119 *
120 * The priority is given to segments where c is in ab. Otherwise, a segment
121 * with the largest angle apb is chosen.
122 *
123 * @param mv the current map view
124 * @param w the way to check
125 * @param p the cursor position
126 * @return nearest way segment to cursor
127 */
128 public static WaySegment findCandidateSegment(MapView mv, Way w, Point p) {
129 if (mv == null || w == null || p == null) {
130 return null;
131 }
132
133 EastNorth pEN = mv.getEastNorth(p.x, p.y);
134
135 Double currentDistance;
136 Double currentAngle;
137 Double bestDistance = Double.MAX_VALUE;
138 Double bestAngle = 0.0;
139
140 int candidate = -1;
141
142 List<Pair<Node, Node>> wpps = w.getNodePairs(true);
143
144 int i = -1;
145 for (Pair<Node, Node> wpp : wpps) {
146 ++i;
147
148 EastNorth a = wpp.a.getEastNorth();
149 EastNorth b = wpp.b.getEastNorth();
150
151 // Finding intersection of the segment with its altitude from p
152 EastNorth altitudeIntersection = Geometry.closestPointToSegment(a, b, pEN);
153 currentDistance = pEN.distance(altitudeIntersection);
154
155 if (!altitudeIntersection.equals(a) && !altitudeIntersection.equals(b)) {
156 // If the segment intersects with the altitude from p,
157 // make an angle too big to let this candidate win any others
158 // having the same distance.
159 currentAngle = Double.MAX_VALUE;
160 } else {
161 // Otherwise measure the angle
162 currentAngle = Math.abs(Geometry.getCornerAngle(a, pEN, b));
163 }
164
165 if (currentDistance < bestDistance
166 || (currentAngle > bestAngle && currentDistance < bestDistance * 1.0001 /*
167 * equality
168 */)) {
169 candidate = i;
170 bestAngle = currentAngle;
171 bestDistance = currentDistance;
172 }
173
174 }
175 return candidate != -1 ? new WaySegment(w, candidate) : null;
176 }
177}
Note: See TracBrowser for help on using the repository browser.