source: josm/trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java@ 8764

Last change on this file since 8764 was 8764, checked in by Don-vip, 9 years ago

fix Checkstyle issues

  • Property svn:eol-style set to native
File size: 27.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.imagery;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Dimension;
7import java.awt.GridBagLayout;
8import java.awt.Point;
9import java.io.ByteArrayInputStream;
10import java.io.IOException;
11import java.io.InputStream;
12import java.net.MalformedURLException;
13import java.net.URL;
14import java.util.ArrayList;
15import java.util.Collection;
16import java.util.Comparator;
17import java.util.HashSet;
18import java.util.Map;
19import java.util.Set;
20import java.util.SortedSet;
21import java.util.TreeSet;
22import java.util.concurrent.ConcurrentHashMap;
23import java.util.regex.Matcher;
24import java.util.regex.Pattern;
25
26import javax.swing.JPanel;
27import javax.swing.JTable;
28import javax.swing.ListSelectionModel;
29import javax.swing.table.AbstractTableModel;
30import javax.xml.XMLConstants;
31import javax.xml.namespace.QName;
32import javax.xml.parsers.DocumentBuilder;
33import javax.xml.parsers.DocumentBuilderFactory;
34import javax.xml.parsers.ParserConfigurationException;
35import javax.xml.xpath.XPath;
36import javax.xml.xpath.XPathConstants;
37import javax.xml.xpath.XPathExpression;
38import javax.xml.xpath.XPathExpressionException;
39import javax.xml.xpath.XPathFactory;
40
41import org.openstreetmap.gui.jmapviewer.Coordinate;
42import org.openstreetmap.gui.jmapviewer.Tile;
43import org.openstreetmap.gui.jmapviewer.TileXY;
44import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
45import org.openstreetmap.gui.jmapviewer.interfaces.TemplatedTileSource;
46import org.openstreetmap.gui.jmapviewer.tilesources.TMSTileSource;
47import org.openstreetmap.josm.Main;
48import org.openstreetmap.josm.data.coor.EastNorth;
49import org.openstreetmap.josm.data.coor.LatLon;
50import org.openstreetmap.josm.data.projection.Projection;
51import org.openstreetmap.josm.data.projection.Projections;
52import org.openstreetmap.josm.gui.ExtendedDialog;
53import org.openstreetmap.josm.io.CachedFile;
54import org.openstreetmap.josm.tools.CheckParameterUtil;
55import org.openstreetmap.josm.tools.GBC;
56import org.openstreetmap.josm.tools.Utils;
57import org.w3c.dom.Document;
58import org.w3c.dom.Node;
59import org.w3c.dom.NodeList;
60
61/**
62 * Tile Source handling WMS providers
63 *
64 * @author Wiktor Niesiobędzki
65 * @since 8526
66 */
67public class WMTSTileSource extends TMSTileSource implements TemplatedTileSource {
68 private static final String PATTERN_HEADER = "\\{header\\(([^,]+),([^}]+)\\)\\}";
69
70 private static final String URL_GET_ENCODING_PARAMS = "SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER={layer}&STYLE={Style}&"
71 + "FORMAT={format}&tileMatrixSet={TileMatrixSet}&tileMatrix={TileMatrix}&tileRow={TileRow}&tileCol={TileCol}";
72
73 private static final String[] ALL_PATTERNS = {
74 PATTERN_HEADER,
75 };
76
77 private static class TileMatrix {
78 private String identifier;
79 private double scaleDenominator;
80 private EastNorth topLeftCorner;
81 private int tileWidth;
82 private int tileHeight;
83 private int matrixWidth = -1;
84 private int matrixHeight = -1;
85 }
86
87 private static class TileMatrixSet {
88 SortedSet<TileMatrix> tileMatrix = new TreeSet<>(new Comparator<TileMatrix>() {
89 @Override
90 public int compare(TileMatrix o1, TileMatrix o2) {
91 // reverse the order, so it will be from greatest (lowest zoom level) to lowest value (highest zoom level)
92 return -1 * Double.compare(o1.scaleDenominator, o2.scaleDenominator);
93 }
94 }); // sorted by zoom level
95 private String crs;
96 private String identifier;
97 }
98
99 private static class Layer {
100 private String format;
101 private String name;
102 private TileMatrixSet tileMatrixSet;
103 private String baseUrl;
104 private String style;
105 }
106
107 private enum TransferMode {
108 KVP("KVP"),
109 REST("RESTful");
110
111 private final String typeString;
112
113 TransferMode(String urlString) {
114 this.typeString = urlString;
115 }
116
117 private String getTypeString() {
118 return typeString;
119 }
120
121 private static TransferMode fromString(String s) {
122 for (TransferMode type : TransferMode.values()) {
123 if (type.getTypeString().equals(s)) {
124 return type;
125 }
126 }
127 return null;
128 }
129 }
130
131 private static final class SelectLayerDialog extends ExtendedDialog {
132 private final Layer[] layers;
133 private final JTable list;
134
135 public SelectLayerDialog(Collection<Layer> layers) {
136 super(Main.parent, tr("Select WMTS layer"), new String[]{tr("Add layers"), tr("Cancel")});
137 this.layers = layers.toArray(new Layer[]{});
138 //getLayersTable(layers, Main.getProjection())
139 this.list = new JTable(
140 new AbstractTableModel() {
141 @Override
142 public Object getValueAt(int rowIndex, int columnIndex) {
143 switch (columnIndex) {
144 case 0:
145 return SelectLayerDialog.this.layers[rowIndex].name;
146 case 1:
147 return SelectLayerDialog.this.layers[rowIndex].tileMatrixSet.crs;
148 case 2:
149 return SelectLayerDialog.this.layers[rowIndex].tileMatrixSet.identifier;
150 default:
151 throw new IllegalArgumentException();
152 }
153 }
154
155 @Override
156 public int getRowCount() {
157 return SelectLayerDialog.this.layers.length;
158 }
159
160 @Override
161 public int getColumnCount() {
162 return 3;
163 }
164
165 @Override
166 public String getColumnName(int column) {
167 switch (column) {
168 case 0: return tr("Layer name");
169 case 1: return tr("Projection");
170 case 2: return tr("Matrix set identifier");
171 default:
172 throw new IllegalArgumentException();
173 }
174 }
175
176 @Override
177 public boolean isCellEditable(int row, int column) {
178 return false;
179 }
180 });
181 this.list.setPreferredSize(new Dimension(400, 400));
182 this.list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
183 this.list.setRowSelectionAllowed(true);
184 this.list.setColumnSelectionAllowed(false);
185 JPanel panel = new JPanel(new GridBagLayout());
186 panel.add(this.list, GBC.eol().fill());
187 setContent(panel);
188 }
189
190 public Layer getSelectedLayer() {
191 int index = list.getSelectedRow();
192 if (index < 0) {
193 return null; //nothing selected
194 }
195 return layers[index];
196 }
197 }
198
199 private final Map<String, String> headers = new ConcurrentHashMap<>();
200 private Collection<Layer> layers;
201 private Layer currentLayer;
202 private TileMatrixSet currentTileMatrixSet;
203 private double crsScale;
204 private TransferMode transferMode;
205
206 /**
207 * Creates a tile source based on imagery info
208 * @param info imagery info
209 * @throws IOException if any I/O error occurs
210 */
211 public WMTSTileSource(ImageryInfo info) throws IOException {
212 super(info);
213 this.baseUrl = normalizeCapabilitiesUrl(handleTemplate(info.getUrl()));
214 this.layers = getCapabilities();
215 if (this.layers.isEmpty())
216 throw new IllegalArgumentException(tr("No layers defined by getCapabilities document: {0}", info.getUrl()));
217
218 // Not needed ? initProjection();
219 }
220
221 private Layer userSelectLayer(Collection<Layer> layers) {
222 if (layers.size() == 1)
223 return layers.iterator().next();
224 Layer ret = null;
225
226 final SelectLayerDialog layerSelection = new SelectLayerDialog(layers);
227 if (layerSelection.showDialog().getValue() == 1) {
228 ret = layerSelection.getSelectedLayer();
229 // TODO: save layer information into ImageryInfo / ImageryPreferences?
230 }
231 if (ret == null) {
232 // user canceled operation or did not choose any layer
233 throw new IllegalArgumentException(tr("No layer selected"));
234 }
235 return ret;
236 }
237
238 private String handleTemplate(String url) {
239 Pattern pattern = Pattern.compile(PATTERN_HEADER);
240 StringBuffer output = new StringBuffer();
241 Matcher matcher = pattern.matcher(url);
242 while (matcher.find()) {
243 this.headers.put(matcher.group(1), matcher.group(2));
244 matcher.appendReplacement(output, "");
245 }
246 matcher.appendTail(output);
247 return output.toString();
248 }
249
250 private Collection<Layer> getCapabilities() throws IOException {
251 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
252 builderFactory.setValidating(false);
253 builderFactory.setNamespaceAware(false);
254 try {
255 builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
256 } catch (ParserConfigurationException e) {
257 //this should not happen
258 throw new IllegalArgumentException(e);
259 }
260 DocumentBuilder builder = null;
261 InputStream in = new CachedFile(baseUrl).
262 setHttpHeaders(headers).
263 setMaxAge(7 * CachedFile.DAYS).
264 setCachingStrategy(CachedFile.CachingStrategy.IfModifiedSince).
265 getInputStream();
266 try {
267 builder = builderFactory.newDocumentBuilder();
268 byte[] data = Utils.readBytesFromStream(in);
269 if (data == null || data.length == 0) {
270 throw new IllegalArgumentException("Could not read data from: " + baseUrl);
271 }
272 Document document = builder.parse(new ByteArrayInputStream(data));
273 Node getTileOperation = getByXpath(document,
274 "/Capabilities/OperationsMetadata/Operation[@name=\"GetTile\"]/DCP/HTTP/Get").item(0);
275 this.baseUrl = getStringByXpath(getTileOperation, "@href");
276 this.transferMode = TransferMode.fromString(getStringByXpath(getTileOperation,
277 "Constraint[@name=\"GetEncoding\"]/AllowedValues/Value"));
278 NodeList layersNodeList = getByXpath(document, "/Capabilities/Contents/Layer");
279 Map<String, TileMatrixSet> matrixSetById = parseMatrices(getByXpath(document, "/Capabilities/Contents/TileMatrixSet"));
280 return parseLayer(layersNodeList, matrixSetById);
281 } catch (Exception e) {
282 throw new IllegalArgumentException(e);
283 }
284 }
285
286 private static String normalizeCapabilitiesUrl(String url) throws MalformedURLException {
287 URL inUrl = new URL(url);
288 URL ret = new URL(inUrl.getProtocol(), inUrl.getHost(), inUrl.getPort(), inUrl.getFile());
289 return ret.toExternalForm();
290 }
291
292 private Collection<Layer> parseLayer(NodeList nodeList, Map<String, TileMatrixSet> matrixSetById) throws XPathExpressionException {
293 Collection<Layer> ret = new ArrayList<>();
294 for (int layerId = 0; layerId < nodeList.getLength(); layerId++) {
295 Node layerNode = nodeList.item(layerId);
296 NodeList tileMatrixSetLinks = getByXpath(layerNode, "TileMatrixSetLink");
297
298 // we add an layer for all matrix sets to allow user to choose, with which tileset he wants to work
299 for (int tileMatrixId = 0; tileMatrixId < tileMatrixSetLinks.getLength(); tileMatrixId++) {
300 Layer layer = new Layer();
301 layer.format = getStringByXpath(layerNode, "Format");
302 layer.name = getStringByXpath(layerNode, "Identifier");
303 layer.baseUrl = getStringByXpath(layerNode, "ResourceURL[@resourceType='tile']/@template");
304 layer.style = getStringByXpath(layerNode, "Style[@isDefault='true']/Identifier");
305 if (layer.style == null) {
306 layer.style = "";
307 }
308 Node tileMatrixLink = tileMatrixSetLinks.item(tileMatrixId);
309 TileMatrixSet tms = matrixSetById.get(getStringByXpath(tileMatrixLink, "TileMatrixSet"));
310 layer.tileMatrixSet = tms;
311 ret.add(layer);
312 }
313 }
314 return ret;
315
316 }
317
318 private Map<String, TileMatrixSet> parseMatrices(NodeList nodeList) throws XPathExpressionException {
319 Map<String, TileMatrixSet> ret = new ConcurrentHashMap<>();
320 for (int matrixSetId = 0; matrixSetId < nodeList.getLength(); matrixSetId++) {
321 Node matrixSetNode = nodeList.item(matrixSetId);
322 TileMatrixSet matrixSet = new TileMatrixSet();
323 matrixSet.identifier = getStringByXpath(matrixSetNode, "Identifier");
324 matrixSet.crs = crsToCode(getStringByXpath(matrixSetNode, "SupportedCRS"));
325 NodeList tileMatrixList = getByXpath(matrixSetNode, "TileMatrix");
326 Projection matrixProj = Projections.getProjectionByCode(matrixSet.crs);
327 if (matrixProj == null) {
328 // use current projection if none found. Maybe user is using custom string
329 matrixProj = Main.getProjection();
330 }
331 for (int matrixId = 0; matrixId < tileMatrixList.getLength(); matrixId++) {
332 Node tileMatrixNode = tileMatrixList.item(matrixId);
333 TileMatrix tileMatrix = new TileMatrix();
334 tileMatrix.identifier = getStringByXpath(tileMatrixNode, "Identifier");
335 tileMatrix.scaleDenominator = Double.parseDouble(getStringByXpath(tileMatrixNode, "ScaleDenominator"));
336 String[] topLeftCorner = getStringByXpath(tileMatrixNode, "TopLeftCorner").split(" ");
337
338 if (matrixProj.switchXY()) {
339 tileMatrix.topLeftCorner = new EastNorth(Double.parseDouble(topLeftCorner[1]), Double.parseDouble(topLeftCorner[0]));
340 } else {
341 tileMatrix.topLeftCorner = new EastNorth(Double.parseDouble(topLeftCorner[0]), Double.parseDouble(topLeftCorner[1]));
342 }
343 tileMatrix.tileHeight = Integer.parseInt(getStringByXpath(tileMatrixNode, "TileHeight"));
344 tileMatrix.tileWidth = Integer.parseInt(getStringByXpath(tileMatrixNode, "TileHeight"));
345 tileMatrix.matrixWidth = getOptionalIntegerByXpath(tileMatrixNode, "MatrixWidth");
346 tileMatrix.matrixHeight = getOptionalIntegerByXpath(tileMatrixNode, "MatrixHeight");
347 if (tileMatrix.tileHeight != tileMatrix.tileWidth) {
348 throw new AssertionError(tr("Only square tiles are supported. {0}x{1} returned by server for TileMatrix identifier {2}",
349 tileMatrix.tileHeight, tileMatrix.tileWidth, tileMatrix.identifier));
350 }
351
352 matrixSet.tileMatrix.add(tileMatrix);
353 }
354 ret.put(matrixSet.identifier, matrixSet);
355 }
356 return ret;
357 }
358
359 private static String crsToCode(String crsIdentifier) {
360 if (crsIdentifier.startsWith("urn:ogc:def:crs:")) {
361 return crsIdentifier.replaceFirst("urn:ogc:def:crs:([^:]*):.*:(.*)$", "$1:$2");
362 }
363 return crsIdentifier;
364 }
365
366 private static int getOptionalIntegerByXpath(Node document, String xpathQuery) throws XPathExpressionException {
367 String ret = getStringByXpath(document, xpathQuery);
368 if (ret == null || "".equals(ret)) {
369 return -1;
370 }
371 return Integer.parseInt(ret);
372 }
373
374 private static String getStringByXpath(Node document, String xpathQuery) throws XPathExpressionException {
375 return (String) getByXpath(document, xpathQuery, XPathConstants.STRING);
376 }
377
378 private static NodeList getByXpath(Node document, String xpathQuery) throws XPathExpressionException {
379 return (NodeList) getByXpath(document, xpathQuery, XPathConstants.NODESET);
380 }
381
382 private static Object getByXpath(Node document, String xpathQuery, QName returnType) throws XPathExpressionException {
383 XPath xpath = XPathFactory.newInstance().newXPath();
384 XPathExpression expr = xpath.compile(xpathQuery);
385 return expr.evaluate(document, returnType);
386 }
387
388 /**
389 * Initializes projection for this TileSource with current projection
390 */
391 protected void initProjection() {
392 initProjection(Main.getProjection());
393 }
394
395 /**
396 * Initializes projection for this TileSource with projection
397 * @param proj projection to be used by this TileSource
398 */
399 public void initProjection(Projection proj) {
400 String layerName = null;
401 if (currentLayer != null) {
402 layerName = currentLayer.name;
403 }
404 Collection<Layer> candidates = getLayers(layerName, proj.toCode());
405 if (!candidates.isEmpty()) {
406 Layer newLayer = userSelectLayer(candidates);
407 if (newLayer != null) {
408 this.currentTileMatrixSet = newLayer.tileMatrixSet;
409 this.currentLayer = newLayer;
410 }
411 }
412
413 this.crsScale = getTileSize() * 0.28e-03 / proj.getMetersPerUnit();
414 }
415
416 private Collection<Layer> getLayers(String name, String projectionCode) {
417 Collection<Layer> ret = new ArrayList<>();
418 for (Layer layer: this.layers) {
419 if ((name == null || name.equals(layer.name)) && (projectionCode == null || projectionCode.equals(layer.tileMatrixSet.crs))) {
420 ret.add(layer);
421 }
422 }
423 return ret;
424 }
425
426 @Override
427 public int getDefaultTileSize() {
428 return getTileSize();
429 }
430
431 // FIXME: remove in September 2015, when ImageryPreferenceEntry.tileSize will be initialized to -1 instead to 256
432 // need to leave it as it is to keep compatiblity between tested and latest JOSM versions
433 @Override
434 public int getTileSize() {
435 TileMatrix matrix = getTileMatrix(1);
436 if (matrix == null) {
437 return 1;
438 }
439 return matrix.tileHeight;
440 }
441
442 @Override
443 public String getTileUrl(int zoom, int tilex, int tiley) {
444 String url;
445 if (currentLayer == null) {
446 return "";
447 }
448
449 switch (transferMode) {
450 case KVP:
451 url = baseUrl + URL_GET_ENCODING_PARAMS;
452 break;
453 case REST:
454 url = currentLayer.baseUrl;
455 break;
456 default:
457 url = "";
458 break;
459 }
460
461 TileMatrix tileMatrix = getTileMatrix(zoom);
462
463 if (tileMatrix == null) {
464 return ""; // no matrix, probably unsupported CRS selected.
465 }
466
467 return url.replaceAll("\\{layer\\}", this.currentLayer.name)
468 .replaceAll("\\{format\\}", this.currentLayer.format)
469 .replaceAll("\\{TileMatrixSet\\}", this.currentTileMatrixSet.identifier)
470 .replaceAll("\\{TileMatrix\\}", tileMatrix.identifier)
471 .replaceAll("\\{TileRow\\}", Integer.toString(tiley))
472 .replaceAll("\\{TileCol\\}", Integer.toString(tilex))
473 .replaceAll("\\{Style\\}", this.currentLayer.style);
474 }
475
476 /**
477 *
478 * @param zoom zoom level
479 * @return TileMatrix that's working on this zoom level
480 */
481 private TileMatrix getTileMatrix(int zoom) {
482 if (zoom > getMaxZoom()) {
483 return null;
484 }
485 if (zoom < 1) {
486 return null;
487 }
488 return this.currentTileMatrixSet.tileMatrix.toArray(new TileMatrix[]{})[zoom - 1];
489 }
490
491 @Override
492 public double getDistance(double lat1, double lon1, double lat2, double lon2) {
493 throw new UnsupportedOperationException("Not implemented");
494 }
495
496 @Override
497 public int lonToX(double lon, int zoom) {
498 throw new UnsupportedOperationException("Not implemented");
499 }
500
501 @Override
502 public int latToY(double lat, int zoom) {
503 throw new UnsupportedOperationException("Not implemented");
504 }
505
506 @Override
507 public double XToLon(int x, int zoom) {
508 throw new UnsupportedOperationException("Not implemented");
509 }
510
511 @Override
512 public double YToLat(int y, int zoom) {
513 throw new UnsupportedOperationException("Not implemented");
514 }
515
516 @Override
517 public double latToTileY(double lat, int zoom) {
518 throw new UnsupportedOperationException("Not implemented");
519 }
520
521 @Override
522 public ICoordinate tileXYToLatLon(Tile tile) {
523 return tileXYToLatLon(tile.getXtile(), tile.getYtile(), tile.getZoom());
524 }
525
526 @Override
527 public ICoordinate tileXYToLatLon(TileXY xy, int zoom) {
528 return tileXYToLatLon(xy.getXIndex(), xy.getYIndex(), zoom);
529 }
530
531 @Override
532 public ICoordinate tileXYToLatLon(int x, int y, int zoom) {
533 TileMatrix matrix = getTileMatrix(zoom);
534 if (matrix == null) {
535 return Main.getProjection().getWorldBoundsLatLon().getCenter().toCoordinate();
536 }
537 double scale = matrix.scaleDenominator * this.crsScale;
538 EastNorth ret = new EastNorth(matrix.topLeftCorner.east() + x * scale, matrix.topLeftCorner.north() - y * scale);
539 return Main.getProjection().eastNorth2latlon(ret).toCoordinate();
540 }
541
542 @Override
543 public TileXY latLonToTileXY(double lat, double lon, int zoom) {
544 TileMatrix matrix = getTileMatrix(zoom);
545 if (matrix == null) {
546 return new TileXY(0, 0);
547 }
548
549 Projection proj = Main.getProjection();
550 EastNorth enPoint = proj.latlon2eastNorth(new LatLon(lat, lon));
551 double scale = matrix.scaleDenominator * this.crsScale;
552 return new TileXY(
553 (enPoint.east() - matrix.topLeftCorner.east()) / scale,
554 (matrix.topLeftCorner.north() - enPoint.north()) / scale
555 );
556 }
557
558 @Override
559 public TileXY latLonToTileXY(ICoordinate point, int zoom) {
560 return latLonToTileXY(point.getLat(), point.getLon(), zoom);
561 }
562
563 @Override
564 public int getTileXMax(int zoom) {
565 return getTileXMax(zoom, Main.getProjection());
566 }
567
568 @Override
569 public int getTileXMin(int zoom) {
570 return 0;
571 }
572
573 @Override
574 public int getTileYMax(int zoom) {
575 return getTileYMax(zoom, Main.getProjection());
576 }
577
578 @Override
579 public int getTileYMin(int zoom) {
580 return 0;
581 }
582
583 @Override
584 public Point latLonToXY(double lat, double lon, int zoom) {
585 TileMatrix matrix = getTileMatrix(zoom);
586 if (matrix == null) {
587 return new Point(0, 0);
588 }
589 double scale = matrix.scaleDenominator * this.crsScale;
590 EastNorth point = Main.getProjection().latlon2eastNorth(new LatLon(lat, lon));
591 return new Point(
592 (int) Math.round((point.east() - matrix.topLeftCorner.east()) / scale),
593 (int) Math.round((matrix.topLeftCorner.north() - point.north()) / scale)
594 );
595 }
596
597 @Override
598 public Point latLonToXY(ICoordinate point, int zoom) {
599 return latLonToXY(point.getLat(), point.getLon(), zoom);
600 }
601
602 @Override
603 public Coordinate xyToLatLon(Point point, int zoom) {
604 return xyToLatLon(point.x, point.y, zoom);
605 }
606
607 @Override
608 public Coordinate xyToLatLon(int x, int y, int zoom) {
609 TileMatrix matrix = getTileMatrix(zoom);
610 if (matrix == null) {
611 return new Coordinate(0, 0);
612 }
613 double scale = matrix.scaleDenominator * this.crsScale;
614 Projection proj = Main.getProjection();
615 EastNorth ret = new EastNorth(
616 matrix.topLeftCorner.east() + x * scale,
617 matrix.topLeftCorner.north() - y * scale
618 );
619 LatLon ll = proj.eastNorth2latlon(ret);
620 return new Coordinate(ll.lat(), ll.lon());
621 }
622
623 @Override
624 public double lonToTileX(double lon, int zoom) {
625 throw new UnsupportedOperationException("Not implemented");
626 }
627
628 @Override
629 public double tileXToLon(int x, int zoom) {
630 throw new UnsupportedOperationException("Not implemented");
631 }
632
633 @Override
634 public double tileYToLat(int y, int zoom) {
635 throw new UnsupportedOperationException("Not implemented");
636 }
637
638 @Override
639 public Map<String, String> getHeaders() {
640 return headers;
641 }
642
643 @Override
644 public int getMaxZoom() {
645 if (this.currentTileMatrixSet != null) {
646 return this.currentTileMatrixSet.tileMatrix.size();
647 }
648 return 0;
649 }
650
651 @Override
652 public String getTileId(int zoom, int tilex, int tiley) {
653 return getTileUrl(zoom, tilex, tiley);
654 }
655
656
657 /**
658 * Checks if url is acceptable by this Tile Source
659 * @param url URL to check
660 */
661 public static void checkUrl(String url) {
662 CheckParameterUtil.ensureParameterNotNull(url, "url");
663 Matcher m = Pattern.compile("\\{[^}]*\\}").matcher(url);
664 while (m.find()) {
665 boolean isSupportedPattern = false;
666 for (String pattern : ALL_PATTERNS) {
667 if (m.group().matches(pattern)) {
668 isSupportedPattern = true;
669 break;
670 }
671 }
672 if (!isSupportedPattern) {
673 throw new IllegalArgumentException(
674 tr("{0} is not a valid WMS argument. Please check this server URL:\n{1}", m.group(), url));
675 }
676 }
677 }
678
679 /**
680 * @return set of projection codes that this TileSource supports
681 */
682 public Set<String> getSupportedProjections() {
683 Set<String> ret = new HashSet<>();
684 if (currentLayer == null) {
685 for (Layer layer: this.layers) {
686 ret.add(layer.tileMatrixSet.crs);
687 }
688 } else {
689 for (Layer layer: this.layers) {
690 if (currentLayer.name.equals(layer.name)) {
691 ret.add(layer.tileMatrixSet.crs);
692 }
693 }
694 }
695 return ret;
696 }
697
698 private int getTileYMax(int zoom, Projection proj) {
699 TileMatrix matrix = getTileMatrix(zoom);
700 if (matrix == null) {
701 return 0;
702 }
703
704 if (matrix.matrixHeight != -1) {
705 return matrix.matrixHeight;
706 }
707
708 double scale = matrix.scaleDenominator * this.crsScale;
709 EastNorth min = matrix.topLeftCorner;
710 EastNorth max = proj.latlon2eastNorth(proj.getWorldBoundsLatLon().getMax());
711 return (int) Math.ceil(Math.abs(max.north() - min.north()) / scale);
712 }
713
714 private int getTileXMax(int zoom, Projection proj) {
715 TileMatrix matrix = getTileMatrix(zoom);
716 if (matrix == null) {
717 return 0;
718 }
719 if (matrix.matrixWidth != -1) {
720 return matrix.matrixWidth;
721 }
722
723 double scale = matrix.scaleDenominator * this.crsScale;
724 EastNorth min = matrix.topLeftCorner;
725 EastNorth max = proj.latlon2eastNorth(proj.getWorldBoundsLatLon().getMax());
726 return (int) Math.ceil(Math.abs(max.east() - min.east()) / scale);
727 }
728}
Note: See TracBrowser for help on using the repository browser.