diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..663bc1b --- /dev/null +++ b/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98217d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build +.settings + diff --git a/.project b/.project new file mode 100644 index 0000000..8a6fe0e --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + JOSM-walkingpapers + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/README b/README new file mode 100644 index 0000000..52fa214 --- /dev/null +++ b/README @@ -0,0 +1,6 @@ +A plugin for displaying tiled, scanned maps from walking-papers.org. + +Written by Frederik Ramm , based on SlippyMap +plugin work by Lubomir Varga or . + +Public Domain. diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..34ac7d5 --- /dev/null +++ b/build.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + diff --git a/data/bg.lang b/data/bg.lang new file mode 100644 index 0000000..b30d90f Binary files /dev/null and b/data/bg.lang differ diff --git a/data/ca.lang b/data/ca.lang new file mode 100644 index 0000000..1e75f29 Binary files /dev/null and b/data/ca.lang differ diff --git a/data/cs.lang b/data/cs.lang new file mode 100644 index 0000000..cff2b09 Binary files /dev/null and b/data/cs.lang differ diff --git a/data/da.lang b/data/da.lang new file mode 100644 index 0000000..e682717 Binary files /dev/null and b/data/da.lang differ diff --git a/data/de.lang b/data/de.lang new file mode 100644 index 0000000..76868a2 Binary files /dev/null and b/data/de.lang differ diff --git a/data/el.lang b/data/el.lang new file mode 100644 index 0000000..9c9af41 Binary files /dev/null and b/data/el.lang differ diff --git a/data/en.lang b/data/en.lang new file mode 100644 index 0000000..a4c40e8 Binary files /dev/null and b/data/en.lang differ diff --git a/data/en_AU.lang b/data/en_AU.lang new file mode 100644 index 0000000..30b6b2b --- /dev/null +++ b/data/en_AU.lang @@ -0,0 +1 @@ +ÿþÿþÿþÿþÿþÿþÿþÿÿ \ No newline at end of file diff --git a/data/en_GB.lang b/data/en_GB.lang new file mode 100644 index 0000000..30b6b2b --- /dev/null +++ b/data/en_GB.lang @@ -0,0 +1 @@ +ÿþÿþÿþÿþÿþÿþÿþÿÿ \ No newline at end of file diff --git a/data/es.lang b/data/es.lang new file mode 100644 index 0000000..20ff18a Binary files /dev/null and b/data/es.lang differ diff --git a/data/et.lang b/data/et.lang new file mode 100644 index 0000000..64329c7 Binary files /dev/null and b/data/et.lang differ diff --git a/data/eu.lang b/data/eu.lang new file mode 100644 index 0000000..f6bb522 Binary files /dev/null and b/data/eu.lang differ diff --git a/data/fr.lang b/data/fr.lang new file mode 100644 index 0000000..96d0914 Binary files /dev/null and b/data/fr.lang differ diff --git a/data/gl.lang b/data/gl.lang new file mode 100644 index 0000000..d2e3f73 Binary files /dev/null and b/data/gl.lang differ diff --git a/data/id.lang b/data/id.lang new file mode 100644 index 0000000..e161a7c Binary files /dev/null and b/data/id.lang differ diff --git a/data/it.lang b/data/it.lang new file mode 100644 index 0000000..3f8e5d4 Binary files /dev/null and b/data/it.lang differ diff --git a/data/ja.lang b/data/ja.lang new file mode 100644 index 0000000..0874920 Binary files /dev/null and b/data/ja.lang differ diff --git a/data/nl.lang b/data/nl.lang new file mode 100644 index 0000000..8c95718 Binary files /dev/null and b/data/nl.lang differ diff --git a/data/pl.lang b/data/pl.lang new file mode 100644 index 0000000..768900c Binary files /dev/null and b/data/pl.lang differ diff --git a/data/pt.lang b/data/pt.lang new file mode 100644 index 0000000..023ba19 Binary files /dev/null and b/data/pt.lang differ diff --git a/data/pt_BR.lang b/data/pt_BR.lang new file mode 100644 index 0000000..8f1965f Binary files /dev/null and b/data/pt_BR.lang differ diff --git a/data/ru.lang b/data/ru.lang new file mode 100644 index 0000000..3de0c37 Binary files /dev/null and b/data/ru.lang differ diff --git a/data/sk.lang b/data/sk.lang new file mode 100644 index 0000000..0c7dc14 Binary files /dev/null and b/data/sk.lang differ diff --git a/data/uk.lang b/data/uk.lang new file mode 100644 index 0000000..62b22a1 Binary files /dev/null and b/data/uk.lang differ diff --git a/data/zh_CN.lang b/data/zh_CN.lang new file mode 100644 index 0000000..d0cabe2 Binary files /dev/null and b/data/zh_CN.lang differ diff --git a/data/zh_TW.lang b/data/zh_TW.lang new file mode 100644 index 0000000..6685442 Binary files /dev/null and b/data/zh_TW.lang differ diff --git a/images/preferences/walkingpapers.png b/images/preferences/walkingpapers.png new file mode 100644 index 0000000..ea18599 Binary files /dev/null and b/images/preferences/walkingpapers.png differ diff --git a/images/walkingpapers.png b/images/walkingpapers.png new file mode 100644 index 0000000..054bafc Binary files /dev/null and b/images/walkingpapers.png differ diff --git a/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersAddLayerAction.java b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersAddLayerAction.java new file mode 100644 index 0000000..ac3eb9b --- /dev/null +++ b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersAddLayerAction.java @@ -0,0 +1,105 @@ +package org.openstreetmap.josm.plugins.fieldpapers; + +import static org.openstreetmap.josm.tools.I18n.tr; + +import java.awt.event.ActionEvent; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.JOptionPane; + +import org.openstreetmap.josm.Main; +import org.openstreetmap.josm.actions.JosmAction; +import org.openstreetmap.josm.data.Bounds; +import org.openstreetmap.josm.data.coor.LatLon; + +@SuppressWarnings("serial") +public class FieldPapersAddLayerAction extends JosmAction { + + public FieldPapersAddLayerAction() { + super(tr("Scanned Map..."), "walkingpapers", + tr("Display a map that was previously scanned and uploaded to walking-papers.org"), null, false); + } + + public void actionPerformed(ActionEvent e) { + String wpid = JOptionPane.showInputDialog(Main.parent, + tr("Enter a walking-papers.org URL or ID (the bit after the ?id= in the URL)"), + Main.pref.get("walkingpapers.last-used-id")); + + if (wpid == null || wpid.equals("")) return; + + // Grab id= from the URL if we need to, otherwise get an ID + String mungedWpId = this.getWalkingPapersId(wpid); + + if (mungedWpId == null || mungedWpId.equals("")) return; + + // screen-scrape details about this id from walking-papers.org + String wpUrl = Main.pref.get("walkingpapers.base-url", "http://walking-papers.org/") + "scan.php?id=" + mungedWpId; + + Pattern spanPattern = Pattern.compile("(\\S+)"); + Matcher m; + + double north = 0; + double south = 0; + double east = 0; + double west = 0; + int minz = -1; + int maxz = -1; + String tile = null; + + try { + BufferedReader r = new BufferedReader(new InputStreamReader(new URL(wpUrl).openStream(), "utf-8")); + for (String line = r.readLine(); line != null; line = r.readLine()) { + m = spanPattern.matcher(line); + if (m.find()) { + if ("tile".equals(m.group(1))) tile = m.group(2); + else if ("north".equals(m.group(1))) north = Double.parseDouble(m.group(2)); + else if ("south".equals(m.group(1))) south = Double.parseDouble(m.group(2)); + else if ("east".equals(m.group(1))) east = Double.parseDouble(m.group(2)); + else if ("west".equals(m.group(1))) west = Double.parseDouble(m.group(2)); + else if ("minzoom".equals(m.group(1))) minz = Integer.parseInt(m.group(2)); + else if ("maxzoom".equals(m.group(1))) maxz = Integer.parseInt(m.group(2)); + } + } + r.close(); + if ((tile == null) || (north == 0 && south == 0) || (east == 0 && west == 0)) throw new Exception(); + } catch (Exception ex) { + JOptionPane.showMessageDialog(Main.parent,tr("Could not read information from walking-papers.org the id \"{0}\"", mungedWpId)); + return; + } + + + //http://walking-papers.org/scan.php?id=rmvdr3lq + // The server is apparently broken and returning the WpId in the URL twice + // which makes it return errors when we fetch it. So, strip out one of + // the dups. This is a hack and needs to get removed when the server + // is fixed. + tile = tile.replaceFirst(mungedWpId+"/"+mungedWpId, mungedWpId); + Main.pref.put("walkingpapers.last-used-id", mungedWpId); + + Bounds b = new Bounds(new LatLon(south, west), new LatLon(north, east)); + + FieldPapersLayer wpl = new FieldPapersLayer(mungedWpId, tile, b, minz, maxz); + Main.main.addLayer(wpl); + + } + + private static String getWalkingPapersId(String wpid) { + if (!wpid.contains("id=")) { + return wpid; + } else { + // To match e.g. http://walking-papers.org/scan.php?id=53h78bbx + final Pattern pattern = Pattern.compile("\\?id=(\\S+)"); + final Matcher matcher = pattern.matcher(wpid); + final boolean found = matcher.find(); + + if (found) { + return matcher.group(1); + } + } + return null; + } +} diff --git a/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersKey.java b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersKey.java new file mode 100644 index 0000000..8d5f759 --- /dev/null +++ b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersKey.java @@ -0,0 +1,78 @@ +/** + * + */ +package org.openstreetmap.josm.plugins.fieldpapers; + +/** + *

+ * Key for map tile. Key have just X and Y value. It have overriden {@link #hashCode()}, + * {@link #equals(Object)} and also {@link #toString()}. + *

+ * + * @author LuVar + * @author Dave Hansen + * + */ +public class FieldPapersKey { + private final int x; + private final int y; + private final int level; + + /** + *

+ * Constructs key for hashmaps for some tile describedy by X and Y position. X and Y are tiles + * positions on discrete map. + *

+ * + * @param x x position in tiles table + * @param y y position in tiles table + */ + public final boolean valid; + public FieldPapersKey(int level, int x, int y) { + this.x = x; + this.y = y; + this.level = level; + if (level <= 0 || x < 0 || y < 0) { + this.valid = false; + System.err.println("invalid WalkingPapersKey("+level+", "+x+", "+y+")"); + } else { + this.valid = true; + } + } + + /** + *

+ * Returns true ONLY if x and y are equals. + *

+ * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof FieldPapersKey) { + FieldPapersKey smk = (FieldPapersKey) obj; + if((smk.x == this.x) && (smk.y == this.y) && (smk.level == this.level)) { + return true; + } + } + return false; + } + + /** + * @return return new Integer(this.x + this.y * 10000).hashCode(); + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return new Integer(this.x + this.y * 10000 + this.level * 100000).hashCode(); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "WalkingPapersKey(x=" + this.x + ",y=" + this.y + ",level=" + level + ")"; + } + +} diff --git a/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersLayer.java b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersLayer.java new file mode 100644 index 0000000..421dec5 --- /dev/null +++ b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersLayer.java @@ -0,0 +1,427 @@ +package org.openstreetmap.josm.plugins.fieldpapers; + +import static org.openstreetmap.josm.tools.I18n.tr; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Point; +import java.awt.image.ImageObserver; +import java.net.URL; +import java.util.Comparator; +import java.util.HashMap; +import java.util.TreeSet; + +import javax.swing.Action; +import javax.swing.Icon; + +import org.openstreetmap.josm.Main; +import org.openstreetmap.josm.data.Bounds; +import org.openstreetmap.josm.data.coor.LatLon; +import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; +import org.openstreetmap.josm.gui.MapView; +import org.openstreetmap.josm.gui.MapView.LayerChangeListener; +import org.openstreetmap.josm.gui.dialogs.LayerListDialog; +import org.openstreetmap.josm.gui.dialogs.LayerListPopup; +import org.openstreetmap.josm.gui.layer.Layer; +import org.openstreetmap.josm.tools.ImageProvider; + +/** + * Class that displays a slippy map layer. Adapted from SlippyMap plugin for Walking Papers use. + * + * @author Frederik Ramm + * @author LuVar + * @author Dave Hansen + * + */ +public class FieldPapersLayer extends Layer implements ImageObserver { + /** + * Actual zoom lvl. Initial zoom lvl is set to + * {@link WalkingPapersPreferences#getMinZoomLvl()}. + */ + private int currentZoomLevel; + private HashMap tileStorage = null; + + private Point[][] pixelpos = new Point[21][21]; + private LatLon lastTopLeft; + private LatLon lastBotRight; + private int viewportMinX, viewportMaxX, viewportMinY, viewportMaxY; + private Image bufferImage; + private boolean needRedraw; + + private int minzoom, maxzoom; + private Bounds printBounds; + private String tileUrlTemplate; + private String walkingPapersId; + + @SuppressWarnings("serial") + public FieldPapersLayer(String id, String tile, Bounds b, int minz, int maxz) { + super(tr("Walking Papers: {0}", id)); + setBackgroundLayer(true); + walkingPapersId = id; + + tileUrlTemplate = tile; + this.printBounds = b; + this.minzoom = minz; this.maxzoom = maxz; + currentZoomLevel = minz; + + clearTileStorage(); + + MapView.addLayerChangeListener(new LayerChangeListener() { + public void activeLayerChange(Layer oldLayer, Layer newLayer) { + // if user changes to a walking papers layer, zoom there just as if + // it was newly added + layerAdded(newLayer); + } + + public void layerAdded(Layer newLayer) { + // only do something if we are affected + if (newLayer != FieldPapersLayer.this) return; + BoundingXYVisitor bbox = new BoundingXYVisitor(); + bbox.visit(printBounds); + Main.map.mapView.recalculateCenterScale(bbox); + needRedraw = true; + } + + public void layerRemoved(Layer oldLayer) { + if (oldLayer == FieldPapersLayer.this) { + MapView.removeLayerChangeListener(this); + } + } + }); + } + + /** + * Zoom in, go closer to map. + */ + public void increaseZoomLevel() { + if (currentZoomLevel < maxzoom) { + currentZoomLevel++; + needRedraw = true; + } + } + + /** + * Zoom out from map. + */ + public void decreaseZoomLevel() { + if (currentZoomLevel > minzoom) { + currentZoomLevel--; + needRedraw = true; + } + } + + public void clearTileStorage() { + tileStorage = new HashMap(); + checkTileStorage(); + } + + static class TileTimeComp implements Comparator { + public int compare(FieldPapersTile s1, FieldPapersTile s2) { + long t1 = s1.access_time(); + long t2 = s2.access_time(); + if (s1 == s2) return 0; + if (t1 == t2) { + t1 = s1.hashCode(); + t2 = s2.hashCode(); + } + if (t1 < t2) return -1; + return 1; + } + } + + long lastCheck = 0; + /** + *

+ * Check if tiles.size() is not more than max_nr_tiles. If yes, oldest tiles by timestamp + * are fired out from cache. + *

+ */ + public void checkTileStorage() { + long now = System.currentTimeMillis(); + if (now - lastCheck < 1000) return; + lastCheck = now; + TreeSet tiles = new TreeSet(new TileTimeComp()); + tiles.addAll(tileStorage.values()); + int max_nr_tiles = 100; + if (tiles.size() < max_nr_tiles) { + return; + } + int dropCount = tiles.size() - max_nr_tiles;; + for (FieldPapersTile t : tiles) { + if (dropCount <= 0) + break; + t.dropImage(); + dropCount--; + } + } + + void loadSingleTile(FieldPapersTile tile) { + tile.loadImage(); + this.checkTileStorage(); + } + + /* + * Attempt to approximate how much the image is + * being scaled. For instance, a 100x100 image + * being scaled to 50x50 would return 0.25. + */ + Double getImageScaling(Image img, Point p0, Point p1) { + int realWidth = img.getWidth(this); + int realHeight = img.getHeight(this); + if (realWidth == -1 || realHeight == -1) + return null; + int drawWidth = p1.x - p0.x; + int drawHeight = p1.x - p0.x; + + double drawArea = drawWidth * drawHeight; + double realArea = realWidth * realHeight; + + return drawArea / realArea; + } + + /** + */ + @Override + public void paint(Graphics2D g, MapView mv, Bounds bounds) { + LatLon topLeft = mv.getLatLon(0, 0); + LatLon botRight = mv.getLatLon(mv.getWidth(), mv.getHeight()); + Graphics2D oldg = g; + + if (botRight.lon() == 0.0 || botRight.lat() == 0) { + // probably still initializing + return; + } + if (lastTopLeft != null && lastBotRight != null + && topLeft.equalsEpsilon(lastTopLeft) + && botRight.equalsEpsilon(lastBotRight) && bufferImage != null + && mv.getWidth() == bufferImage.getWidth(null) + && mv.getHeight() == bufferImage.getHeight(null) && !needRedraw) { + + g.drawImage(bufferImage, 0, 0, null); + return; + } + + needRedraw = false; + lastTopLeft = topLeft; + lastBotRight = botRight; + bufferImage = mv.createImage(mv.getWidth(), mv.getHeight()); + g = (Graphics2D) bufferImage.getGraphics(); + + if (!LatLon.isValidLat(topLeft.lat()) || + !LatLon.isValidLat(botRight.lat()) || + !LatLon.isValidLon(topLeft.lon()) || + !LatLon.isValidLon(botRight.lon())) + return; + + viewportMinX = lonToTileX(topLeft.lon()); + viewportMaxX = lonToTileX(botRight.lon()); + viewportMinY = latToTileY(topLeft.lat()); + viewportMaxY = latToTileY(botRight.lat()); + + if (viewportMinX > viewportMaxX) { + int tmp = viewportMinX; + viewportMinX = viewportMaxX; + viewportMaxX = tmp; + } + if (viewportMinY > viewportMaxY) { + int tmp = viewportMinY; + viewportMinY = viewportMaxY; + viewportMaxY = tmp; + } + + if (viewportMaxX-viewportMinX > 18) return; + if (viewportMaxY-viewportMinY > 18) return; + + for (int x = viewportMinX - 1; x <= viewportMaxX + 1; x++) { + double lon = tileXToLon(x); + for (int y = viewportMinY - 1; y <= viewportMaxY + 1; y++) { + LatLon tmpLL = new LatLon(tileYToLat(y), lon); + pixelpos[x - viewportMinX + 1][y - viewportMinY + 1] = mv.getPoint(Main.getProjection() + .latlon2eastNorth(tmpLL)); + } + } + + g.setColor(Color.DARK_GRAY); + + Double imageScale = null; + int count = 0; + + for (int x = viewportMinX-1; x <= viewportMaxX; x++) { + + for (int y = viewportMinY-1; y <= viewportMaxY; y++) { + FieldPapersKey key = new FieldPapersKey(currentZoomLevel, x, y); + FieldPapersTile tile; + tile = tileStorage.get(key); + if (!key.valid) continue; + if (tile == null) { + // check if tile is in range + Bounds tileBounds = new Bounds(new LatLon(tileYToLat(y+1), tileXToLon(x)), + new LatLon(tileYToLat(y), tileXToLon(x+1))); + if (!tileBounds.asRect().intersects(printBounds.asRect())) continue; + tile = new FieldPapersTile(x, y, currentZoomLevel, this); + tileStorage.put(key, tile); + loadSingleTile(tile); + checkTileStorage(); + } + Image img = tile.getImage(); + + if (img != null) { + Point p = pixelpos[x - viewportMinX + 1][y - viewportMinY + 1]; + Point p2 = pixelpos[x - viewportMinX + 2][y - viewportMinY + 2]; + g.drawImage(img, p.x, p.y, p2.x - p.x, p2.y - p.y, this); + if (imageScale == null) + imageScale = getImageScaling(img, p, p2); + count++; + } + } + } + + if (count == 0) + { + //System.out.println("no images on " + walkingPapersId + ", return"); + return; + } + + oldg.drawImage(bufferImage, 0, 0, null); + + if (imageScale != null) { + // If each source image pixel is being stretched into > 3 + // drawn pixels, zoom in... getting too pixelated + if (imageScale > 3) { + increaseZoomLevel(); + this.paint(oldg, mv, bounds); + } + + // If each source image pixel is being squished into > 0.32 + // of a drawn pixels, zoom out. + else if (imageScale < 0.32) { + decreaseZoomLevel(); + this.paint(oldg, mv, bounds); + } + } + }// end of paint metod + + FieldPapersTile getTileForPixelpos(int px, int py) { + int tilex = viewportMaxX; + int tiley = viewportMaxY; + for (int x = viewportMinX; x <= viewportMaxX; x++) { + if (pixelpos[x - viewportMinX + 1][0].x > px) { + tilex = x - 1; + break; + } + } + + if (tilex == -1) return null; + + for (int y = viewportMinY; y <= viewportMaxY; y++) { + if (pixelpos[0][y - viewportMinY + 1].y > py) { + tiley = y - 1; + break; + } + } + + if (tiley == -1) return null; + + FieldPapersKey key = new FieldPapersKey(currentZoomLevel, tilex, tiley); + if (!key.valid) { + System.err.println("getTileForPixelpos("+px+","+py+") made invalid key"); + return null; + } + FieldPapersTile tile = tileStorage.get(key); + if (tile == null) + tileStorage.put(key, tile = new FieldPapersTile(tilex, tiley, currentZoomLevel, this)); + checkTileStorage(); + return tile; + } + + @Override + public Icon getIcon() { + return ImageProvider.get("walkingpapers"); + } + + @Override + public Object getInfoComponent() { + return getToolTipText(); + } + + @Override + public Action[] getMenuEntries() { + return new Action[] { + LayerListDialog.getInstance().createShowHideLayerAction(), + LayerListDialog.getInstance().createDeleteLayerAction(), + SeparatorLayerAction.INSTANCE, + // color, + // new JMenuItem(new RenameLayerAction(associatedFile, this)), + SeparatorLayerAction.INSTANCE, + new LayerListPopup.InfoAction(this) }; + } + + @Override + public String getToolTipText() { + return tr("Walking Papers layer ({0}) in zoom {1}", this.getWalkingPapersId(), currentZoomLevel); + } + + @Override + public boolean isMergable(Layer other) { + return false; + } + + @Override + public void mergeFrom(Layer from) { + } + + @Override + public void visitBoundingBox(BoundingXYVisitor v) { + if (printBounds != null) + v.visit(printBounds); + } + + private int latToTileY(double lat) { + double l = lat / 180 * Math.PI; + double pf = Math.log(Math.tan(l) + (1 / Math.cos(l))); + return (int) (Math.pow(2.0, currentZoomLevel - 1) * (Math.PI - pf) / Math.PI); + } + + private int lonToTileX(double lon) { + return (int) (Math.pow(2.0, currentZoomLevel - 3) * (lon + 180.0) / 45.0); + } + + private double tileYToLat(int y) { + return Math.atan(Math.sinh(Math.PI + - (Math.PI * y / Math.pow(2.0, currentZoomLevel - 1)))) + * 180 / Math.PI; + } + + private double tileXToLon(int x) { + return x * 45.0 / Math.pow(2.0, currentZoomLevel - 3) - 180.0; + } + + public boolean imageUpdate(Image img, int infoflags, int x, int y, + int width, int height) { + boolean done = ((infoflags & (ERROR | FRAMEBITS | ALLBITS)) != 0); + if ((infoflags & ERROR) != 0) return false; + // Repaint immediately if we are done, otherwise batch up + // repaint requests every 100 milliseconds + needRedraw = true; + Main.map.repaint(done ? 0 : 100); + return !done; + } + + public String getWalkingPapersId() { + return walkingPapersId; + } + + public URL formatImageUrl(int x, int y, int z) { + String urlstr = tileUrlTemplate. + replace("{x}", String.valueOf(x)). + replace("{y}", String.valueOf(y)). + replace("{z}", String.valueOf(z)); + try { + return new URL(urlstr); + } catch (Exception ex) { + return null; + } + } + +} diff --git a/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersPlugin.java b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersPlugin.java new file mode 100644 index 0000000..bfbf7b9 --- /dev/null +++ b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersPlugin.java @@ -0,0 +1,33 @@ +package org.openstreetmap.josm.plugins.fieldpapers; + +import static org.openstreetmap.josm.gui.help.HelpUtil.ht; +import static org.openstreetmap.josm.tools.I18n.marktr; + +import java.awt.event.KeyEvent; + +import javax.swing.JMenu; +import javax.swing.JMenuItem; + +import org.openstreetmap.josm.Main; +import org.openstreetmap.josm.gui.MainMenu; +import org.openstreetmap.josm.plugins.Plugin; +import org.openstreetmap.josm.plugins.PluginInformation; + +/** + * Main class for the walking papers plugin. + * + * @author Frederik Ramm + * + */ +public class FieldPapersPlugin extends Plugin +{ + static JMenu walkingPapersMenu; + + public FieldPapersPlugin(PluginInformation info) + { + super(info); + MainMenu menu = Main.main.menu; + walkingPapersMenu = menu.addMenu(marktr("Walking Papers"), KeyEvent.VK_K, menu.defaultMenuPos, ht("/Plugin/WalkingPapers")); + walkingPapersMenu.add(new JMenuItem(new FieldPapersAddLayerAction())); + } +} diff --git a/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersTile.java b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersTile.java new file mode 100644 index 0000000..9679e03 --- /dev/null +++ b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersTile.java @@ -0,0 +1,67 @@ +package org.openstreetmap.josm.plugins.fieldpapers; + +import java.awt.Image; +import java.awt.Toolkit; +import java.net.URL; + +/** + * Class that contains information about one single slippy map tile. + * + * @author Frederik Ramm + * @author LuVar + * @author Dave Hansen + * + */ +public class FieldPapersTile { + private Image tileImage; + long timestamp; + + int x; + int y; + int z; + + FieldPapersLayer parentLayer; + + + public FieldPapersTile(int x, int y, int z, FieldPapersLayer parent) { + this.x = x; + this.y = y; + this.z = z; + parentLayer = parent; + timestamp = System.currentTimeMillis(); + } + + public URL getImageUrl() { + return parentLayer.formatImageUrl(x, y, z); + } + + public void loadImage() { + URL imageUrl = this.getImageUrl(); + tileImage = Toolkit.getDefaultToolkit().createImage(imageUrl); + Toolkit.getDefaultToolkit().sync(); + timestamp = System.currentTimeMillis(); + } + + public Image getImage() { + timestamp = System.currentTimeMillis(); + return tileImage; + } + + public void dropImage() { + tileImage = null; + // This should work in theory but doesn't seem to actually + // reduce the X server memory usage + //tileImage.flush(); + } + + public long access_time() { + return timestamp; + } + + public boolean equals(Object o) { + if (!(o instanceof FieldPapersTile)) + return false; + FieldPapersTile other = (FieldPapersTile) o; + return (this.x == other.x && this.y == other.y && this.z == other.z); + } +}