Index: src/org/openstreetmap/josm/data/imagery/TemplatedWMSTileSource.java
===================================================================
--- src/org/openstreetmap/josm/data/imagery/TemplatedWMSTileSource.java	(revision 9167)
+++ src/org/openstreetmap/josm/data/imagery/TemplatedWMSTileSource.java	(working copy)
@@ -21,6 +21,7 @@
 import org.openstreetmap.gui.jmapviewer.interfaces.TemplatedTileSource;
 import org.openstreetmap.gui.jmapviewer.tilesources.TMSTileSource;
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.ProjectionBounds;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
@@ -37,7 +38,9 @@
 public class TemplatedWMSTileSource extends TMSTileSource implements TemplatedTileSource {
     private final Map<String, String> headers = new ConcurrentHashMap<>();
     private final Set<String> serverProjections;
-    private EastNorth topLeftCorner;
+    private EastNorth anchorPosition;
+    private int[] tileXMin;
+    private int[] tileYMin;
     private int[] tileXMax;
     private int[] tileYMax;
     private double[] degreesPerTile;
@@ -88,20 +91,28 @@
         initProjection(Main.getProjection());
     }
 
+    private void initAnchorPosition(Projection proj) {
+        Bounds worldBounds = proj.getWorldBoundsLatLon();
+        EastNorth min = proj.latlon2eastNorth(worldBounds.getMin());
+        EastNorth max = proj.latlon2eastNorth(worldBounds.getMax());
+        this.anchorPosition = new EastNorth(min.east(), max.north());
+    }
+
     /**
      * Initializes class with projection in JOSM. This call is needed every time projection changes.
      * @param proj new projection that shall be used for computations
      */
     public void initProjection(Projection proj) {
+        initAnchorPosition(proj);
         ProjectionBounds worldBounds = proj.getWorldBoundsBoxEastNorth();
-        EastNorth min = worldBounds.getMin();
-        EastNorth max = worldBounds.getMax();
-        this.topLeftCorner = new EastNorth(min.east(), max.north());
 
+        EastNorth topLeft = new EastNorth(worldBounds.getMin().east(), worldBounds.getMax().north());
         EastNorth bottomRight = new EastNorth(worldBounds.getMax().east(), worldBounds.getMin().north());
 
         // use 256 as "tile size" to keep the scale in line with default tiles in Mercator projection
         double crsScale = 256 * 0.28e-03 / proj.getMetersPerUnit();
+        tileXMin = new int[getMaxZoom() + 1];
+        tileYMin = new int[getMaxZoom() + 1];
         tileXMax = new int[getMaxZoom() + 1];
         tileYMax = new int[getMaxZoom() + 1];
         degreesPerTile = new double[getMaxZoom() + 1];
@@ -110,9 +121,13 @@
             // use well known scale set "GoogleCompatibile" from OGC WMTS spec to calculate number of tiles per zoom level
             // this makes the zoom levels "glued" to standard TMS zoom levels
             degreesPerTile[zoom] = (SCALE_DENOMINATOR_ZOOM_LEVEL_1 / Math.pow(2, zoom - 1)) * crsScale;
+            TileXY minTileIndex = eastNorthToTileXY(topLeft, zoom);
+            tileXMin[zoom] = minTileIndex.getXIndex();
+            tileYMin[zoom] = minTileIndex.getYIndex();
             TileXY maxTileIndex = eastNorthToTileXY(bottomRight, zoom);
             tileXMax[zoom] = maxTileIndex.getXIndex();
             tileYMax[zoom] = maxTileIndex.getYIndex();
+            //System.err.println("z:"+zoom+" xmin="+tileXMin[zoom]+" xmax="+tileXMax[zoom]+" ymin="+tileYMin[zoom]+" ymax="+tileYMax[zoom]);
         }
     }
 
@@ -246,8 +261,8 @@
     private TileXY eastNorthToTileXY(EastNorth enPoint, int zoom) {
         double scale = getDegreesPerTile(zoom);
         return new TileXY(
-                (enPoint.east() - topLeftCorner.east()) / scale,
-                (topLeftCorner.north() - enPoint.north()) / scale
+                (enPoint.east() - anchorPosition.east()) / scale,
+                (anchorPosition.north() - enPoint.north()) / scale
                 );
     }
 
@@ -263,7 +278,7 @@
 
     @Override
     public int getTileXMin(int zoom) {
-        return 0;
+        return tileXMin[zoom];
     }
 
     @Override
@@ -273,7 +288,7 @@
 
     @Override
     public int getTileYMin(int zoom) {
-        return 0;
+        return tileYMin[zoom];
     }
 
     @Override
@@ -281,8 +296,8 @@
         double scale = getDegreesPerTile(zoom) / getTileSize();
         EastNorth point = Main.getProjection().latlon2eastNorth(new LatLon(lat, lon));
         return new Point(
-                    (int) Math.round((point.east() - topLeftCorner.east())   / scale),
-                    (int) Math.round((topLeftCorner.north() - point.north()) / scale)
+                    (int) Math.round((point.east() - anchorPosition.east())   / scale),
+                    (int) Math.round((anchorPosition.north() - point.north()) / scale)
                 );
     }
 
@@ -301,8 +316,8 @@
         double scale = getDegreesPerTile(zoom) / getTileSize();
         Projection proj = Main.getProjection();
         EastNorth ret = new EastNorth(
-                topLeftCorner.east() + x * scale,
-                topLeftCorner.north() - y * scale
+                anchorPosition.east() + x * scale,
+                anchorPosition.north() - y * scale
                 );
         return proj.eastNorth2latlon(ret).toCoordinate();
     }
@@ -349,8 +364,8 @@
     protected EastNorth getTileEastNorth(int x, int y, int z) {
         double scale = getDegreesPerTile(z);
         return new EastNorth(
-                        topLeftCorner.east() + x * scale,
-                        topLeftCorner.north() - y * scale
+                        anchorPosition.east() + x * scale,
+                        anchorPosition.north() - y * scale
                         );
     }
 
