source: josm/trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java@ 653

Last change on this file since 653 was 627, checked in by framm, 16 years ago
  • Property svn:eol-style set to native
File size: 9.7 KB
Line 
1// License: GPL. See LICENSE file for details.
2
3package org.openstreetmap.josm.gui;
4
5import java.awt.Point;
6import java.util.Collection;
7import java.util.Collections;
8import java.util.HashSet;
9import java.util.TreeMap;
10import java.util.List;
11import java.util.ArrayList;
12import java.util.LinkedList;
13
14import javax.swing.JComponent;
15
16import org.openstreetmap.josm.Main;
17import org.openstreetmap.josm.actions.HelpAction.Helpful;
18import org.openstreetmap.josm.data.coor.EastNorth;
19import org.openstreetmap.josm.data.coor.LatLon;
20import org.openstreetmap.josm.data.osm.Node;
21import org.openstreetmap.josm.data.osm.OsmPrimitive;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.data.osm.WaySegment;
24import org.openstreetmap.josm.data.projection.Projection;
25
26/**
27 * An component that can be navigated by a mapmover. Used as map view and for the
28 * zoomer in the download dialog.
29 *
30 * @author imi
31 */
32public class NavigatableComponent extends JComponent implements Helpful {
33
34
35 public static final EastNorth world = Main.proj.latlon2eastNorth(new LatLon(Projection.MAX_LAT, Projection.MAX_LON));
36
37 /**
38 * The scale factor in x or y-units per pixel. This means, if scale = 10,
39 * every physical pixel on screen are 10 x or 10 y units in the
40 * northing/easting space of the projection.
41 */
42 protected double scale;
43 /**
44 * Center n/e coordinate of the desired screen center.
45 */
46 protected EastNorth center;
47
48 public NavigatableComponent() {
49 setLayout(null);
50 }
51
52 /**
53 * Return the OSM-conform zoom factor (0 for whole world, 1 for half, 2 for quarter...)
54 */
55 public int zoom() {
56 double sizex = scale * getWidth();
57 double sizey = scale * getHeight();
58 for (int zoom = 0; zoom <= 32; zoom++, sizex *= 2, sizey *= 2)
59 if (sizex > world.east() || sizey > world.north())
60 return zoom;
61 return 32;
62 }
63
64 /**
65 * Return the current scale value.
66 * @return The scale value currently used in display
67 */
68 public double getScale() {
69 return scale;
70 }
71
72 /**
73 * @return Returns the center point. A copy is returned, so users cannot
74 * change the center by accessing the return value. Use zoomTo instead.
75 */
76 public EastNorth getCenter() {
77 return center;
78 }
79
80 /**
81 * @param x X-Pixelposition to get coordinate from
82 * @param y Y-Pixelposition to get coordinate from
83 *
84 * @return Geographic coordinates from a specific pixel coordination
85 * on the screen.
86 */
87 public EastNorth getEastNorth(int x, int y) {
88 return new EastNorth(
89 center.east() + (x - getWidth()/2.0)*scale,
90 center.north() - (y - getHeight()/2.0)*scale);
91 }
92
93 /**
94 * @param x X-Pixelposition to get coordinate from
95 * @param y Y-Pixelposition to get coordinate from
96 *
97 * @return Geographic unprojected coordinates from a specific pixel coordination
98 * on the screen.
99 */
100 public LatLon getLatLon(int x, int y) {
101
102 return getProjection().eastNorth2latlon(getEastNorth(x, y));
103 }
104
105 /**
106 * Return the point on the screen where this Coordinate would be.
107 * @param point The point, where this geopoint would be drawn.
108 * @return The point on screen where "point" would be drawn, relative
109 * to the own top/left.
110 */
111 public Point getPoint(EastNorth p) {
112 double x = (p.east()-center.east())/scale + getWidth()/2;
113 double y = (center.north()-p.north())/scale + getHeight()/2;
114 return new Point((int)x,(int)y);
115 }
116
117 /**
118 * Zoom to the given coordinate.
119 * @param centerX The center x-value (easting) to zoom to.
120 * @param centerY The center y-value (northing) to zoom to.
121 * @param scale The scale to use.
122 */
123 public void zoomTo(EastNorth newCenter, double scale) {
124 center = newCenter;
125 getProjection().eastNorth2latlon(center);
126 this.scale = scale;
127 repaint();
128 }
129
130 /**
131 * Return the nearest point to the screen point given.
132 * If a node within 10 pixel is found, the nearest node is returned.
133 */
134 public final Node getNearestNode(Point p) {
135 double minDistanceSq = Double.MAX_VALUE;
136 Node minPrimitive = null;
137 for (Node n : Main.ds.nodes) {
138 if (n.deleted || n.incomplete)
139 continue;
140 Point sp = getPoint(n.eastNorth);
141 double dist = p.distanceSq(sp);
142 if (minDistanceSq > dist && dist < 100) {
143 minDistanceSq = p.distanceSq(sp);
144 minPrimitive = n;
145 }
146 }
147 return minPrimitive;
148 }
149
150 /**
151 * @return all way segments within 10px of p, sorted by their
152 * perpendicular distance.
153 *
154 * @param p the point for which to search the nearest segment.
155 */
156 public final List<WaySegment> getNearestWaySegments(Point p) {
157 TreeMap<Double, List<WaySegment>> nearest = new TreeMap<Double, List<WaySegment>>();
158 for (Way w : Main.ds.ways) {
159 if (w.deleted || w.incomplete) continue;
160 Node lastN = null;
161 int i = -2;
162 for (Node n : w.nodes) {
163 i++;
164 if (n.deleted || n.incomplete) continue;
165 if (lastN == null) {
166 lastN = n;
167 continue;
168 }
169
170 Point A = getPoint(lastN.eastNorth);
171 Point B = getPoint(n.eastNorth);
172 double c = A.distanceSq(B);
173 double a = p.distanceSq(B);
174 double b = p.distanceSq(A);
175 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
176 if (perDist < 100 && a < c+100 && b < c+100) {
177 List<WaySegment> l;
178 if (nearest.containsKey(perDist)) {
179 l = nearest.get(perDist);
180 } else {
181 l = new LinkedList<WaySegment>();
182 nearest.put(perDist, l);
183 }
184 l.add(new WaySegment(w, i));
185 }
186
187 lastN = n;
188 }
189 }
190 ArrayList<WaySegment> nearestList = new ArrayList<WaySegment>();
191 for (List<WaySegment> wss : nearest.values()) {
192 nearestList.addAll(wss);
193 }
194 return nearestList;
195 }
196
197 /**
198 * @return the nearest way segment to the screen point given that is not
199 * in ignore.
200 *
201 * @param p the point for which to search the nearest segment.
202 * @param ignore a collection of segments which are not to be returned.
203 * May be null.
204 */
205 public final WaySegment getNearestWaySegment(Point p, Collection<WaySegment> ignore) {
206 List<WaySegment> nearest = getNearestWaySegments(p);
207 if (ignore != null) nearest.removeAll(ignore);
208 return nearest.isEmpty() ? null : nearest.get(0);
209 }
210
211 /**
212 * @return the nearest way segment to the screen point given.
213 */
214 public final WaySegment getNearestWaySegment(Point p) {
215 return getNearestWaySegment(p, null);
216 }
217
218 /**
219 * @return the nearest way to the screen point given.
220 */
221 public final Way getNearestWay(Point p) {
222 WaySegment nearestWaySeg = getNearestWaySegment(p);
223 return nearestWaySeg == null ? null : nearestWaySeg.way;
224 }
225
226 /**
227 * Return the object, that is nearest to the given screen point.
228 *
229 * First, a node will be searched. If a node within 10 pixel is found, the
230 * nearest node is returned.
231 *
232 * If no node is found, search for near ways.
233 *
234 * If nothing is found, return <code>null</code>.
235 *
236 * @param p The point on screen.
237 * @return The primitive, that is nearest to the point p.
238 */
239 public OsmPrimitive getNearest(Point p) {
240 OsmPrimitive osm = getNearestNode(p);
241 if (osm == null)
242 osm = getNearestWay(p);
243 return osm;
244 }
245
246 /**
247 * Returns a singleton of the nearest object, or else an empty collection.
248 */
249 public Collection<OsmPrimitive> getNearestCollection(Point p) {
250 OsmPrimitive osm = getNearest(p);
251 if (osm == null)
252 return Collections.emptySet();
253 return Collections.singleton(osm);
254 }
255
256 @Deprecated
257 public OsmPrimitive getNearest(Point p, boolean segmentInsteadWay) {
258 return getNearest(p);
259 }
260
261 /**
262 * @return A list of all objects that are nearest to
263 * the mouse. Does a simple sequential scan on all the data.
264 *
265 * @return A collection of all items or <code>null</code>
266 * if no item under or near the point. The returned
267 * list is never empty.
268 */
269 public Collection<OsmPrimitive> getAllNearest(Point p) {
270 Collection<OsmPrimitive> nearest = new HashSet<OsmPrimitive>();
271 for (Way w : Main.ds.ways) {
272 if (w.deleted || w.incomplete) continue;
273 Node lastN = null;
274 for (Node n : w.nodes) {
275 if (n.deleted || n.incomplete) continue;
276 if (lastN == null) {
277 lastN = n;
278 continue;
279 }
280 Point A = getPoint(lastN.eastNorth);
281 Point B = getPoint(n.eastNorth);
282 double c = A.distanceSq(B);
283 double a = p.distanceSq(B);
284 double b = p.distanceSq(A);
285 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
286 if (perDist < 100 && a < c+100 && b < c+100) {
287 nearest.add(w);
288 break;
289 }
290 lastN = n;
291 }
292 }
293 for (Node n : Main.ds.nodes) {
294 if (!n.deleted && !n.incomplete
295 && getPoint(n.eastNorth).distanceSq(p) < 100) {
296 nearest.add(n);
297 }
298 }
299 return nearest.isEmpty() ? null : nearest;
300 }
301
302 /**
303 * @return A list of all nodes that are nearest to
304 * the mouse. Does a simple sequential scan on all the data.
305 *
306 * @return A collection of all nodes or <code>null</code>
307 * if no node under or near the point. The returned
308 * list is never empty.
309 */
310 public Collection<Node> getNearestNodes(Point p) {
311 Collection<Node> nearest = new HashSet<Node>();
312 for (Node n : Main.ds.nodes) {
313 if (!n.deleted && !n.incomplete
314 && getPoint(n.eastNorth).distanceSq(p) < 100) {
315 nearest.add(n);
316 }
317 }
318 return nearest.isEmpty() ? null : nearest;
319 }
320
321 /**
322 * @return the nearest nodes to the screen point given that is not
323 * in ignore.
324 *
325 * @param p the point for which to search the nearest segment.
326 * @param ignore a collection of nodes which are not to be returned.
327 * May be null.
328 */
329 public final Collection<Node> getNearestNodes(Point p, Collection<Node> ignore) {
330 Collection<Node> nearest = getNearestNodes(p);
331 if (nearest == null) return null;
332 if (ignore != null) nearest.removeAll(ignore);
333 return nearest.isEmpty() ? null : nearest;
334 }
335
336 /**
337 * @return The projection to be used in calculating stuff.
338 */
339 protected Projection getProjection() {
340 return Main.proj;
341 }
342
343 public String helpTopic() {
344 String n = getClass().getName();
345 return n.substring(n.lastIndexOf('.')+1);
346 }
347}
Note: See TracBrowser for help on using the repository browser.