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

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