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

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