| | 1 | // License: GPL. For details, see LICENSE file. |
| | 2 | package org.openstreetmap.josm.gui; |
| | 3 | |
| | 4 | import java.awt.Point; |
| | 5 | import java.awt.geom.Point2D; |
| | 6 | import java.awt.geom.Point2D.Double; |
| | 7 | |
| | 8 | import javax.swing.SwingUtilities; |
| | 9 | |
| | 10 | import org.openstreetmap.josm.Main; |
| | 11 | import org.openstreetmap.josm.data.Bounds; |
| | 12 | import org.openstreetmap.josm.data.ProjectionBounds; |
| | 13 | import org.openstreetmap.josm.data.coor.EastNorth; |
| | 14 | import org.openstreetmap.josm.data.coor.LatLon; |
| | 15 | import org.openstreetmap.josm.data.projection.Projection; |
| | 16 | |
| | 17 | /** |
| | 18 | * This class represents a state of the {@link MapView}. |
| | 19 | * @author Michael Zangl |
| | 20 | * @since xxx |
| | 21 | */ |
| | 22 | public class MapViewState { |
| | 23 | |
| | 24 | private final Projection projection = Main.getProjection(); |
| | 25 | |
| | 26 | private final int viewWidth; |
| | 27 | private final int viewHeight; |
| | 28 | |
| | 29 | private final double scale; |
| | 30 | |
| | 31 | /** |
| | 32 | * Top left {@link EastNorth} coordinate of the view. |
| | 33 | */ |
| | 34 | private final EastNorth topLeft; |
| | 35 | |
| | 36 | private final NavigatableComponent navigatableComponent; |
| | 37 | |
| | 38 | /** |
| | 39 | * Create a new {@link MapViewState} object for the given map view. |
| | 40 | * @param navigatableComponent The view. |
| | 41 | */ |
| | 42 | public MapViewState(NavigatableComponent navigatableComponent) { |
| | 43 | this.navigatableComponent = navigatableComponent; |
| | 44 | viewWidth = navigatableComponent.getWidth(); |
| | 45 | viewHeight = navigatableComponent.getHeight(); |
| | 46 | |
| | 47 | scale = navigatableComponent.getScale(); |
| | 48 | EastNorth center = navigatableComponent.getCenter(); |
| | 49 | topLeft = new EastNorth(center.east() - viewWidth / 2.0 * scale, center.north() + viewHeight / 2.0 * scale); |
| | 50 | } |
| | 51 | |
| | 52 | /** |
| | 53 | * Gets the MapViewPoint representation for a position in view coordinates. |
| | 54 | * @param x The x coordinate inside the view. |
| | 55 | * @param y The y coordinate inside the view. |
| | 56 | * @return The MapViewPoint. |
| | 57 | */ |
| | 58 | public MapViewPoint getForView(double x, double y) { |
| | 59 | return new MapViewViewPoint(x, y); |
| | 60 | } |
| | 61 | |
| | 62 | /** |
| | 63 | * Gets the {@link MapViewPoint} for the given {@link EastNorth} coordinate. |
| | 64 | * @param eastNorth the position. |
| | 65 | * @return The point for that position. |
| | 66 | */ |
| | 67 | public MapViewPoint getPointFor(EastNorth eastNorth) { |
| | 68 | return new MapViewEastNorthPoint(eastNorth); |
| | 69 | } |
| | 70 | |
| | 71 | /** |
| | 72 | * Gets a rectangle representing the whole view area. |
| | 73 | * @return The rectangle. |
| | 74 | */ |
| | 75 | public MapViewRectangle getViewArea() { |
| | 76 | return getForView(0, 0).rectTo(getForView(viewWidth, viewHeight)); |
| | 77 | } |
| | 78 | |
| | 79 | /** |
| | 80 | * Gets the center of the view. |
| | 81 | * @return The center position. |
| | 82 | */ |
| | 83 | public MapViewPoint getCenter() { |
| | 84 | return getForView(viewWidth / 2.0, viewHeight / 2.0); |
| | 85 | } |
| | 86 | |
| | 87 | /** |
| | 88 | * Gets the width of the view on the Screen; |
| | 89 | * @return The width of the view component in screen pixel. |
| | 90 | */ |
| | 91 | public double getViewWidth() { |
| | 92 | return viewWidth; |
| | 93 | } |
| | 94 | |
| | 95 | /** |
| | 96 | * Gets the height of the view on the Screen; |
| | 97 | * @return The height of the view component in screen pixel. |
| | 98 | */ |
| | 99 | public double getViewHeight() { |
| | 100 | return viewHeight; |
| | 101 | } |
| | 102 | |
| | 103 | /** |
| | 104 | * Gets the current projection used for the MapView. |
| | 105 | * @return The projection. |
| | 106 | */ |
| | 107 | public Projection getProjection() { |
| | 108 | return projection; |
| | 109 | } |
| | 110 | |
| | 111 | /** |
| | 112 | * A class representing a point in the map view. It allws to convert between the different coordinate systems. |
| | 113 | * @author Michael Zangl |
| | 114 | * @since xxx |
| | 115 | */ |
| | 116 | public abstract class MapViewPoint { |
| | 117 | |
| | 118 | /** |
| | 119 | * Get this point in view coordinates. |
| | 120 | * @return The point in view coordinates. |
| | 121 | */ |
| | 122 | public Point2D getInView() { |
| | 123 | return new Point2D.Double(getInViewX(), getInViewY()); |
| | 124 | } |
| | 125 | |
| | 126 | protected abstract double getInViewX(); |
| | 127 | |
| | 128 | protected abstract double getInViewY(); |
| | 129 | |
| | 130 | /** |
| | 131 | * Convert this point to window coordinates. |
| | 132 | * @return The point in window coordinates. |
| | 133 | */ |
| | 134 | public Point2D getInWindow() { |
| | 135 | Point corner = SwingUtilities.convertPoint(navigatableComponent, new Point(0, 0), null); |
| | 136 | return getUsingCorner(corner); |
| | 137 | } |
| | 138 | |
| | 139 | /** |
| | 140 | * Convert this point to screen coordinates. |
| | 141 | * @return The point in screen coordinates. |
| | 142 | */ |
| | 143 | public Point2D getOnScreen() { |
| | 144 | Point corner = new Point(0, 0); |
| | 145 | SwingUtilities.convertPointToScreen(corner, navigatableComponent); |
| | 146 | return getUsingCorner(corner); |
| | 147 | } |
| | 148 | |
| | 149 | private Double getUsingCorner(Point corner) { |
| | 150 | return new Point2D.Double(corner.getX() + getInViewX(), corner.getY() + getInViewY()); |
| | 151 | } |
| | 152 | |
| | 153 | /** |
| | 154 | * Gets the {@link EastNorth} coordinate of this point. |
| | 155 | * @return The east/north coordinate. |
| | 156 | */ |
| | 157 | public EastNorth getEastNorth() { |
| | 158 | return new EastNorth(topLeft.east() + getInViewX() * scale, topLeft.north() - getInViewY() * scale); |
| | 159 | } |
| | 160 | |
| | 161 | /** |
| | 162 | * Create a rectangle from this to the other point. |
| | 163 | * @param other The other point. Needs to be of the same {@link MapViewState} |
| | 164 | * @return A rectangle. |
| | 165 | */ |
| | 166 | public MapViewRectangle rectTo(MapViewPoint other) { |
| | 167 | return new MapViewRectangle(this, other); |
| | 168 | } |
| | 169 | |
| | 170 | /** |
| | 171 | * Gets the current position in LatLon coordinates according to the current projection. |
| | 172 | * @return The positon as LatLon. |
| | 173 | */ |
| | 174 | public LatLon getLatLon() { |
| | 175 | return projection.eastNorth2latlon(getEastNorth()); |
| | 176 | } |
| | 177 | |
| | 178 | } |
| | 179 | |
| | 180 | private class MapViewViewPoint extends MapViewPoint { |
| | 181 | private final double x; |
| | 182 | private final double y; |
| | 183 | |
| | 184 | MapViewViewPoint(double x, double y) { |
| | 185 | this.x = x; |
| | 186 | this.y = y; |
| | 187 | } |
| | 188 | |
| | 189 | @Override |
| | 190 | protected double getInViewX() { |
| | 191 | return x; |
| | 192 | } |
| | 193 | |
| | 194 | @Override |
| | 195 | protected double getInViewY() { |
| | 196 | return y; |
| | 197 | } |
| | 198 | |
| | 199 | @Override |
| | 200 | public String toString() { |
| | 201 | return "MapViewViewPoint [x=" + x + ", y=" + y + "]"; |
| | 202 | } |
| | 203 | } |
| | 204 | |
| | 205 | private class MapViewEastNorthPoint extends MapViewPoint { |
| | 206 | |
| | 207 | private final EastNorth eastNorth; |
| | 208 | |
| | 209 | MapViewEastNorthPoint(EastNorth eastNorth) { |
| | 210 | this.eastNorth = eastNorth; |
| | 211 | } |
| | 212 | |
| | 213 | @Override |
| | 214 | protected double getInViewX() { |
| | 215 | return (eastNorth.east() - topLeft.east()) / scale; |
| | 216 | } |
| | 217 | |
| | 218 | @Override |
| | 219 | protected double getInViewY() { |
| | 220 | return (topLeft.north() - eastNorth.north()) / scale; |
| | 221 | } |
| | 222 | |
| | 223 | @Override |
| | 224 | public EastNorth getEastNorth() { |
| | 225 | return eastNorth; |
| | 226 | } |
| | 227 | |
| | 228 | @Override |
| | 229 | public String toString() { |
| | 230 | return "MapViewEastNorthPoint [eastNorth=" + eastNorth + "]"; |
| | 231 | } |
| | 232 | |
| | 233 | } |
| | 234 | |
| | 235 | /** |
| | 236 | * A rectangle on the MapView. It is rectangular in screen / EastNorth space. |
| | 237 | * @author Michael Zangl |
| | 238 | * @since xxx |
| | 239 | */ |
| | 240 | public class MapViewRectangle { |
| | 241 | private final MapViewPoint p1; |
| | 242 | private final MapViewPoint p2; |
| | 243 | |
| | 244 | /** |
| | 245 | * Create a new MapViewRectangle |
| | 246 | * @param p1 The first point to use |
| | 247 | * @param p2 The second point to use. |
| | 248 | */ |
| | 249 | MapViewRectangle(MapViewPoint p1, MapViewPoint p2) { |
| | 250 | super(); |
| | 251 | this.p1 = p1; |
| | 252 | this.p2 = p2; |
| | 253 | } |
| | 254 | |
| | 255 | /** |
| | 256 | * Gets the projection bounds for this rectangle. |
| | 257 | * @return The projection bounds. |
| | 258 | */ |
| | 259 | public ProjectionBounds getProjectionBounds() { |
| | 260 | ProjectionBounds b = new ProjectionBounds(p1.getEastNorth()); |
| | 261 | b.extend(p2.getEastNorth()); |
| | 262 | return b; |
| | 263 | } |
| | 264 | |
| | 265 | /** |
| | 266 | * Gets a rough estimate of the bounds by assuming lat/lon are parallel to x/y. |
| | 267 | * @return The bounds computed by converting the corners of this rectangle. |
| | 268 | */ |
| | 269 | public Bounds getCornerBounds() { |
| | 270 | Bounds b = new Bounds(p1.getLatLon()); |
| | 271 | b.extend(p2.getLatLon()); |
| | 272 | return b; |
| | 273 | } |
| | 274 | } |
| | 275 | |
| | 276 | } |