Statistics
| Revision:

gvsig-raster / org.gvsig.raster.wmts / trunk / org.gvsig.raster.wmts / org.gvsig.raster.wmts.io / src / main / java / org / gvsig / raster / wmts / io / WMTSProvider.java @ 4272

History | View | Annotate | Download (48.8 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22
package org.gvsig.raster.wmts.io;
23

    
24
import java.awt.Image;
25
import java.awt.Rectangle;
26
import java.awt.geom.AffineTransform;
27
import java.awt.geom.NoninvertibleTransformException;
28
import java.awt.geom.Point2D;
29
import java.awt.geom.Rectangle2D;
30
import java.io.File;
31
import java.io.IOException;
32
import java.net.ConnectException;
33
import java.net.MalformedURLException;
34
import java.net.URI;
35
import java.net.URISyntaxException;
36
import java.net.URL;
37
import java.util.List;
38

    
39
import javax.swing.ImageIcon;
40

    
41
import org.gvsig.compat.net.ICancellable;
42
import org.gvsig.fmap.dal.DALLocator;
43
import org.gvsig.fmap.dal.DataStore;
44
import org.gvsig.fmap.dal.DataStoreParameters;
45
import org.gvsig.fmap.dal.coverage.RasterLocator;
46
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
47
import org.gvsig.fmap.dal.coverage.datastruct.BandList;
48
import org.gvsig.fmap.dal.coverage.datastruct.DatasetBand;
49
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
50
import org.gvsig.fmap.dal.coverage.datastruct.NoData;
51
import org.gvsig.fmap.dal.coverage.exception.BandAccessException;
52
import org.gvsig.fmap.dal.coverage.exception.BandNotFoundInListException;
53
import org.gvsig.fmap.dal.coverage.exception.FileNotOpenException;
54
import org.gvsig.fmap.dal.coverage.exception.InfoByPointException;
55
import org.gvsig.fmap.dal.coverage.exception.InvalidSetViewException;
56
import org.gvsig.fmap.dal.coverage.exception.InvalidSourceException;
57
import org.gvsig.fmap.dal.coverage.exception.NotSupportedExtensionException;
58
import org.gvsig.fmap.dal.coverage.exception.ProcessInterruptedException;
59
import org.gvsig.fmap.dal.coverage.exception.QueryException;
60
import org.gvsig.fmap.dal.coverage.exception.RasterDriverException;
61
import org.gvsig.fmap.dal.coverage.exception.RemoteServiceException;
62
import org.gvsig.fmap.dal.coverage.store.RasterDataStore;
63
import org.gvsig.fmap.dal.coverage.store.RasterQuery;
64
import org.gvsig.fmap.dal.coverage.store.props.ColorInterpretation;
65
import org.gvsig.fmap.dal.coverage.store.props.HistogramComputer;
66
import org.gvsig.fmap.dal.coverage.store.props.Transparency;
67
import org.gvsig.fmap.dal.coverage.util.MathUtils;
68
import org.gvsig.fmap.dal.exception.CloseException;
69
import org.gvsig.fmap.dal.exception.InitializeException;
70
import org.gvsig.fmap.dal.exception.OpenException;
71
import org.gvsig.fmap.dal.exception.ProviderNotRegisteredException;
72
import org.gvsig.fmap.dal.spi.DataManagerProviderServices;
73
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
74
import org.gvsig.metadata.MetadataLocator;
75
import org.gvsig.raster.cache.tile.TileCacheLocator;
76
import org.gvsig.raster.cache.tile.TileCacheManager;
77
import org.gvsig.raster.cache.tile.exception.TileGettingException;
78
import org.gvsig.raster.cache.tile.provider.CacheStruct;
79
import org.gvsig.raster.cache.tile.provider.TileListener;
80
import org.gvsig.raster.cache.tile.provider.TileServer;
81
import org.gvsig.raster.impl.buffer.SpiRasterQuery;
82
import org.gvsig.raster.impl.datastruct.BandListImpl;
83
import org.gvsig.raster.impl.datastruct.DatasetBandImpl;
84
import org.gvsig.raster.impl.datastruct.ExtentImpl;
85
import org.gvsig.raster.impl.provider.AbstractRasterProvider;
86
import org.gvsig.raster.impl.provider.MemoryTileMatrixBuffer;
87
import org.gvsig.raster.impl.provider.RasterProvider;
88
import org.gvsig.raster.impl.provider.RemoteRasterProvider;
89
import org.gvsig.raster.impl.provider.TiledRasterProvider;
90
import org.gvsig.raster.impl.store.DefaultRasterStore;
91
import org.gvsig.raster.impl.store.DefaultStoreFactory;
92
import org.gvsig.raster.impl.store.properties.DataStoreColorInterpretation;
93
import org.gvsig.raster.impl.store.properties.DataStoreTransparency;
94
import org.gvsig.raster.impl.store.properties.RemoteStoreHistogram;
95
import org.gvsig.raster.util.DefaultProviderServices;
96
import org.gvsig.raster.wmts.io.downloader.WMTSTileServer;
97
import org.gvsig.raster.wmts.ogc.WMTSClient;
98
import org.gvsig.raster.wmts.ogc.WMTSOGCLocator;
99
import org.gvsig.raster.wmts.ogc.WMTSStatus;
100
import org.gvsig.raster.wmts.ogc.exception.DownloadException;
101
import org.gvsig.raster.wmts.ogc.exception.ServerErrorException;
102
import org.gvsig.raster.wmts.ogc.exception.WMTSException;
103
import org.gvsig.raster.wmts.ogc.struct.WMTSLayer;
104
import org.gvsig.raster.wmts.ogc.struct.WMTSTile;
105
import org.gvsig.raster.wmts.ogc.struct.WMTSTileMatrix;
106
import org.gvsig.raster.wmts.ogc.struct.WMTSTileMatrixLimits;
107
import org.gvsig.raster.wmts.ogc.struct.WMTSTileMatrixSet;
108
import org.gvsig.raster.wmts.ogc.struct.WMTSTileMatrixSetLink;
109
import org.gvsig.tools.ToolsLocator;
110

    
111
import org.apache.commons.io.FilenameUtils;
112
import org.cresques.cts.IProjection;
113
import org.slf4j.Logger;
114
import org.slf4j.LoggerFactory;
115
/**
116
 * Provider for WMTS service
117
 *
118
 * @author Nacho Brodin (nachobrodin@gmail.com)
119
 */
120
public class WMTSProvider extends AbstractRasterProvider implements RemoteRasterProvider, TiledRasterProvider {
121
        public static String                NAME                     = "Wmts Store";
122
        public static String                DESCRIPTION              = "Wmts Raster file";
123
        public static final String          METADATA_DEFINITION_NAME = "WmtsStore";
124
        private static Logger               logger                   = LoggerFactory.getLogger(WMTSProvider.class);
125
        public static boolean               TILED                    = true;
126

    
127
        //Los tiles se piden de forma secuencial y sin lanzar threads para ello (+Lento)
128
        public static int                   SEQUENTIAL               = 0;
129
        //Los tiles se piden en threads y hay un thread manager para gestionar que no se pidan m?s de cierto n?mero
130
        public static int                   LIMITED_THREADS          = 1;
131
        //Los tiles se piden en threads y se lanzan tantos threads como tiles haya
132
        public static int                   UNLIMITED_THREADS        = 2;
133
        private int                         requestType              = LIMITED_THREADS;
134

    
135
        private static final double         MTS_X_GRADO              = 111319.490793274;
136

    
137
        private Extent                      viewRequest              = null;
138
        private WMTSClient                  ogcClient                = null;
139
        //private static Hashtable<URL, WMTSConnector>
140
        //                                    drivers                  = new Hashtable<URL, WMTSConnector> ();
141
        private boolean                     open                     = false;
142
        private File                        lastRequest              = null;
143
        private DataStoreTransparency       lastFileTransparency     = null;
144
        private int                         lastWidthRequest         = 0;
145
        private int                         lastHeightRequest        = 0;
146
        private WMTSStatus                  lastStatus               = null;
147
        private boolean                     gridSubsets              = true;
148
        private Extent[]                    extentByLevel            = null; //Only for layers without gridSubsets
149
        private Extent                      bbox                     = null;
150
        private MathUtils                   math                     = RasterLocator.getManager().getMathUtils();
151

    
152
        /**
153
         * This thread manages the number of tiles that have been thrown.
154
         * This number is controlled by the NTHREADS_QUEUE variable.
155
         *
156
         * @author Nacho Brodin (nachobrodin@gmail.com)
157
         */
158
        public class RequestThreadManager extends Thread {
159
                private TilePipe               pipe           = null;
160
                private List<WMTSTile>         tiles          = null;
161
                private WMTSStatus             status         = null;
162

    
163
                public RequestThreadManager(TilePipe pipe, List<WMTSTile> tiles, WMTSStatus status) {
164
                        this.pipe = pipe;
165
                        this.tiles = tiles;
166
                        this.status = status;
167
                }
168

    
169
                public void run() {
170
                        for (int i = 0; i < tiles.size(); i++) {
171
                                WMTSTile tile = tiles.get(i);
172
                                WMTSStatus statusCopy = status.cloneStatus();
173
                                statusCopy.setTileRow(tile.getRow());
174
                                statusCopy.setTileCol(tile.getCol());
175
                                if (pipe.getSize() > TilePipe.NTHREADS_QUEUE) {
176
                                        try {
177
                                                synchronized (this) {
178
                                                        wait();
179
                                                }
180
                                        } catch( InterruptedException e ) {
181
                                        }
182
                                }
183
                                new RequestTileLauncher(pipe, statusCopy, tile).start();
184
                        }
185
                }
186
        }
187

    
188
        /**
189
         * Thread to download a tile
190
         * @author Nacho Brodin (nachobrodin@gmail.com)
191
         */
192
        class RequestTileLauncher extends Thread {
193
                private TilePipe      pipe    = null;
194
                private WMTSStatus    status  = null;
195
                private WMTSTile      tile    = null;
196

    
197
                public RequestTileLauncher(TilePipe pipe, WMTSStatus status, WMTSTile tile) {
198
                        this.pipe = pipe;
199
                        this.status = status;
200
                        this.tile = tile;
201
                }
202

    
203
                public void run() {
204
                        try {
205
                                //File file = getConnector().getTile(status, null);
206
                                URL url = getOGCClient().getTileURL(status);
207
                                tile.setFile(getOGCClient().downloadFile(url, null));
208
                                pipe.setTile(tile);
209
                        } catch (DownloadException e) {
210
                                logger.info("Error downloading files", e);
211
                        } catch (MalformedURLException e) {
212
                                logger.info("Malformed URL", e);
213
                        } catch (WMTSException e) {
214
                                logger.info("", e);
215
                        }
216
                }
217
        }
218

    
219
        /**
220
         * Point information
221
         * @author Nacho Brodin (nachobrodin@gmail.com)
222
         */
223
        public class PointInfo {
224
                public Point2D worldCoord;
225
                public Point2D tile;
226
                public Point2D pixelInTile;
227
                public int     level;
228

    
229
                public PointInfo(Point2D worldCoord) {
230
                        this.worldCoord = worldCoord;
231
                }
232
        }
233

    
234
        public static void register() {
235
                DataManagerProviderServices dataman = (DataManagerProviderServices) DALLocator.getDataManager();
236
                if (dataman != null && !dataman.getStoreProviders().contains(NAME)) {
237
                        dataman.registerStoreProvider(NAME,
238
                                        WMTSProvider.class, WMTSDataParametersImpl.class);
239
                }
240

    
241
                if (!dataman.getExplorerProviders().contains(WMTSServerExplorer.NAME)) {
242
                        dataman.registerExplorerProvider(WMTSServerExplorer.NAME, WMTSServerExplorer.class, WMTSServerExplorerParameters.class);
243
                }
244
                dataman.registerStoreFactory(NAME, DefaultStoreFactory.class);
245
        }
246

    
247
        public WMTSProvider() throws NotSupportedExtensionException {
248
                super();
249
        }
250

    
251
        /**
252
         * Constructor. Abre el dataset.
253
         * @param proj Proyecci?n
254
         * @param fName Nombre del fichero
255
         * @throws NotSupportedExtensionException
256
         * @throws OpenException
257
     * @deprecated use {@link #WMTSProvider(URI)}, this constructor will be removed in gvSIG 2.5
258
         */
259
        public WMTSProvider(String params) throws NotSupportedExtensionException, OpenException {
260
                super(params);
261
        logger.info("Deprecated use of WMTSProvider constructor");
262
                if(params instanceof String) {
263
                        WMTSDataParameters p = new WMTSDataParametersImpl();
264
            try {
265
                p.setURI(new URI((String) params));
266
            } catch (URISyntaxException e) {
267
                throw new OpenException("Can't create URI from" + (String) params, e);
268
            }
269
                        super.init(p, null, ToolsLocator.getDynObjectManager()
270
                                        .createDynObject(
271
                                                        MetadataLocator.getMetadataManager().getDefinition(
272
                                                                        DataStore.METADATA_DEFINITION_NAME)));
273
                        init(p, null);
274
                }
275
        }
276

    
277
         /**
278
     * Constructor. Abre el dataset.
279
     * @param uri URI del fichero
280
     * @throws NotSupportedExtensionException
281
     */
282
    public WMTSProvider(URI uri) throws NotSupportedExtensionException {
283
        super(uri);
284
        WMTSDataParameters p = new WMTSDataParametersImpl();
285
        p.setURI(uri);
286
        super.init(
287
            p,
288
            null,
289
            ToolsLocator.getDynObjectManager().createDynObject(
290
                MetadataLocator.getMetadataManager().getDefinition(DataStore.METADATA_DEFINITION_NAME)));
291
        init(p, null);
292
    }
293

    
294
    public WMTSProvider(WMTSDataParameters params,
295
                        DataStoreProviderServices storeServices) throws NotSupportedExtensionException {
296
                super(params, storeServices, ToolsLocator.getDynObjectManager()
297
                                .createDynObject(
298
                                                MetadataLocator.getMetadataManager().getDefinition(
299
                                                                DataStore.METADATA_DEFINITION_NAME)));
300
                init(params, storeServices);
301
        }
302

    
303
        /**
304
         * Gets the connector from the URL
305
         * @return
306
         * @throws RemoteServiceException
307
         */
308
        public WMTSClient getOGCClient() throws WMTSException {
309
                if(ogcClient == null) {
310
                        WMTSDataParameters p = (WMTSDataParameters)parameters;
311
                        ogcClient = p.getOGCClient();
312
                        if(ogcClient != null)
313
                                return ogcClient;
314

    
315
                        URL url = null;
316
                        try {
317
                                url = p.getURI().toURL();
318
                        } catch (Exception e) {
319
                                throw new WMTSException("Malformed URL",e);
320
                        }
321
                        try {
322
                                ogcClient = WMTSOGCLocator.getManager().createWMTSClient(url.toString());
323
                                ogcClient.connect(true, new ICancellable() {
324

    
325
                                        public boolean isCanceled() {
326
                                                return false;
327
                                        }
328

    
329
                                        public Object getID() {
330
                                                return null;
331
                                        }
332
                                });
333
                        } catch (ConnectException e) {
334
                                throw new WMTSException("Connect exception",e);
335
                        } catch (IOException e) {
336
                                throw new WMTSException("Connect exception",e);
337
                        }
338
                }
339
                return ogcClient;
340
        }
341

    
342
        /**
343
         * Crea las referencias al fichero y carga
344
         * las estructuras con la informaci?n y los metadatos.
345
         * @param proj Proyecci?n
346
         * @param param Parametros de carga
347
         * @throws NotSupportedExtensionException
348
         */
349
        public void init (DataStoreParameters params,
350
                        DataStoreProviderServices storeServices) throws NotSupportedExtensionException {
351
                setParam(storeServices, params);
352
                if(((WMTSDataParameters)params).getImageFormat().compareTo("image/gif") == 0) {
353
                        setDataType(new int[]{Buffer.TYPE_BYTE});
354
                        bandCount = 1;
355
                } else {
356
                        setDataType(new int[]{Buffer.TYPE_BYTE, Buffer.TYPE_BYTE, Buffer.TYPE_BYTE, Buffer.TYPE_BYTE});
357
                        bandCount = 4;
358
                }
359

    
360
                if(!(param instanceof WMTSDataParameters))
361
                        return;
362

    
363
                gridSubsets = hasGridSubsets((WMTSDataParameters)param);
364
                open = true;
365
        }
366

    
367
        /**
368
         * Returns true if this layer has grid subsets
369
         * @return
370
         */
371
        public boolean hasGridSubsets() {
372
                return gridSubsets;
373
        }
374

    
375
        /**
376
         * Checks if this layer has grid subsets or doesn't
377
         * @param p
378
         * @return
379
         */
380
        private boolean hasGridSubsets(WMTSDataParameters p) {
381
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = null;
382
                List<WMTSTileMatrixSetLink> tileMatrixSetLinkList = p.getLayer().getTileMatrixSetLink();
383
                String srs = p.getSRSCode();
384
                for (int i = 0; i < tileMatrixSetLinkList.size(); i++) {
385
                        WMTSTileMatrixSetLink tileMatrixSetLink = (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(i);
386
                        WMTSTileMatrixSet tms = tileMatrixSetLink.getTileMatrixSet();
387
                        List<WMTSTileMatrixLimits> tmsl = tileMatrixSetLink.getTileMatrixLimits();
388
                        String srsTileSet = tms.getSupportedCRS();
389
                        if(areSrsEquals(srsTileSet, srs)) {
390
                                tileMatrixSetLimits = tmsl;
391
                        }
392
                }
393

    
394
                return (tileMatrixSetLimits == null || tileMatrixSetLimits.size() <= 0) ? false : true;
395
        }
396

    
397
        private boolean areSrsEquals(String sourceSrs, String appSrs) {
398
                if(sourceSrs.compareTo(appSrs) == 0)
399
                        return true;
400
                if(sourceSrs.contains("CRS:84") || sourceSrs.contains("CRS84")) {
401
                        if(appSrs.equals("EPSG:4326"))
402
                                return true;
403
                }
404
                return false;
405
        }
406

    
407
        /*public static final WMTSConnector getConnectorFromURL(URL url) throws IOException {
408
                WMTSConnector drv = (WMTSConnector) drivers.get(url);
409
                if (drv == null) {
410
                        drv = new WMTSConnector(url);
411
                        drivers.put(url, drv);
412
                }
413
                return drv;
414
        }*/
415

    
416
        /**
417
         * Obtiene el objeto que contiene que contiene la interpretaci?n de
418
         * color por banda
419
         * @return
420
         */
421
        public ColorInterpretation getColorInterpretation() {
422
                if(super.getColorInterpretation() == null) {
423
                        ColorInterpretation colorInterpretation = new DataStoreColorInterpretation(getBandCount());
424

    
425
                        if(getBandCount() == 1)
426
                                colorInterpretation = DataStoreColorInterpretation.createGrayInterpretation();
427

    
428
                        if(getBandCount() == 3)
429
                                colorInterpretation = DataStoreColorInterpretation.createRGBInterpretation();
430

    
431
                        if(getBandCount() == 4)
432
                                colorInterpretation = DataStoreColorInterpretation.createRGBAInterpretation();
433

    
434
                        if(getBandCount() > 4 || getBandCount() == 2) {
435
                                for (int i = 0; i < getBandCount(); i++) {
436
                                        colorInterpretation.setColorInterpValue(i, DataStoreColorInterpretation.UNDEF_BAND);
437
                                }
438
                        }
439
                        setColorInterpretation(colorInterpretation);
440
                }
441
                return super.getColorInterpretation();
442
        }
443

    
444
        public boolean isTiled() {
445
                return true;
446
        }
447

    
448
        public AffineTransform getAffineTransform() {
449
                WMTSDataParameters p = (WMTSDataParameters)parameters;
450
                Extent e = getExtent();
451
                double psX = e.width() / (lastWidthRequest <= 0 ? p.getWidth() : lastWidthRequest);
452
                double psY = -(e.height() / (lastHeightRequest <= 0 ? p.getHeight() : lastHeightRequest));
453
                ownTransformation = new AffineTransform(
454
                                psX,
455
                                0,
456
                                0,
457
                                psY,
458
                                e.getULX() - (psX / 2),
459
                                e.getULY() - (psY / 2));
460
                externalTransformation = (AffineTransform) ownTransformation.clone();
461
                return ownTransformation;
462
        }
463

    
464
        /**
465
         * <p>
466
         * Gets the bounding box in world coordinates.
467
         * If the layer has defined the BoundingBox tag, we will take this bounding box as entire
468
         * extension of this layer, else we'll see if the tag WGS84BoundingBox is defined (it can be approximated).
469
         * In this case we'll take WGS84BoundingBox as entire extension.
470
         * </p>
471
         * <br>
472
         * Note:
473
         * <br>
474
         * <p>
475
         * If the layer has grid subsets (TileMatrixLimits) then
476
         * this will have a only extent but if the layer doesn't have grid subsets then this will have a different
477
         * extent in each level resolution. In this case we need to know the extent for each level.
478
         * </p>
479
         * @return Extent
480
         */
481
        public Extent getExtent() {
482
                WMTSDataParameters p = (WMTSDataParameters)parameters;
483
                WMTSLayer layer = p.getLayer();
484

    
485
                if(layer.getBBox() != null)
486
                        return new ExtentImpl(layer.getBBox().toRectangle2D());
487

    
488
                if(layer.getWGS84BBox() != null) {
489
                        String crsCode = p.getSRSCode();
490
                        Rectangle2D r = layer.getWGS84BBoxTransformed(crsCode);
491
                        if(r != null)
492
                                return new ExtentImpl(r);
493
                }
494

    
495
                if(bbox == null)
496
                        getExtentByResolutionLevel();
497
                return bbox;
498

    
499
                /*if(gridSubsets) {
500
                        WMTSBoundingBox bbox = layer.getWGS84BBox();
501
                        return new ExtentImpl(bbox.toRectangle2D());
502
                } else {
503
                        if(bbox == null)
504
                                getExtentByResolutionLevel();
505
                        return bbox;
506
                }*/
507
        }
508

    
509
        /**
510
         * Gets the suffix of the downloaded image
511
         * @return
512
         */
513
        public String getFileSuffix() {
514
                WMTSDataParameters p = (WMTSDataParameters)parameters;
515
                String format = p.getImageFormat();
516
                if (format == null){
517
                        return "xml";
518
                }
519
                if (format.indexOf("png") >= 0){
520
                return "png";
521
                }
522
            if (format.indexOf("xml") >= 0){
523
                return "xml";
524
            }
525
            if (format.indexOf("gif") >= 0){
526
                return "gif";
527
            }
528
            if (format.indexOf("tif") >= 0){
529
                return "tif";
530
            }
531
            if (format.indexOf("bmp") >= 0){
532
                return "bmp";
533
            }
534
            if (format.indexOf("jpg") >= 0
535
                || format.indexOf("jpeg") >= 0){
536
                return "jpg";
537
            }
538
                return "xml";
539
        }
540

    
541
        /**
542
         * When a layer doesn't have grid subsets this will have a different bounding
543
         * box by resolution level. This function calculates and returns the array of
544
         * extents, one by resolution level.
545
         * @return
546
         */
547
        public Extent[] getExtentByResolutionLevel() {
548
                if(extentByLevel == null) {
549
                        WMTSDataParameters p = (WMTSDataParameters)parameters;
550
                        WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
551
                        WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
552

    
553
                    double widthMtsTile = 0;
554
                    double heightMtsTile = 0;
555
                        List<WMTSTileMatrix> tileMatrixList = tileMatrixSet.getTileMatrix();
556
                        extentByLevel = new ExtentImpl[tileMatrixList.size()];
557
                        double minX = 0;
558
                        double minY = 0;
559
                        double maxX = 0;
560
                        double maxY = 0;
561
                        for (int i = 0; i < tileMatrixList.size(); i++) {
562
                                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixList.get(i);
563
                            if(!p.isProjected()) {
564
                                    widthMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / (MTS_X_GRADO * 1000);
565
                                    heightMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileHeight() * 0.28) / (MTS_X_GRADO * 1000);
566
                            } else {
567
                                    widthMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / 1000;
568
                                    heightMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileHeight() * 0.28) / 1000;
569
                            }
570

    
571
                            //TODO: Revisar!!! Creo que el top left sale al rev?s en el de la nasa
572

    
573
                            double h = Math.abs(tileMatrix.getTopLeftCorner()[1] - (tileMatrix.getTopLeftCorner()[1] - (tileMatrix.getMatrixHeight() * heightMtsTile)));
574
                            Rectangle2D r = new Rectangle2D.Double(
575
                                            tileMatrix.getTopLeftCorner()[0],
576
                                            tileMatrix.getTopLeftCorner()[1] - h,
577
                                            Math.abs(tileMatrix.getTopLeftCorner()[0] - (tileMatrix.getTopLeftCorner()[0] + (tileMatrix.getMatrixWidth() * widthMtsTile))),
578
                                            h);
579
                            extentByLevel[i] = new ExtentImpl(r);
580
                            if(i == 0) {
581
                                    minX = extentByLevel[i].getMin().getX();
582
                                    minY = extentByLevel[i].getMin().getY();
583
                                    maxX = extentByLevel[i].getMax().getX();
584
                                    maxY = extentByLevel[i].getMax().getY();
585
                            } else {
586
                                    minX = Math.min(minX, extentByLevel[i].getMin().getX());
587
                                    minY = Math.min(minY, extentByLevel[i].getMin().getY());
588
                                    maxX = Math.max(maxX, extentByLevel[i].getMax().getX());
589
                                    maxY = Math.max(maxY, extentByLevel[i].getMax().getY());
590
                            }
591
                        }
592
                        bbox = new ExtentImpl(minX, maxY, maxX, minY);
593
                }
594
                return extentByLevel;
595
        }
596

    
597
        public Rectangle2D getLayerExtent(String layerName, String srs) throws RemoteServiceException {
598
                return null;
599
        }
600

    
601
        public RasterProvider load() {
602
                return this;
603
        }
604

    
605
        public boolean isOpen() {
606
                return open;
607
        }
608

    
609
        public void close() {
610
                open = false;
611
        }
612

    
613
        public Transparency getTransparency() {
614
                if(lastFileTransparency == null) {
615
                        lastFileTransparency = new DataStoreTransparency(getColorInterpretation());
616
                        lastFileTransparency.setTransparencyBand(3);
617
                }
618
                return lastFileTransparency;
619
        }
620

    
621
        public NoData getNoDataValue() {
622
                NoData nodata = super.getNoDataValue();
623
                if(nodata != null)
624
                        nodata.setNoDataTransparent(false);
625
                return noData;
626
        }
627

    
628
        public URI translateURI(URI uri) {
629
                return uri;
630
        }
631

    
632
        public void setView(Extent e) {
633
                viewRequest = e;
634
        }
635

    
636
        public Extent getView() {
637
                return viewRequest;
638
        }
639

    
640
        public double getWidth() {
641
                WMTSDataParameters p = (WMTSDataParameters)parameters;
642
                if (lastWidthRequest <= 0)
643
                        return p.getWidth();
644
                return lastWidthRequest;
645
        }
646

    
647
        public double getHeight() {
648
                WMTSDataParameters p = (WMTSDataParameters)parameters;
649
                if (lastHeightRequest <= 0)
650
                        return p.getHeight();
651
                return lastHeightRequest;
652
        }
653

    
654
        public Object readCompleteLine(int line, int band)
655
                throws InvalidSetViewException, FileNotOpenException, RasterDriverException {
656
                return null;
657
        }
658

    
659
        /**
660
         * When the remote layer has fixed size this method downloads the file and return its reference.
661
         * File layer has in the long side FIXED_SIZE pixels and the bounding box is complete. This file could be
662
         * useful to build an histogram or calculate statistics. This represents a sample of data.
663
         * @return
664
         * @throws RasterDriverException
665
         */
666
        public File getFileLayer() throws RasterDriverException {
667
                return null;
668
        }
669

    
670
        /**
671
         * Reads a complete block of data and returns an tridimensional array of the right type. This function is useful
672
         * to read a file very fast without setting a view. In a WMTS service when the size is fixed then it will read the
673
         * entire image but when the source hasn't pixel size it will read a sample of data. This set of data will have
674
         * the size defined in FIXED_SIZE.
675
         *
676
         * @param pos Posici?n donde se empieza  a leer
677
         * @param blockHeight Altura m?xima del bloque leido
678
         * @return Object que es un array tridimendional del tipo de datos del raster. (Bandas X Filas X Columnas)
679
         * @throws InvalidSetViewException
680
         * @throws FileNotOpenException
681
         * @throws RasterDriverException
682
         */
683
        public Object readBlock(int pos, int blockHeight, double scale)
684
        throws InvalidSetViewException, FileNotOpenException, RasterDriverException, ProcessInterruptedException {
685
                return null;
686
        }
687

    
688
        public Object getData(int x, int y, int band)
689
                throws InvalidSetViewException, FileNotOpenException, RasterDriverException {
690
                return null;
691
        }
692

    
693
        /**
694
         * Assigns the list of bands RGB and read a window of data
695
         * @param rasterBuf
696
         * @param bandList
697
         * @param lastFile
698
         * @param ulx
699
         * @param uly
700
         * @param lrx
701
         * @param lry
702
         * @return
703
         * @throws RasterDriverException
704
         * @throws ProcessInterruptedException
705
         */
706
        public Buffer getBuffer(Buffer rasterBuf, BandList bandList, File lastFile,
707
                        double ulx, double uly, double lrx, double lry) throws RasterDriverException, ProcessInterruptedException {
708
                return null;
709
        }
710

    
711
        /**
712
         * Gets the tile matrix from the selected level
713
         * @param level
714
         * @return
715
         */
716
        private WMTSTileMatrix getTileMatrixByLevel(int level) {
717
                level = adjustLevel(level);
718

    
719
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
720
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
721
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
722

    
723
                WMTSTileMatrixLimits tileMatrixLimits = null;
724
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(level);
725
                if(hasGridSubsets()) {
726
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(level);
727
                        tileMatrix = tileMatrixLimits.getTileMatrix();
728
                }
729
                return tileMatrix;
730
        }
731

    
732
        /**
733
         * Returns the number of levels
734
         * @return
735
         */
736
        public int getZoomLevels() {
737
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
738
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
739
                if(hasGridSubsets()) {
740
                        List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
741
                        return Math.min(tileMatrixSet.getTileMatrix().size(), tileMatrixSetLimits.size());
742
                }
743
                return tileMatrixSet.getTileMatrix().size();
744

    
745
        }
746

    
747
        public Extent getCoordsInTheNearestLevel(Extent extent, int w, int h) {
748
                double[] pixelSizes = getPixelSizeByLevel();
749
                double currentPixelSize = extent.width() / (double)w;
750

    
751
                int level = 0;
752
                for (int i = 0; i < (pixelSizes.length - 1); i++) {
753
                        if(currentPixelSize < pixelSizes[i] && currentPixelSize >= pixelSizes[i + 1]) {
754
                                level = i + 1;
755
                                break;
756
                        }
757
                }
758

    
759
                return getZoomLevelCoordinates(level, extent, w, h);
760
        }
761

    
762
        public Extent getCoordsInLevel(Point2D viewCenter, int level, int w, int h) {
763
                WMTSDataParameters p = (WMTSDataParameters)param;
764
                level = adjustLevel(level);
765
                WMTSTileMatrix tileMatrix = getTileMatrixByLevel(level);
766

    
767
                boolean proj = p.isProjected();
768

    
769
                double psX = tileMatrix.getWidthWCTile(proj) / tileMatrix.getTileWidth();
770
                double psY = tileMatrix.getHeightWCTile(proj) / tileMatrix.getTileHeight();
771

    
772
                double ulx = viewCenter.getX() - ((w / 2) * psX);
773
                double uly = viewCenter.getY() - ((h / 2) * psY);
774
                double lrx = ulx + (w * psX);
775
                double lry = uly + (h * psY);
776
                return new ExtentImpl(ulx, uly, lrx, lry);
777
        }
778

    
779
        /**
780
         * Calculates the extent of a zoom level using other extent as a reference. The new extent is
781
         * calculated with the same coordinate at the center.
782
         * @param level
783
         * @param extent
784
         * @param w
785
         * @param h
786
         * @return
787
         */
788
        public Extent getZoomLevelCoordinates(int level, Extent extent, int w, int h) {
789
                double centerX = extent.getCenterX();
790
                double centerY = extent.getCenterY();
791
                return getCoordsInLevel(new Point2D.Double(centerX, centerY), level, w, h);
792
        }
793

    
794
        /**
795
         * Returns a list of pixel sizes by level
796
         * @return
797
         */
798
        public double[] getPixelSizeByLevel() {
799
                WMTSDataParameters p = (WMTSDataParameters)param;
800
                double[] list = new double[getZoomLevels()];
801

    
802
                for (int i = 0; i < getZoomLevels(); i++) {
803
                        WMTSTileMatrix tileMatrix = getTileMatrixByLevel(i);
804
                        list[i] = math.adjustDouble(tileMatrix.getWidthWCTile(p.isProjected()) / tileMatrix.getTileWidth());
805
                }
806
                return list;
807
        }
808

    
809
        /**
810
         * Adjust de level to the range
811
         * @param level
812
         * @return
813
         */
814
        private int adjustLevel(int level) {
815
                if(level < 0)
816
                        level = 0;
817
                if(level > getZoomLevels())
818
                        level = getZoomLevels();
819
                return level;
820
        }
821

    
822
        public org.gvsig.raster.cache.tile.Tile getTile(SpiRasterQuery q) throws TileGettingException {
823
                //q.getResolutionLevel(), q.getTileCol(), q.getTileRow(), q.getBBox(), q.getCacheStruct()!
824

    
825
                CacheStruct str = getTileServer().getStruct();
826

    
827
                //1-Selecci?n de WMTSTileMatrixSet por srs
828
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
829
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
830
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
831

    
832
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(q.getResolutionLevel());
833
                if(gridSubsets) {
834
                        WMTSTileMatrixLimits tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(q.getResolutionLevel());
835
                        tileMatrix = tileMatrixLimits.getTileMatrix();
836
                }
837
                int bufWidth = tileMatrix.getTileWidth();
838
                int bufHeight = tileMatrix.getTileHeight();
839

    
840
                try {
841
                        Extent adjBbox = q.getAdjustedRequestBoundingBox();
842
                        Rectangle2D r = adjBbox.toRectangle2D();//new Rectangle2D.Double(Math.min(minX, maxX), Math.min(minY, maxY), Math.abs(maxX - minX), Math.abs(maxY - minY));
843
                        WMTSStatus status = buildWMTSStatus(r, bufWidth , bufHeight);
844

    
845
                        int[] size = str.getTileSizeByLevel(q.getResolutionLevel());
846
                        WMTSTile tile = WMTSOGCLocator.getManager().createTile(
847
                                        size,
848
                                        new int[]{q.getTileRow(), q.getTileCol()},
849
                                        new double[]{adjBbox.getULX(), adjBbox.getULY(), adjBbox.getLRX(), adjBbox.getLRY()});
850

    
851
                        File file = getOGCClient().getTile(status, null);
852
                        tile.setFile(file);
853
                        //Creamos un BandList con todas las bandas del fichero
854
                        BandList bandList = new BandListImpl();
855
                        for(int i = 0; i < getBandCount(); i++) {
856
                                try {
857
                                        DatasetBand band = new DatasetBandImpl(getURIOfFirstProvider().getPath(), i, getDataType()[i], getBandCount());
858
                                        bandList.addBand(band);
859
                                } catch(BandNotFoundInListException e) {
860
                                        //No a?adimos la banda
861
                                }
862
                        }
863
                        return drawTile(tile, null, bandList);
864
                } catch (WMTSException e) {
865
                        throw new TileGettingException("Error getting tiles", e);
866
                } catch (ServerErrorException e) {
867
                        throw new TileGettingException("Error getting tiles", e);
868
                } catch (RasterDriverException e) {
869
                        throw new TileGettingException("Error getting tiles", e);
870
                }
871
        }
872

    
873
        @Override
874
        public void loadBuffer(SpiRasterQuery q)
875
                        throws ProcessInterruptedException, RasterDriverException {
876
                Rectangle2D r = q.getAdjustedRequestBoundingBox().toRectangle2D();//new Rectangle2D.Double(Math.min(minX, maxX), Math.min(minY, maxY), Math.abs(maxX - minX), Math.abs(maxY - minY));
877
                WMTSStatus status = buildWMTSStatus(r, q.getAdjustedWidth(), q.getAdjustedBufHeight());
878
                request(status, q.getBandList(), q.getTileListener(), requestType);
879
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, q.getBandList(), null, requestType);
880
                MemoryTileMatrixBuffer matrixBuffer = new MemoryTileMatrixBuffer(tileList);
881
                Buffer b = matrixBuffer.getWindow(q.getAdjustedRequestBoundingBox(), q.getBufWidth(), q.getBufHeight(), q.getBandList().getDrawableBandsCount());
882
                q.setBufferResult(b);
883
        }
