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

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

Checkstyle:

  • private constructors for util classes
  • final classes
  • missing "else" statements
  • import cleanup
File size: 6.0 KB
Line 
1// License: GPL. See LICENSE file for details.
2package org.openstreetmap.josm.actions.mapmode;
3
4import java.awt.Point;
5import java.util.Collection;
6import java.util.List;
7
8import org.openstreetmap.josm.Main;
9import org.openstreetmap.josm.data.coor.EastNorth;
10import org.openstreetmap.josm.data.osm.Node;
11import org.openstreetmap.josm.data.osm.OsmPrimitive;
12import org.openstreetmap.josm.data.osm.Way;
13import org.openstreetmap.josm.data.osm.WaySegment;
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.isSelectablePredicate);
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 candidate = Main.map.mapView.getNearestWay(p,
60 OsmPrimitive.isSelectablePredicate);
61
62 return candidate;
63 }
64
65 /**
66 * Returns the nearest node to cursor. All nodes that are “behind” segments
67 * are neglected. This is to avoid way self-intersection after moving the
68 * candidateNode to a new place.
69 *
70 * @param mv the current map view
71 * @param w the way to check
72 * @param p the cursor position
73 * @return nearest node to cursor
74 */
75 public static Node findCandidateNode(MapView mv, Way w, Point p) {
76 if (mv == null || w == null || p == null) {
77 return null;
78 }
79
80 EastNorth pEN = mv.getEastNorth(p.x, p.y);
81
82 Double bestDistance = Double.MAX_VALUE;
83 Double currentDistance;
84 List<Pair<Node, Node>> wpps = w.getNodePairs(false);
85
86 Node result = null;
87
88 mainLoop:
89 for (Node n : w.getNodes()) {
90 EastNorth nEN = n.getEastNorth();
91 currentDistance = pEN.distance(nEN);
92
93 if (currentDistance < bestDistance) {
94 // Making sure this candidate is not behind any segment.
95 for (Pair<Node, Node> wpp : wpps) {
96 if (!wpp.a.equals(n)
97 && !wpp.b.equals(n)
98 && Geometry.getSegmentSegmentIntersection(
99 wpp.a.getEastNorth(), wpp.b.getEastNorth(),
100 pEN, nEN) != null) {
101 continue mainLoop;
102 }
103 }
104 result = n;
105 bestDistance = currentDistance;
106 }
107 }
108
109 return result;
110 }
111
112 /**
113 * Returns the nearest way segment to cursor. The distance to segment ab is
114 * the length of altitude from p to ab (say, c) or the minimum distance from
115 * p to a or b if c is out of ab.
116 *
117 * The priority is given to segments where c is in ab. Otherwise, a segment
118 * with the largest angle apb is chosen.
119 *
120 * @param mv the current map view
121 * @param w the way to check
122 * @param p the cursor position
123 * @return nearest way segment to cursor
124 */
125 public static WaySegment findCandidateSegment(MapView mv, Way w, Point p) {
126 if (mv == null || w == null || p == null) {
127 return null;
128 }
129
130 EastNorth pEN = mv.getEastNorth(p.x, p.y);
131
132 Double currentDistance;
133 Double currentAngle;
134 Double bestDistance = Double.MAX_VALUE;
135 Double bestAngle = 0.0;
136
137 int candidate = -1;
138
139 List<Pair<Node, Node>> wpps = w.getNodePairs(true);
140
141 int i = -1;
142 for (Pair<Node, Node> wpp : wpps) {
143 ++i;
144
145 // Finding intersection of the segment with its altitude from p (c)
146 EastNorth altitudeIntersection = Geometry.getSegmentAltituteIntersection(wpp.a.getEastNorth(),
147 wpp.b.getEastNorth(), pEN);
148
149 if (altitudeIntersection != null) {
150 // If the segment intersects with the altitude from p
151 currentDistance = pEN.distance(altitudeIntersection);
152
153 // Making an angle too big to let this candidate win any others
154 // having the same distance.
155 currentAngle = Double.MAX_VALUE;
156
157 } else {
158 // Otherwise: Distance is equal to the shortest distance from p
159 // to a or b
160 currentDistance = Math.min(pEN.distance(wpp.a.getEastNorth()),
161 pEN.distance(wpp.b.getEastNorth()));
162
163 // Measuring the angle
164 currentAngle = Math.abs(Geometry.getCornerAngle(
165 wpp.a.getEastNorth(), pEN, wpp.b.getEastNorth()));
166 }
167
168 if (currentDistance < bestDistance
169 || (currentAngle > bestAngle && currentDistance < bestDistance * 1.0001 /*
170 * equality
171 */)) {
172 candidate = i;
173 bestAngle = currentAngle;
174 bestDistance = currentDistance;
175 }
176
177 }
178 return candidate != -1 ? new WaySegment(w, candidate) : null;
179 }
180}
Note: See TracBrowser for help on using the repository browser.