Index: trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java	(revision 8585)
+++ trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java	(revision 8586)
@@ -80,4 +80,6 @@
         int tileWidth;
         int tileHeight;
+        public int matrixWidth = -1;
+        public int matrixHeight = -1;
     }
 
@@ -99,4 +101,5 @@
         Map<String, TileMatrixSet> tileMatrixSetByCRS = new ConcurrentHashMap<>();
         public String baseUrl;
+        public String style;
     }
 
@@ -163,5 +166,4 @@
     private double crsScale;
     private TransferMode transferMode;
-    private String style = "";
 
     /**
@@ -248,4 +250,8 @@
             layer.name = getStringByXpath(layerNode, "Identifier");
             layer.baseUrl = getStringByXpath(layerNode, "ResourceURL[@resourceType='tile']/@template");
+            layer.style = getStringByXpath(layerNode, "Style[@isDefault='true']/Identifier");
+            if (layer.style == null) {
+                layer.style = "";
+            }
             NodeList tileMatrixSetLinks = getByXpath(layerNode, "TileMatrixSetLink");
             for (int tileMatrixId = 0; tileMatrixId < tileMatrixSetLinks.getLength(); tileMatrixId++) {
@@ -287,4 +293,6 @@
                 tileMatrix.tileHeight = Integer.parseInt(getStringByXpath(tileMatrixNode, "TileHeight"));
                 tileMatrix.tileWidth = Integer.parseInt(getStringByXpath(tileMatrixNode, "TileHeight"));
+                tileMatrix.matrixWidth = getOptionalIntegerByXpath(tileMatrixNode, "MatrixWidth");
+                tileMatrix.matrixHeight = getOptionalIntegerByXpath(tileMatrixNode, "MatrixHeight");
                 if (tileMatrix.tileHeight != tileMatrix.tileWidth) {
                     throw new AssertionError(tr("Only square tiles are supported. {0}x{1} returned by server for TileMatrix identifier {2}",
@@ -304,4 +312,12 @@
         }
         return crsIdentifier;
+    }
+
+    private int getOptionalIntegerByXpath(Node document, String xpathQuery) throws XPathExpressionException {
+        String ret = getStringByXpath(document, xpathQuery);
+        if (ret == null || "".equals(ret)) {
+            return -1;
+        }
+        return Integer.parseInt(ret);
     }
 
@@ -384,5 +400,5 @@
                 .replaceAll("\\{TileRow\\}", Integer.toString(tiley))
                 .replaceAll("\\{TileCol\\}", Integer.toString(tilex))
-                .replaceAll("\\{Style\\}", this.style);
+                .replaceAll("\\{Style\\}", this.currentLayer.style);
     }
 
@@ -595,6 +611,11 @@
             return 0;
         }
+
+        if (matrix.matrixHeight != -1) {
+            return matrix.matrixHeight;
+        }
+
         double scale = matrix.scaleDenominator * this.crsScale;
-        Bounds bounds = Main.getProjection().getWorldBoundsLatLon();
+        Bounds bounds = proj.getWorldBoundsLatLon();
         EastNorth min = proj.latlon2eastNorth(bounds.getMin());
         EastNorth max = proj.latlon2eastNorth(bounds.getMax());
@@ -607,6 +628,10 @@
             return 0;
         }
+        if (matrix.matrixWidth != -1) {
+            return matrix.matrixWidth;
+        }
+
         double scale = matrix.scaleDenominator * this.crsScale;
-        Bounds bounds = Main.getProjection().getWorldBoundsLatLon();
+        Bounds bounds = proj.getWorldBoundsLatLon();
         EastNorth min = proj.latlon2eastNorth(bounds.getMin());
         EastNorth max = proj.latlon2eastNorth(bounds.getMax());
Index: trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java	(revision 8585)
+++ trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java	(revision 8586)
@@ -5,4 +5,5 @@
 import java.util.Map;
 
+import org.openstreetmap.gui.jmapviewer.TileXY;
 import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
@@ -81,10 +82,12 @@
      */
     private double getTileToScreenRatio(int zoom) {
-         ICoordinate north = tileSource.tileXYToLatLon(0, 0, zoom);
-         ICoordinate south = tileSource.tileXYToLatLon(0, 1, zoom);
-
          MapView mv = Main.map.mapView;
          LatLon topLeft = mv.getLatLon(0, 0);
          LatLon botLeft = mv.getLatLon(0, tileSource.getTileSize());
+
+         TileXY topLeftTile = tileSource.latLonToTileXY(topLeft.toCoordinate(), zoom);
+
+         ICoordinate north = tileSource.tileXYToLatLon(topLeftTile.getXIndex(), topLeftTile.getYIndex(), zoom);
+         ICoordinate south = tileSource.tileXYToLatLon(topLeftTile.getXIndex(), topLeftTile.getYIndex() + 1, zoom);
 
          return Math.abs((north.getLat() - south.getLat()) / (topLeft.lat() - botLeft.lat()));
@@ -95,8 +98,8 @@
         if (!Main.isDisplayingMapView()) return 1;
 
-        for (int i = getMinZoomLvl(); i <= getMaxZoomLvl(); i++) {
+        for (int i = getMinZoomLvl() + 1; i <= getMaxZoomLvl(); i++) {
             double ret = getTileToScreenRatio(i);
             if (ret < 1) {
-                return i;
+                return i - 1;
             }
         }