884

    
885
        /**
886
         * Gets the information from a point
887
         * @param wcx
888
         * @param wcy
889
         * @param level
890
         * @return
891
         * @throws RasterDriverException
892
         */
893
        public String getFeatureInfo(double wcx, double wcy, int level) throws RasterDriverException {
894
                PointInfo pointInfo = new PointInfo(new Point2D.Double(wcx, wcy));
895
                pointInfo.level = level;
896
                getTileInfo(pointInfo);
897

    
898
                WMTSClient ogcClient = null;
899
                try {
900
                        ogcClient = getOGCClient();
901
                        lastStatus.setTileRow((int)pointInfo.tile.getX());
902
                        lastStatus.setTileCol((int)pointInfo.tile.getY());
903

    
904
                        String fi = ogcClient.getFeatureInfo(lastStatus, (int)pointInfo.pixelInTile.getX(), (int)pointInfo.pixelInTile.getY(), null);
905
                        return fi;
906
                } catch (WMTSException e) {
907
                        throw new RasterDriverException("Error getting the connector object", e);
908
                }
909
        }
910

    
911
        /**
912
         * Gets a tile position from a world coordinates point and a resolution level
913
         * @param point
914
         * @param level
915
         * @return An array with two elements. The first is the row and the second the column
916
         * of the tile in the tile matrix
917
         */
