source: josm/trunk/src/org/openstreetmap/josm/gui/MapViewState.java@ 10482

Last change on this file since 10482 was 10462, checked in by Don-vip, 8 years ago

sonar - Performance - Method passes constant String of length 1 to character overridden method

  • Property svn:eol-style set to native
File size: 13.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import java.awt.Container;
5import java.awt.Point;
6import java.awt.Rectangle;
7import java.awt.geom.AffineTransform;
8import java.awt.geom.Point2D;
9import java.awt.geom.Point2D.Double;
10
11import javax.swing.JComponent;
12
13import org.openstreetmap.josm.Main;
14import org.openstreetmap.josm.data.Bounds;
15import org.openstreetmap.josm.data.ProjectionBounds;
16import org.openstreetmap.josm.data.coor.EastNorth;
17import org.openstreetmap.josm.data.coor.LatLon;
18import org.openstreetmap.josm.data.projection.Projection;
19import org.openstreetmap.josm.gui.download.DownloadDialog;
20
21/**
22 * This class represents a state of the {@link MapView}.
23 * @author Michael Zangl
24 * @since 10343
25 */
26public final class MapViewState {
27
28 private final Projection projection;
29
30 private final int viewWidth;
31 private final int viewHeight;
32
33 private final double scale;
34
35 /**
36 * Top left {@link EastNorth} coordinate of the view.
37 */
38 private final EastNorth topLeft;
39
40 private final Point topLeftOnScreen;
41 private final Point topLeftInWindow;
42
43 /**
44 * Create a new {@link MapViewState}
45 * @param projection The projection to use.
46 * @param viewWidth The view width
47 * @param viewHeight The view height
48 * @param scale The scale to use
49 * @param topLeft The top left corner in east/north space.
50 */
51 private MapViewState(Projection projection, int viewWidth, int viewHeight, double scale, EastNorth topLeft) {
52 this.projection = projection;
53 this.scale = scale;
54 this.topLeft = topLeft;
55
56 this.viewWidth = viewWidth;
57 this.viewHeight = viewHeight;
58 topLeftInWindow = new Point(0, 0);
59 topLeftOnScreen = new Point(0, 0);
60 }
61
62 private MapViewState(EastNorth topLeft, MapViewState mapViewState) {
63 this.projection = mapViewState.projection;
64 this.scale = mapViewState.scale;
65 this.topLeft = topLeft;
66
67 viewWidth = mapViewState.viewWidth;
68 viewHeight = mapViewState.viewHeight;
69 topLeftInWindow = mapViewState.topLeftInWindow;
70 topLeftOnScreen = mapViewState.topLeftOnScreen;
71 }
72
73 private MapViewState(double scale, MapViewState mapViewState) {
74 this.projection = mapViewState.projection;
75 this.scale = scale;
76 this.topLeft = mapViewState.topLeft;
77
78 viewWidth = mapViewState.viewWidth;
79 viewHeight = mapViewState.viewHeight;
80 topLeftInWindow = mapViewState.topLeftInWindow;
81 topLeftOnScreen = mapViewState.topLeftOnScreen;
82 }
83
84 private MapViewState(JComponent position, MapViewState mapViewState) {
85 this.projection = mapViewState.projection;
86 this.scale = mapViewState.scale;
87 this.topLeft = mapViewState.topLeft;
88
89 viewWidth = position.getWidth();
90 viewHeight = position.getHeight();
91 topLeftInWindow = new Point();
92 // better than using swing utils, since this allows us to use the mehtod if no screen is present.
93 Container component = position;
94 while (component != null) {
95 topLeftInWindow.x += component.getX();
96 topLeftInWindow.y += component.getY();
97 component = component.getParent();
98 }
99 topLeftOnScreen = position.getLocationOnScreen();
100 }
101
102 /**
103 * The scale in east/north units per pixel.
104 * @return The scale.
105 */
106 public double getScale() {
107 return scale;
108 }
109
110 /**
111 * Gets the MapViewPoint representation for a position in view coordinates.
112 * @param x The x coordinate inside the view.
113 * @param y The y coordinate inside the view.
114 * @return The MapViewPoint.
115 */
116 public MapViewPoint getForView(double x, double y) {
117 return new MapViewViewPoint(x, y);
118 }
119
120 /**
121 * Gets the {@link MapViewPoint} for the given {@link EastNorth} coordinate.
122 * @param eastNorth the position.
123 * @return The point for that position.
124 */
125 public MapViewPoint getPointFor(EastNorth eastNorth) {
126 return new MapViewEastNorthPoint(eastNorth);
127 }
128
129 /**
130 * Gets a rectangle representing the whole view area.
131 * @return The rectangle.
132 */
133 public MapViewRectangle getViewArea() {
134 return getForView(0, 0).rectTo(getForView(viewWidth, viewHeight));
135 }
136
137 /**
138 * Gets a rectangle of the view as map view area.
139 * @param rectangle The rectangle to get.
140 * @return The view area.
141 * @since 10458
142 */
143 public MapViewRectangle getViewArea(Rectangle rectangle) {
144 return getForView(rectangle.getMinX(), rectangle.getMinY()).rectTo(getForView(rectangle.getMaxX(), rectangle.getMaxY()));
145 }
146
147 /**
148 * Gets the center of the view.
149 * @return The center position.
150 */
151 public MapViewPoint getCenter() {
152 return getForView(viewWidth / 2.0, viewHeight / 2.0);
153 }
154
155 /**
156 * Gets the width of the view on the Screen;
157 * @return The width of the view component in screen pixel.
158 */
159 public double getViewWidth() {
160 return viewWidth;
161 }
162
163 /**
164 * Gets the height of the view on the Screen;
165 * @return The height of the view component in screen pixel.
166 */
167 public double getViewHeight() {
168 return viewHeight;
169 }
170
171 /**
172 * Gets the current projection used for the MapView.
173 * @return The projection.
174 */
175 public Projection getProjection() {
176 return projection;
177 }
178
179 /**
180 * Creates an affine transform that is used to convert the east/north coordinates to view coordinates.
181 * @return The affine transform. It should not be changed.
182 * @since 10375
183 */
184 public AffineTransform getAffineTransform() {
185 return new AffineTransform(1.0 / scale, 0.0, 0.0, -1.0 / scale, -topLeft.east() / scale,
186 topLeft.north() / scale);
187 }
188
189 /**
190 * Creates a new state that is the same as the current state except for that it is using a new center.
191 * @param newCenter The new center coordinate.
192 * @return The new state.
193 * @since 10375
194 */
195 public MapViewState usingCenter(EastNorth newCenter) {
196 return movedTo(getCenter(), newCenter);
197 }
198
199 /**
200 * @param mapViewPoint The reference point.
201 * @param newEastNorthThere The east/north coordinate that should be there.
202 * @return The new state.
203 * @since 10375
204 */
205 public MapViewState movedTo(MapViewPoint mapViewPoint, EastNorth newEastNorthThere) {
206 EastNorth delta = newEastNorthThere.subtract(mapViewPoint.getEastNorth());
207 if (delta.distanceSq(0, 0) < .1e-20) {
208 return this;
209 } else {
210 return new MapViewState(topLeft.add(delta), this);
211 }
212 }
213
214 /**
215 * Creates a new state that is the same as the current state except for that it is using a new scale.
216 * @param newScale The new scale to use.
217 * @return The new state.
218 * @since 10375
219 */
220 public MapViewState usingScale(double newScale) {
221 return new MapViewState(newScale, this);
222 }
223
224 /**
225 * Creates a new state that is the same as the current state except for that it is using the location of the given component.
226 * <p>
227 * The view is moved so that the center is the same as the old center.
228 * @param positon The new location to use.
229 * @return The new state.
230 * @since 10375
231 */
232 public MapViewState usingLocation(JComponent positon) {
233 EastNorth center = this.getCenter().getEastNorth();
234 return new MapViewState(positon, this).usingCenter(center);
235 }
236
237 /**
238 * Create the default {@link MapViewState} object for the given map view. The screen position won't be set so that this method can be used
239 * before the view was added to the hirarchy.
240 * @param width The view width
241 * @param height The view height
242 * @return The state
243 * @since 10375
244 */
245 public static MapViewState createDefaultState(int width, int height) {
246 Projection projection = Main.getProjection();
247 double scale = projection.getDefaultZoomInPPD();
248 MapViewState state = new MapViewState(projection, width, height, scale, new EastNorth(0, 0));
249 EastNorth center = calculateDefaultCenter();
250 return state.movedTo(state.getCenter(), center);
251 }
252
253 private static EastNorth calculateDefaultCenter() {
254 Bounds b = DownloadDialog.getSavedDownloadBounds();
255 if (b == null) {
256 b = Main.getProjection().getWorldBoundsLatLon();
257 }
258 return Main.getProjection().latlon2eastNorth(b.getCenter());
259 }
260
261 /**
262 * A class representing a point in the map view. It allows to convert between the different coordinate systems.
263 * @author Michael Zangl
264 */
265 public abstract class MapViewPoint {
266
267 /**
268 * Get this point in view coordinates.
269 * @return The point in view coordinates.
270 */
271 public Point2D getInView() {
272 return new Point2D.Double(getInViewX(), getInViewY());
273 }
274
275 protected abstract double getInViewX();
276
277 protected abstract double getInViewY();
278
279 /**
280 * Convert this point to window coordinates.
281 * @return The point in window coordinates.
282 */
283 public Point2D getInWindow() {
284 return getUsingCorner(topLeftInWindow);
285 }
286
287 /**
288 * Convert this point to screen coordinates.
289 * @return The point in screen coordinates.
290 */
291 public Point2D getOnScreen() {
292 return getUsingCorner(topLeftOnScreen);
293 }
294
295 private Double getUsingCorner(Point corner) {
296 return new Point2D.Double(corner.getX() + getInViewX(), corner.getY() + getInViewY());
297 }
298
299 /**
300 * Gets the {@link EastNorth} coordinate of this point.
301 * @return The east/north coordinate.
302 */
303 public EastNorth getEastNorth() {
304 return new EastNorth(topLeft.east() + getInViewX() * scale, topLeft.north() - getInViewY() * scale);
305 }
306
307 /**
308 * Create a rectangle from this to the other point.
309 * @param other The other point. Needs to be of the same {@link MapViewState}
310 * @return A rectangle.
311 */
312 public MapViewRectangle rectTo(MapViewPoint other) {
313 return new MapViewRectangle(this, other);
314 }
315
316 /**
317 * Gets the current position in LatLon coordinates according to the current projection.
318 * @return The positon as LatLon.
319 */
320 public LatLon getLatLon() {
321 return projection.eastNorth2latlon(getEastNorth());
322 }
323 }
324
325 private class MapViewViewPoint extends MapViewPoint {
326 private final double x;
327 private final double y;
328
329 MapViewViewPoint(double x, double y) {
330 this.x = x;
331 this.y = y;
332 }
333
334 @Override
335 protected double getInViewX() {
336 return x;
337 }
338
339 @Override
340 protected double getInViewY() {
341 return y;
342 }
343
344 @Override
345 public String toString() {
346 return "MapViewViewPoint [x=" + x + ", y=" + y + ']';
347 }
348 }
349
350 private class MapViewEastNorthPoint extends MapViewPoint {
351
352 private final EastNorth eastNorth;
353
354 MapViewEastNorthPoint(EastNorth eastNorth) {
355 this.eastNorth = eastNorth;
356 }
357
358 @Override
359 protected double getInViewX() {
360 return (eastNorth.east() - topLeft.east()) / scale;
361 }
362
363 @Override
364 protected double getInViewY() {
365 return (topLeft.north() - eastNorth.north()) / scale;
366 }
367
368 @Override
369 public EastNorth getEastNorth() {
370 return eastNorth;
371 }
372
373 @Override
374 public String toString() {
375 return "MapViewEastNorthPoint [eastNorth=" + eastNorth + ']';
376 }
377 }
378
379 /**
380 * A rectangle on the MapView. It is rectangular in screen / EastNorth space.
381 * @author Michael Zangl
382 */
383 public class MapViewRectangle {
384 private final MapViewPoint p1;
385 private final MapViewPoint p2;
386
387 /**
388 * Create a new MapViewRectangle
389 * @param p1 The first point to use
390 * @param p2 The second point to use.
391 */
392 MapViewRectangle(MapViewPoint p1, MapViewPoint p2) {
393 this.p1 = p1;
394 this.p2 = p2;
395 }
396
397 /**
398 * Gets the projection bounds for this rectangle.
399 * @return The projection bounds.
400 */
401 public ProjectionBounds getProjectionBounds() {
402 ProjectionBounds b = new ProjectionBounds(p1.getEastNorth());
403 b.extend(p2.getEastNorth());
404 return b;
405 }
406
407 /**
408 * Gets a rough estimate of the bounds by assuming lat/lon are parallel to x/y.
409 * @return The bounds computed by converting the corners of this rectangle.
410 * @see #getLatLonBoundsBox()
411 */
412 public Bounds getCornerBounds() {
413 Bounds b = new Bounds(p1.getLatLon());
414 b.extend(p2.getLatLon());
415 return b;
416 }
417
418 /**
419 * Gets the real bounds that enclose this rectangle.
420 * This is computed respecting that the borders of this rectangle may not be a straignt line in latlon coordinates.
421 * @return The bounds.
422 * @since 10458
423 */
424 public Bounds getLatLonBoundsBox() {
425 return projection.getLatLonBoundsBox(getProjectionBounds());
426 }
427 }
428
429}
Note: See TracBrowser for help on using the repository browser.