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

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