918
        private void getTileInfo(PointInfo pointInfo) {
919
                WMTSDataParameters p = (WMTSDataParameters)param;
920

    
921
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
922
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
923
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
924

    
925
                WMTSTileMatrixLimits tileMatrixLimits = null;
926
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(pointInfo.level);
927
                if(hasGridSubsets()) {
928
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(pointInfo.level);
929
                        tileMatrix = tileMatrixLimits.getTileMatrix();
930
                }
931

    
932
                List<WMTSTile> tiles = null;
933
                if(hasGridSubsets())
934
                        tiles = tileMatrix.contains(p.isProjected(), tileMatrixLimits, pointInfo.worldCoord, getExtent().toRectangle2D());
935
                else
936
                        tiles = tileMatrix.contains(p.isProjected(), pointInfo.worldCoord, getExtent().toRectangle2D());
937

    
938
                //Tile row and column
939
                pointInfo.tile = new Point2D.Double(tiles.get(0).getRow(), tiles.get(0).getCol());
940

    
941
                //Desplazamiento en pixels dentro del tile
942
                Point2D rasterPoint = tiles.get(0).worldToRaster(pointInfo.worldCoord);
943
                pointInfo.pixelInTile = new Point2D.Double(rasterPoint.getX(), rasterPoint.getY());
944
        }
