[josm-dev] [PATCH] Tile Box download tab

Robert Fitzsimons robfitz at 273k.net
Sun Nov 11 15:48:34 GMT 2007


Add a Tile Box tab to the download dialog which creates a suitable
bounding box based on the tile coordinates and zoom level entered by
the user.

Signed-off-by: Robert Fitzsimons <robfitz at 273k.net>

---

While investigating some rendering problems with my tilesAtHome client,
I was finding it inconvenient to figure out and enter the relevant
lat/log coordinates.  So the follow patch has a tab to allow the tile
details to loaded directly into JOSM.

It might be a useful feature to add to JOSM.

Robert


Index: src/org/openstreetmap/josm/gui/download/DownloadDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/DownloadDialog.java	(revision 466)
+++ src/org/openstreetmap/josm/gui/download/DownloadDialog.java	(working copy)
@@ -89,6 +89,7 @@
 		downloadSelections.add(new BoundingBoxSelection());
 		downloadSelections.add(new BookmarkSelection());	
 		downloadSelections.add(new WorldChooser());
+		downloadSelections.add(new TileBoxSelection());
 		
 		// add selections from plugins
 		for (PluginProxy p : Main.plugins) {
Index: src/org/openstreetmap/josm/gui/download/TileBoxSelection.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/TileBoxSelection.java	(revision 0)
+++ src/org/openstreetmap/josm/gui/download/TileBoxSelection.java	(revision 0)
@@ -0,0 +1,151 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.download;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.tools.GBC;
+
+/**
+ * Tile box selector.
+ * 
+ * @author Robert Fitzsimons <robfitz at 273k.net>
+ *
+ */
+public class TileBoxSelection implements DownloadSelection {
+	private final JTextField xField = new JTextField(8);
+	private final JTextField yField = new JTextField(8);
+	private final JTextField zoomField = new JTextField(4);
+
+	public void addGui(final DownloadDialog gui) {
+		final JPanel dlg = new JPanel(new GridBagLayout());
+
+		final FocusListener dialogUpdater = new FocusAdapter() {
+			@Override public void focusLost(final FocusEvent e) {
+				SwingUtilities.invokeLater(new Runnable() {
+					public void run() {
+						try {
+							final int zoom = TileBoxSelection.this.getZoom();
+							final int tileCount = tileCount(zoom);
+							final int x = Integer.parseInt(TileBoxSelection.this.xField.getText());
+							final int y = Integer.parseInt(TileBoxSelection.this.yField.getText());
+
+							if ((x < 0) || (x > tileCount) || (y < 0) || (x > tileCount)) {
+								return;
+							}
+
+							final double minlon = tileXToLongitude(x, zoom);
+							final double maxlon = minlon + tileXSize(zoom);
+
+							final double minlat = tileYToLatitude(y + 1, zoom);
+							final double maxlat = tileYToLatitude(y, zoom);
+
+							if (minlat != gui.minlat || minlon != gui.minlon || maxlat != gui.maxlat || maxlon != gui.maxlon) {
+								gui.minlat = minlat; gui.minlon = minlon; 
+								gui.maxlat = maxlat; gui.maxlon = maxlon;
+								gui.boundingBoxChanged(TileBoxSelection.this);
+							}
+						} catch (final NumberFormatException x) {
+							// ignore
+						}
+					}
+				});
+			}
+		};
+
+		this.zoomField.addFocusListener(dialogUpdater);
+		this.zoomField.setText("12");
+		this.xField.addFocusListener(dialogUpdater);
+		this.yField.addFocusListener(dialogUpdater);
+
+		dlg.add(new JLabel(tr("Enter the Zoom level, and X & Y coordinates for a tile image.")), GBC.eol().insets(10, 5, 5, 0));
+		dlg.add(new JLabel(tr("Zoom")), GBC.std().insets(10, 5, 5, 0));
+		dlg.add(this.zoomField, GBC.eol().insets(10, 5, 5, 0));
+		dlg.add(new JLabel(tr("X")), GBC.std().insets(10, 5, 5, 0));
+		dlg.add(this.xField, GBC.eol().insets(10, 5, 5, 0));
+		dlg.add(new JLabel(tr("Y")), GBC.std().insets(10, 5, 5, 0));
+		dlg.add(this.yField, GBC.eol().insets(10, 5, 5, 0));
+
+		gui.tabpane.addTab("Tile Box", dlg);
+	}
+
+	public void boundingBoxChanged(final DownloadDialog gui) {
+		final int zoom = this.getZoom();
+		final double clon = (gui.minlon + gui.maxlon) / 2;
+		final double clat = (gui.minlat + gui.maxlat) / 2;
+
+		final int x = longitudeToTileX(clon, zoom);
+		final int y = latitudeToTileY(clat, zoom);
+
+		this.xField.setText(Integer.toString(x));
+		this.yField.setText(Integer.toString(y));
+	}
+
+	private int getZoom() {
+		try {
+			final int zoom = Integer.parseInt(this.zoomField.getText());
+			if ((zoom >= 10) && (zoom <= 20)) {
+				return zoom;
+			}
+		} catch (final NumberFormatException x) {
+			// ignore
+		}
+		return 12;
+	}
+
+	private static int tileCount(final int zoom) {
+		return (int)Math.pow(2.0d, zoom);
+	}
+
+	private static double tileXSize(final int zoom) {
+		return 360.0d / tileCount(zoom);
+	}
+
+	private static double mercatorProjectionYToLatitude(final double mpy) {
+		return Math.atan(Math.sinh(mpy));
+	}
+	private static double tileYToLatitude(final int y, final int zoom) {
+		double mpy = y * (1.0d / tileCount(zoom)); // Value from 0 to 1
+		mpy = Math.PI * 2 * mpy;                   // Value from 0 to 2pi
+		mpy = Math.PI - mpy;                       // Value from -pi to +pi
+		return Math.toDegrees(mercatorProjectionYToLatitude(mpy));
+	}
+
+	private static double latitudeToMercatorProjectionY(final double radlat) {
+		return Math.log(Math.tan((Math.PI / 4) + (radlat / 2)));
+	}
+	private static int latitudeToTileY(final double lat, final int zoom) {
+		double mpy = latitudeToMercatorProjectionY(Math.toRadians(lat));
+		mpy = mpy / Math.PI;         // Values from +1 to -1
+		mpy = (1.0d - mpy) / 2.0d;   // Values from 0 to 1
+		mpy = mpy * tileCount(zoom); // Scale up to zoom level
+		return (int)Math.floor(mpy); // Round to integer value
+	}
+
+	private static double mercatorProjectionXToLongitude(final double mpx) {
+		return mpx - 180.0d; // Values from -180 to 180
+	}
+	private static double tileXToLongitude(final int x, final int zoom) {
+		return mercatorProjectionXToLongitude(x * tileXSize(zoom));
+	}
+
+	private static double longitudeToMercatorProjectionX(final double lon) {
+		return lon + 180.0d; // Values from 0 to 360
+	}
+	private static int longitudeToTileX(final double lon, final int zoom) {
+		double mpx = longitudeToMercatorProjectionX(lon);
+		mpx = mpx / 360.0d;          // Values from 0 to 1
+		mpx = mpx * tileCount(zoom); // Scale up to zoom level
+		return (int)Math.floor(mpx); // Round to integer value
+	}
+}
+







More information about the josm-dev mailing list