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

Last change on this file since 298 was 298, checked in by imi, 17 years ago
  • added license description to head of each source file
File size: 8.8 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.gui;
3
4import java.awt.Point;
5import java.util.Collection;
6import java.util.HashSet;
7
8import javax.swing.JComponent;
9
10import org.openstreetmap.josm.Main;
11import org.openstreetmap.josm.actions.HelpAction.Helpful;
12import org.openstreetmap.josm.data.coor.EastNorth;
13import org.openstreetmap.josm.data.coor.LatLon;
14import org.openstreetmap.josm.data.osm.Node;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.data.osm.Segment;
17import org.openstreetmap.josm.data.osm.Way;
18import org.openstreetmap.josm.data.projection.Projection;
19
20/**
21 * An component that can be navigated by a mapmover. Used as map view and for the
22 * zoomer in the download dialog.
23 *
24 * @author imi
25 */
26public class NavigatableComponent extends JComponent implements Helpful {
27
28
29 public static final EastNorth world = Main.proj.latlon2eastNorth(new LatLon(Projection.MAX_LAT, Projection.MAX_LON));
30
31 /**
32 * The scale factor in x or y-units per pixel. This means, if scale = 10,
33 * every physical pixel on screen are 10 x or 10 y units in the
34 * northing/easting space of the projection.
35 */
36 protected double scale;
37 /**
38 * Center n/e coordinate of the desired screen center.
39 */
40 protected EastNorth center;
41
42 public NavigatableComponent() {
43 setLayout(null);
44 }
45
46 /**
47 * Return the OSM-conform zoom factor (0 for whole world, 1 for half, 2 for quarter...)
48 */
49 public int zoom() {
50 double sizex = scale * getWidth();
51 double sizey = scale * getHeight();
52 for (int zoom = 0; zoom <= 32; zoom++, sizex *= 2, sizey *= 2)
53 if (sizex > world.east() || sizey > world.north())
54 return zoom;
55 return 32;
56 }
57
58 /**
59 * Return the current scale value.
60 * @return The scale value currently used in display
61 */
62 public double getScale() {
63 return scale;
64 }
65
66 /**
67 * @return Returns the center point. A copy is returned, so users cannot
68 * change the center by accessing the return value. Use zoomTo instead.
69 */
70 public EastNorth getCenter() {
71 return center;
72 }
73
74 /**
75 * @param x X-Pixelposition to get coordinate from
76 * @param y Y-Pixelposition to get coordinate from
77 *
78 * @return Geographic coordinates from a specific pixel coordination
79 * on the screen.
80 */
81 public EastNorth getEastNorth(int x, int y) {
82 return new EastNorth(
83 center.east() + (x - getWidth()/2.0)*scale,
84 center.north() - (y - getHeight()/2.0)*scale);
85 }
86
87 /**
88 * @param x X-Pixelposition to get coordinate from
89 * @param y Y-Pixelposition to get coordinate from
90 *
91 * @return Geographic unprojected coordinates from a specific pixel coordination
92 * on the screen.
93 */
94 public LatLon getLatLon(int x, int y) {
95 EastNorth eastNorth = new EastNorth(
96 center.east() + (x - getWidth()/2.0)*scale,
97 center.north() - (y - getHeight()/2.0)*scale);
98 return getProjection().eastNorth2latlon(eastNorth);
99 }
100
101 /**
102 * Return the point on the screen where this Coordinate would be.
103 * @param point The point, where this geopoint would be drawn.
104 * @return The point on screen where "point" would be drawn, relative
105 * to the own top/left.
106 */
107 public Point getPoint(EastNorth p) {
108 double x = (p.east()-center.east())/scale + getWidth()/2;
109 double y = (center.north()-p.north())/scale + getHeight()/2;
110 return new Point((int)x,(int)y);
111 }
112
113 /**
114 * Zoom to the given coordinate.
115 * @param centerX The center x-value (easting) to zoom to.
116 * @param centerY The center y-value (northing) to zoom to.
117 * @param scale The scale to use.
118 */
119 public void zoomTo(EastNorth newCenter, double scale) {
120 center = newCenter;
121 getProjection().eastNorth2latlon(center);
122 this.scale = scale;
123 repaint();
124 }
125
126 /**
127 * Return the nearest point to the screen point given.
128 * If a node within 10 pixel is found, the nearest node is returned.
129 */
130 public final Node getNearestNode(Point p) {
131 double minDistanceSq = Double.MAX_VALUE;
132 Node minPrimitive = null;
133 for (Node n : Main.ds.nodes) {
134 if (n.deleted)
135 continue;
136 Point sp = getPoint(n.eastNorth);
137 double dist = p.distanceSq(sp);
138 if (minDistanceSq > dist && dist < 100) {
139 minDistanceSq = p.distanceSq(sp);
140 minPrimitive = n;
141 }
142 }
143 return minPrimitive;
144 }
145
146 /**
147 * @return the nearest way to the screen point given.
148 */
149 public final Way getNearestWay(Point p) {
150 Way minPrimitive = null;
151 double minDistanceSq = Double.MAX_VALUE;
152 for (Way w : Main.ds.ways) {
153 if (w.deleted)
154 continue;
155 for (Segment ls : w.segments) {
156 if (ls.deleted || ls.incomplete)
157 continue;
158 Point A = getPoint(ls.from.eastNorth);
159 Point B = getPoint(ls.to.eastNorth);
160 double c = A.distanceSq(B);
161 double a = p.distanceSq(B);
162 double b = p.distanceSq(A);
163 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
164 if (perDist < 100 && minDistanceSq > perDist && a < c+100 && b < c+100) {
165 minDistanceSq = perDist;
166 minPrimitive = w;
167 }
168 }
169 }
170 return minPrimitive;
171 }
172
173 /**
174 * @return the nearest segment to the screen point given.
175 */
176 public final Segment getNearestSegment(Point p) {
177 Segment minPrimitive = null;
178 double minDistanceSq = Double.MAX_VALUE;
179 // segments
180 for (Segment ls : Main.ds.segments) {
181 if (ls.deleted || ls.incomplete)
182 continue;
183 Point A = getPoint(ls.from.eastNorth);
184 Point B = getPoint(ls.to.eastNorth);
185 double c = A.distanceSq(B);
186 double a = p.distanceSq(B);
187 double b = p.distanceSq(A);
188 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
189 if (perDist < 100 && minDistanceSq > perDist && a < c+100 && b < c+100) {
190 minDistanceSq = perDist;
191 minPrimitive = ls;
192 }
193 }
194 return minPrimitive;
195 }
196
197 /**
198 * Return the object, that is nearest to the given screen point.
199 *
200 * First, a node will be searched. If a node within 10 pixel is found, the
201 * nearest node is returned.
202 *
203 * If no node is found, search for pending segments.
204 *
205 * If no such segment is found, and a non-pending segment is
206 * within 10 pixel to p, this segment is returned, except when
207 * <code>wholeWay</code> is <code>true</code>, in which case the
208 * corresponding Way is returned.
209 *
210 * If no segment is found and the point is within an area, return that
211 * area.
212 *
213 * If no area is found, return <code>null</code>.
214 *
215 * @param p The point on screen.
216 * @param segmentInsteadWay Whether the segment (true) or only the whole
217 * way should be returned.
218 * @return The primitive, that is nearest to the point p.
219 */
220 public OsmPrimitive getNearest(Point p, boolean segmentInsteadWay) {
221 OsmPrimitive osm = getNearestNode(p);
222 if (osm == null && !segmentInsteadWay)
223 osm = getNearestWay(p);
224 if (osm == null)
225 osm = getNearestSegment(p);
226 return osm;
227 }
228
229 /**
230 * @return A list of all objects that are nearest to
231 * the mouse. To do this, first the nearest object is
232 * determined.
233 *
234 * If its a node, return all segments and
235 * streets the node is part of, as well as all nodes
236 * (with their segments and ways) with the same
237 * location.
238 *
239 * If its a segment, return all ways this segment
240 * belongs to as well as all segments that are between
241 * the same nodes (in both direction) with all their ways.
242 *
243 * @return A collection of all items or <code>null</code>
244 * if no item under or near the point. The returned
245 * list is never empty.
246 */
247 public Collection<OsmPrimitive> getAllNearest(Point p) {
248 OsmPrimitive osm = getNearest(p, true);
249 if (osm == null)
250 return null;
251 Collection<OsmPrimitive> c = new HashSet<OsmPrimitive>();
252 c.add(osm);
253 if (osm instanceof Node) {
254 Node node = (Node)osm;
255 for (Node n : Main.ds.nodes)
256 if (!n.deleted && n.coor.equals(node.coor))
257 c.add(n);
258 for (Segment ls : Main.ds.segments)
259 // segments never match nodes, so they are skipped by contains
260 if (!ls.deleted && !ls.incomplete && (c.contains(ls.from) || c.contains(ls.to)))
261 c.add(ls);
262 }
263 if (osm instanceof Segment) {
264 Segment line = (Segment)osm;
265 for (Segment ls : Main.ds.segments)
266 if (!ls.deleted && ls.equalPlace(line))
267 c.add(ls);
268 }
269 if (osm instanceof Node || osm instanceof Segment) {
270 for (Way w : Main.ds.ways) {
271 if (w.deleted)
272 continue;
273 for (Segment ls : w.segments) {
274 if (!ls.deleted && !ls.incomplete && c.contains(ls)) {
275 c.add(w);
276 break;
277 }
278 }
279 }
280 }
281 return c;
282 }
283
284 /**
285 * @return The projection to be used in calculating stuff.
286 */
287 protected Projection getProjection() {
288 return Main.proj;
289 }
290
291 public String helpTopic() {
292 String n = getClass().getName();
293 return n.substring(n.lastIndexOf('.')+1);
294 }
295}
Note: See TracBrowser for help on using the repository browser.