945

    
946
        /**
947
         * Builds the WMTSStatus object using the parameters and the request bounding box.
948
         * @param r
949
         * @param bufWidth
950
         * @return
951
         * @throws RasterDriverException
952
         */
953
        public WMTSStatus buildWMTSStatus(Rectangle2D r, int bufWidth, int bufHeight) throws RasterDriverException {
954
                WMTSDataParameters p = (WMTSDataParameters)param;
955

    
956
                //Mantiene actualizados los par?metros del WMTSStoreParameters con la ?ltima petici?n hecha
957
                p.setExtent(r);
958
                p.setWidth(bufWidth);
959
                p.setHeight(bufHeight);
960

    
961
                lastWidthRequest = bufWidth;
962
                lastHeightRequest = bufHeight;
963

    
964
                //1-Selecci?n de WMTSTileMatrixSet por srs
965
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
966
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
967
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
968
                int initialLevel = p.getLayer().getInitialLevel(tileMatrixSet.getIdentifier());
969

    
970
                //Esto hace lo mismo que getScale y getLevelFromScale
971
                /*int level = 0;
972
                double[] pixelSizes = getPixelSizeByLevel();
973
                double psViewPort = math.adjustDouble(r.getWidth() / (double)bufWidth);
974
                for (int i = 0; i < pixelSizes.length - 1; i++) {
975
                        if(psViewPort <= pixelSizes[i] && psViewPort > pixelSizes[i + 1]) {
976
                                level = i;
977
                                break;
978
                        }
979
                }*/
980

    
981
                //2-Calculo de la escala
982
                double scale = getScale(r, bufWidth);
983

    
984
                //3-Selecci?n del nivel a partir de la escala
985
                int level = getLevelFromScale(scale, tileMatrixSet);
986

    
987
                //Para evitar que se salga del array si la capa tiene menos niveles que el tilematrixset
988
                int dif = 0;
989
                if(gridSubsets)
990
                        dif = (level - initialLevel) >= tileMatrixSetLimits.size() ?  (level - initialLevel) - tileMatrixSetLimits.size() + 1 : 0;
991

    
992
                //4-Obtenemos la matriz de tiles y los l?mites si tiene subsets
993
                @SuppressWarnings("unused")
994
                WMTSTileMatrixLimits tileMatrixLimits = null;
995
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(level - dif);
996
                if(gridSubsets)
997
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(level - initialLevel - dif);
998

    
999
                //5-Selecci?n de tiles que entran en esta bounding box
1000
                List<WMTSTile> tiles = null;
1001
                /*if(gridSubsets)
1002
                        tiles = tileMatrix.intersects(p.isProjected(), tileMatrixLimits, r, getExtent().toRectangle2D());
1003
                else*/
1004
                Extent[] extList = getExtentByResolutionLevel();
1005
                tiles = tileMatrix.intersects(p.isProjected(), r, extList[level].toRectangle2D());
1006

    
1007
                //6-Petici?n
1008
                WMTSStatus status = null;
1009
                try {
1010
                        status = getOGCClient().createStatus();
1011
                } catch (WMTSException e) {
1012
                        throw new RasterDriverException("Error creating WMTSStatus", e);
1013
                }
1014
                WMTSLayer wmtsLayer = p.getLayer();
1015
                status.setTileList(tiles);
1016
                status.setLayer(wmtsLayer.getIdentifier());//.substring(p.getLayer().getIdentifier().indexOf("_") + 1));
1017

    
1018
                status.setFormat(p.getImageFormat());
1019
                status.setInfoFormat(p.getInfoFormat());
1020
                status.setStyle(p.getStyle() != null ? p.getStyle().getIdentifier() : "");
1021
                status.setTileMatrixSet(tileMatrixSet.getIdentifier());
1022
                status.setTileMatrix(tileMatrix.getIdentifier());
1023
                status.setLevel(level - dif);
1024
                status.setDimension(p.getDimension());
1025
                status.setValueForDimension(p.getDimensionSelectedValue());
1026

    
1027
                wmtsLayer.buildResourceURLListFromTemplate(status);
1028
                this.lastStatus = status;
1029

    
1030
                return status;
1031
        }
