[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