1032

    
1033
        /**
1034
         * Gets the resolution level from the real coordinates
1035
         * @param r
1036
         * @param
1037
         * @return
1038
         * @throws RasterDriverException
1039
         */
1040
        public int getLevelFromRealCoords(Rectangle2D r, int width) throws RasterDriverException {
1041
                double scale = getScale(r, width);
1042
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
1043
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
1044
                return getLevelFromScale(scale, tileMatrixSet);
1045
        }
1046

    
1047
        /**
1048
         * Gets the resolution level from the scale
1049
         * @param scale
1050
         * @param tileMatrixSet
1051
         * @return
1052
         * @throws RasterDriverException
1053
         */
1054
        public int getLevelFromScale(double scale, WMTSTileMatrixSet tileMatrixSet) throws RasterDriverException {
1055
                //Recorremos los tileMatrix para obtener la escala m?s aproximada
1056
                int levelModifier = 0;
1057
                scale = math.adjustDouble(scale);
1058
                try {
1059
                        for (int resolutionLevel = 0; resolutionLevel < tileMatrixSet.getTileMatrix().size(); resolutionLevel++) {
1060
                                WMTSTileMatrix tm = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(resolutionLevel);
1061
                                double scaleDenominator = math.adjustDouble(tm.getScaleDenominator());
1062
                                if(scale >= scaleDenominator) {
1063
                                        return Math.max(resolutionLevel + levelModifier, 0);
1064
                                }
1065
                        }
1066
                } catch (IndexOutOfBoundsException e) {
1067
                        throw new RasterDriverException("Error in this resolution level", e);
1068
                }
1069
                return 0;
1070
        }
1071

    
1072
        /**
1073
         * Get the tile matrix set using the crs
1074
         * @param srs
1075
         * @return
1076
         */
1077
        public WMTSTileMatrixSetLink getTileMatrixSetLink() {
1078
                WMTSDataParameters p = (WMTSDataParameters)param;
1079
                List<WMTSTileMatrixSetLink> tileMatrixSetLinkList = p.getLayer().getTileMatrixSetLink();
1080
                for (int i = 0; i < tileMatrixSetLinkList.size(); i++) {
1081
                        WMTSTileMatrixSetLink tileMatrixSetLink = (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(i);
1082
                        String srsTileSet = tileMatrixSetLink.getTileMatrixSet().getSupportedCRS();
1083
                        if(srsTileSet.compareTo(p.getSRSCode()) == 0) {
1084
                                return tileMatrixSetLink;
1085
                        }
1086
                }
1087
                if(tileMatrixSetLinkList != null && tileMatrixSetLinkList.size() > 0)
1088
                        return (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(0);
1089
                return null;
1090
        }
1091

    
1092
        /**
1093
         * Gets the scale using the extent and the width in pixels.
1094
         * @param r
1095
         * @param width
1096
         * @return
1097
         */
1098
        private double getScale(Rectangle2D r, int width) {
1099
                WMTSDataParameters p = (WMTSDataParameters)param;
1100
                if(!p.isProjected()) {
1101
                        return (r.getWidth() * MTS_X_GRADO) / (width * 0.00028);
1102
                } else
1103
                        return (r.getWidth()) / (width * 0.00028);
1104
        }
1105

    
1106
        /**
1107
         * Throw a request
1108
         * @param status
1109
         * @param bandList
1110
         * @param listener
1111
         * @param alphaBandNumber
1112
         * @return returns a buffer if the listener is null. In any other case it return null.
1113
         * @throws RasterDriverException
1114
         * @throws ProcessInterruptedException
1115
         */
1116
        private synchronized org.gvsig.raster.cache.tile.Tile[] request(
1117
                        WMTSStatus status, BandList bandList, TileListener listener, int requestType) throws RasterDriverException, ProcessInterruptedException {
1118
                //WMTSDataParameters p = (WMTSDataParameters)param;
1119
                WMTSClient ogcClient = null;
1120
                try {
1121
                        ogcClient = getOGCClient();
1122
                } catch (WMTSException e) {
1123
                        throw new RasterDriverException("Error getting the connector object", e);
1124
                }
1125

    
1126
                if(ogcClient == null)
1127
                        throw new RasterDriverException("Error getting the connector object");
1128

    
1129
                List<WMTSTile> tiles = status.getTileList();
1130

    
1131
                TilePipe pipe = new TilePipe();
1132
                //TilePipe2 pipe = new TilePipe2();
1133
                //TileThreadPool pool = null;
1134

    
1135
                //Caso 1: Lanza un thread que gestiona que no se lancen muchos threads a la vez
1136
                if(requestType == LIMITED_THREADS) {
1137
                        RequestThreadManager threadManager = new RequestThreadManager(pipe, tiles, status);
1138
                        pipe.setRequestManager(threadManager);
1139
                        threadManager.start();
1140
                //Caso 2: Lanza todos los threads
1141
                } else if(requestType == UNLIMITED_THREADS) {
1142
                        for (int i = 0; i < tiles.size(); i++) {
1143
                                WMTSTile tile = tiles.get(i);
1144
                                WMTSStatus statusCopy = status.cloneStatus();
1145
                                statusCopy.setTileRow(tile.getRow());
1146
                                statusCopy.setTileCol(tile.getCol());
1147
                                new RequestTileLauncher(pipe, statusCopy, tile).start();
1148
                        }
1149
                }
1150

    
1151
                org.gvsig.raster.cache.tile.Tile[] tileList = new org.gvsig.raster.cache.tile.Tile[tiles.size()];
1152

    
1153
                if(requestType == LIMITED_THREADS || requestType == UNLIMITED_THREADS) {
1154
                        int nCollected = 0;
1155
                        while (nCollected < tiles.size()) {
1156
                                WMTSTile tile = pipe.getTile();
1157
                                tileList[nCollected] = drawTile(tile, listener, bandList);
1158
                                nCollected ++;
1159
                        }
1160
                }
1161

    
1162
                if(requestType == SEQUENTIAL) {
1163
                        for (int i = 0; i < tiles.size(); i++) {
1164
                                WMTSTile tile = tiles.get(i);
1165
                                status.setTileRow(tile.getRow());
1166
                                status.setTileCol(tile.getCol());
1167
                                //TODO:Cancelaci?n
1168
                                try {
1169
                                        File file = ogcClient.getTile(status, null);
1170
                                        tile.setFile(file);
1171
                                        tileList[i] = drawTile(tile, listener, bandList);
1172
                                } catch (WMTSException e) {
1173
                                        throw new RasterDriverException("Error getting tiles", e);
1174
                                } catch (ServerErrorException e) {
1175
                                        throw new RasterDriverException("Error getting tiles", e);
1176
                                }
1177
                        }
1178
                }
1179
                if(listener != null)
1180
                        listener.endReading();
1181

    
1182
                return tileList;
1183
        }
1184

    
1185
        /**
1186
         * Reads a tile with gdal and calls the method nextBuffer
1187
         * @param tile
1188
         * @param listener
1189
         * @param bandList
1190
         * @return
1191
         * @throws RasterDriverException
1192
         */
1193
        private synchronized org.gvsig.raster.cache.tile.Tile drawTile(WMTSTile tile, TileListener listener, BandList bandList) throws RasterDriverException {
1194
                WMTSDataParameters p = (WMTSDataParameters)param;
1195
                try {
1196
                        AbstractRasterProvider driver = DefaultProviderServices.loadProvider(tile.getFile());
1197
                        colorTable = driver.getColorTable();
1198
                        bandCount = driver.getBandCount();
1199
                        lastFileTransparency = (DataStoreTransparency)driver.getTransparency();
1200

    
1201
                        RasterQuery q = RasterLocator.getManager().createQuery();
1202
                        q.setAreaOfInterest(new Rectangle(0, 0, tile.getWidthPx(), tile.getHeightPx()));
1203
                        int[] drawableBands = bandList.getDrawableBands();
1204
                        if(drawableBands.length > 3)
1205
                                drawableBands = new int[]{drawableBands[0], drawableBands[1], drawableBands[2]};
1206
                        q.setDrawableBands(bandList.getDrawableBands());
1207
                        RasterDataStore store = new DefaultRasterStore();
1208
                        store.setProvider(driver);
1209
                        Buffer buf = store.query(q);
1210

    
1211
                        buf.setDataExtent(new Rectangle2D.Double(
1212
                                        Math.min(tile.getULX(), tile.getLRX()),
1213
                                        Math.min(tile.getULY(), tile.getLRY()),
1214
                                        Math.abs(tile.getULX() - tile.getLRX()),
1215
                                        Math.abs(tile.getULY() - tile.getLRY())));
1216

    
1217
                        Buffer alphaBand = null;
1218
                        if(p.getAlphaBand() != -1 && listener != null && p.getAlphaBand() < bandCount) {
1219
                                q = RasterLocator.getManager().createQuery();
1220
                                q.setAreaOfInterest(new Rectangle(0, 0, tile.getWidthPx(), tile.getHeightPx()));
1221
                                q.setDrawableBands(new int[]{p.getAlphaBand()});
1222
                                alphaBand = store.query(q);
1223
                        }
1224

    
1225
                        try {
1226
                                store.close();
1227
                        } catch (CloseException e) {
1228
                                logger.info("I cannot close the DataStore", e);
1229
                        }
1230

    
1231

    
1232
                        TileCacheManager m = TileCacheLocator.getManager();
1233
                        org.gvsig.raster.cache.tile.Tile t = m.createTile(-1, tile.getRow(), tile.getCol());
1234
                        t.setData(new Object[]{buf, alphaBand});
1235
                        t.setUl(new Point2D.Double(tile.getULX(), tile.getULY()));
1236
                        t.setLr(new Point2D.Double(tile.getLRX(), tile.getLRY()));
1237
                        t.setDownloaderParams("AffineTransform", getAffineTransform());
1238
                        t.setDownloaderParams("Tiling", new Boolean(true));
1239
                        if(listener != null)
1240
                                listener.tileReady(t);
1241
                        else
1242
                                return t;
1243

    
1244
                } catch (ProcessInterruptedException e) {
1245
                } catch (TileGettingException e) {
1246
                        throw new RasterDriverException("Error throwing a tile", e);
1247
                } catch (ProviderNotRegisteredException e) {
1248
                        throw new RasterDriverException("Error throwing a tile", e);
1249
                } catch (InitializeException e) {
1250
                        throw new RasterDriverException("Error throwing a tile", e);
1251
                } catch (QueryException e) {
1252
                        throw new RasterDriverException("Error throwing a tile", e);
1253
                }
1254
                return null;
1255
        }
1256

    
1257
        public Image getImageLegend() {
1258
                try {
1259
                        File file = getOGCClient().getLegendGraphic(
1260
                                        ((WMTSDataParameters)param).getLayer(),
1261
                                        ((WMTSDataParameters)param).getStyle(),
1262
                                        new ICancellable() {
1263
                                                public boolean isCanceled() {
1264
                                                        return false;
1265
                                                }
1266

    
1267
                                                public Object getID() {
1268
                                                        return null;
1269
                                                }
1270
                                        });
1271
                        Image img = null;
1272
                        if ((file != null) && (file.length() > 0)) {
1273
                                img = new ImageIcon(file.getAbsolutePath()).getImage();
1274
                        }
1275
                        return img;
1276
                } catch (Exception e) {
1277
                        logger.info("Problems in GetLegendGraphic", e);
1278
                }
1279
                return null;
1280
        }
1281

    
1282
        public int getBlockSize() {
1283
                return 0;
1284
        }
1285

    
1286
        public void setAffineTransform(AffineTransform t){
1287

    
1288
        }
1289

    
1290
        public int getOverviewCount(int band) throws BandAccessException, RasterDriverException {
1291
                return 0;
1292
        }
1293

    
1294
        public int getOverviewWidth(int band, int overview) throws BandAccessException, RasterDriverException {
1295
                return 0;
1296
        }
1297

    
1298
        public int getOverviewHeight(int band, int overview) throws BandAccessException, RasterDriverException {
1299
                return 0;
1300
        }
1301

    
1302
        public boolean isOverviewsSupported() {
1303
                return false;
1304
        }
1305

    
1306
        public boolean isReproyectable() {
1307
                return false;
1308
        }
1309

    
1310
        public String getProviderName() {
1311
                return NAME;
1312
        }
1313

    
1314
        public String getName() {
1315
            return this.getParameters().getLayer().getTitle();
1316
        }
1317

    
1318
        public WMTSDataParameters getParameters() {
1319
                return (WMTSDataParameters)this.param;
1320
        }
1321

    
1322
        /**
1323
         * Convierte un punto desde coordenadas pixel a coordenadas del mundo.
1324
         * @param pt Punto a transformar
1325
         * @return punto transformado en coordenadas del mundo
1326
         */
1327
        public Point2D rasterToWorld(Point2D pt) {
1328
                Point2D p = new Point2D.Double();
1329
                getAffineTransform().transform(pt, p);
1330
                return p;
1331
        }
1332

    
1333
        /**
1334
         * Convierte un punto desde del mundo a coordenadas pixel.
1335
         * @param pt Punto a transformar
1336
         * @return punto transformado en coordenadas pixel
1337
         */
1338
        public Point2D worldToRaster(Point2D pt) {
1339
                Point2D p = new Point2D.Double();
1340
                try {
1341
                        getAffineTransform().inverseTransform(pt, p);
1342
                } catch (NoninvertibleTransformException e) {
1343
                        return pt;
1344
                }
1345
                return p;
1346
        }
1347

    
1348
        public void setStatus(RasterProvider provider) {
1349
                if(provider instanceof WMTSProvider) {
1350
                }
1351
        }
1352

    
1353
        public File getLastRequest() {
1354
                return lastRequest;
1355
        }
1356

    
1357
        /**
1358
         * ASigna el par?metro de inicializaci?n del driver.
1359
         */
1360
        @Override
1361
        public void setParam(DataStoreProviderServices storeServices, DataStoreParameters param) {
1362
                if(param instanceof WMTSDataParameters)
1363
                        this.uri = ((WMTSDataParameters)param).getURI();
1364
                this.param = param;
1365
                this.storeServices = storeServices;
1366
        }
1367

    
1368
        public String getInfoByPoint(int x, int y, Extent bbox, int w, int h, ICancellable cancellable) throws InfoByPointException {
1369
                int level;
1370
                try {
1371
                        level = getLevelFromRealCoords(bbox.toRectangle2D(), w);
1372
                        return getFeatureInfo(x, y, level);
1373
                } catch (RasterDriverException e) {
1374
                        throw new InfoByPointException("Error in getFeatureInfo", e);
1375
                }
1376
        }
1377

    
1378
        public int getNearestLevel(double pixelSize) {
1379
                double[] pixelSizes = getPixelSizeByLevel();
1380
                for (int i = 0; i < pixelSizes.length - 1; i++) {
1381
                        if(pixelSize <= pixelSizes[i] && pixelSize > pixelSizes[i + 1]) {
1382
                                return i;
1383
                        }
1384
                }
1385
                if(pixelSize < pixelSizes[getZoomLevels() - 1])
1386
                        return getZoomLevels() - 1;
1387
                return 0;
1388
        }
1389

    
1390
        public TileServer getTileServer() {
1391
                if(tileServer == null) {
1392
                        DefaultRasterStore store = new DefaultRasterStore();
1393
                        store.setProvider(this);
1394
                        tileServer = new WMTSTileServer(store, getTileMatrixSetLink());
1395
                }
1396
                return tileServer;
1397
        }
1398

    
1399
        public int[] getTileSize(int level) {
1400
                return getTileServer().getStruct().getTileSizeByLevel(level);
1401
        }
1402

    
1403
        public boolean isRasterEnclosed() {
1404
                return true;
1405
        }
1406

    
1407
        public Buffer getBufferLastRequest() throws ProcessInterruptedException, RasterDriverException {
1408
                return null;
1409
        }
1410

    
1411
        /**
1412
         * Gets the srs code
1413
         * @return
1414
         */
1415
        public String getSRSCode() {
1416
                WMTSDataParameters p = (WMTSDataParameters)param;
1417
                return p.getSRSCode();
1418
        }
1419

    
1420
        public RasterProvider getInternalProvider() {
1421
                return this;
1422
        }
1423

    
1424
        public HistogramComputer getHistogramComputer() {
1425
                if (histogram == null)
1426
                        histogram = new RemoteStoreHistogram(this);
1427
                return histogram;
1428
        }
1429

    
1430
    /* (non-Javadoc)
1431
     * @see org.gvsig.raster.impl.provider.RasterProvider#addFile(java.io.File)
1432
     */
1433
    @Override
1434
    public void addFile(File file) throws InvalidSourceException {
1435
        // Do nothing
1436

    
1437
    }
1438

    
1439
    /* (non-Javadoc)
1440
     * @see org.gvsig.raster.impl.provider.RasterProvider#removeFile(java.io.File)
1441
     */
1442
    @Override
1443
    public void removeFile(File file) {
1444
        // Do nothing
1445

    
1446
    }
1447

    
1448
    /* (non-Javadoc)
1449
     * @see org.gvsig.raster.impl.provider.AbstractRasterProvider#getProjection()
1450
     */
1451
    @Override
1452
    public IProjection getProjection() {
1453
        if(proj==null){
1454
            proj = ((WMTSDataParameters)param).getSRS();
1455
        }
1456
        return proj;
1457
    }
1458

    
1459
}