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 @ 1057

History | View | Annotate | Download (51.6 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.geom.AffineTransform;
25
import java.awt.geom.NoninvertibleTransformException;
26
import java.awt.geom.Point2D;
27
import java.awt.geom.Rectangle2D;
28
import java.io.File;
29
import java.io.IOException;
30
import java.net.ConnectException;
31
import java.net.MalformedURLException;
32
import java.net.URL;
33
import java.util.ArrayList;
34

    
35
import org.gvsig.compat.net.ICancellable;
36
import org.gvsig.fmap.dal.DALLocator;
37
import org.gvsig.fmap.dal.DataStore;
38
import org.gvsig.fmap.dal.DataStoreParameters;
39
import org.gvsig.fmap.dal.coverage.RasterLocator;
40
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
41
import org.gvsig.fmap.dal.coverage.datastruct.BandList;
42
import org.gvsig.fmap.dal.coverage.datastruct.DatasetBand;
43
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
44
import org.gvsig.fmap.dal.coverage.exception.BandAccessException;
45
import org.gvsig.fmap.dal.coverage.exception.BandNotFoundInListException;
46
import org.gvsig.fmap.dal.coverage.exception.FileNotOpenException;
47
import org.gvsig.fmap.dal.coverage.exception.HistogramException;
48
import org.gvsig.fmap.dal.coverage.exception.InvalidSetViewException;
49
import org.gvsig.fmap.dal.coverage.exception.NotSupportedExtensionException;
50
import org.gvsig.fmap.dal.coverage.exception.ProcessInterruptedException;
51
import org.gvsig.fmap.dal.coverage.exception.RasterDriverException;
52
import org.gvsig.fmap.dal.coverage.exception.RemoteServiceException;
53
import org.gvsig.fmap.dal.coverage.store.props.ColorInterpretation;
54
import org.gvsig.fmap.dal.coverage.store.props.HistogramComputer;
55
import org.gvsig.fmap.dal.coverage.store.props.Transparency;
56
import org.gvsig.fmap.dal.coverage.util.MathUtils;
57
import org.gvsig.fmap.dal.exception.InitializeException;
58
import org.gvsig.fmap.dal.exception.ProviderNotRegisteredException;
59
import org.gvsig.fmap.dal.spi.DataManagerProviderServices;
60
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
61
import org.gvsig.metadata.MetadataLocator;
62
import org.gvsig.raster.cache.tile.TileCacheLocator;
63
import org.gvsig.raster.cache.tile.TileCacheManager;
64
import org.gvsig.raster.cache.tile.exception.TileGettingException;
65
import org.gvsig.raster.cache.tile.provider.CacheStruct;
66
import org.gvsig.raster.cache.tile.provider.TileListener;
67
import org.gvsig.raster.cache.tile.provider.TileServer;
68
import org.gvsig.raster.impl.DefaultRasterManager;
69
import org.gvsig.raster.impl.buffer.DefaultRasterQuery;
70
import org.gvsig.raster.impl.datastruct.BandListImpl;
71
import org.gvsig.raster.impl.datastruct.DatasetBandImpl;
72
import org.gvsig.raster.impl.datastruct.ExtentImpl;
73
import org.gvsig.raster.impl.provider.DefaultRasterProvider;
74
import org.gvsig.raster.impl.provider.MemoryMatrixBuffer;
75
import org.gvsig.raster.impl.provider.RasterProvider;
76
import org.gvsig.raster.impl.provider.RemoteRasterProvider;
77
import org.gvsig.raster.impl.provider.TiledRasterProvider;
78
import org.gvsig.raster.impl.store.DefaultStoreFactory;
79
import org.gvsig.raster.impl.store.properties.DataStoreColorInterpretation;
80
import org.gvsig.raster.impl.store.properties.DataStoreTransparency;
81
import org.gvsig.raster.impl.store.properties.RemoteStoreHistogram;
82
import org.gvsig.raster.util.DefaultProviderServices;
83
import org.gvsig.raster.wmts.io.downloader.WMTSTileServer;
84
import org.gvsig.remoteclient.exceptions.ServerErrorException;
85
import org.gvsig.remoteclient.wmts.WMTSStatus;
86
import org.gvsig.remoteclient.wmts.exception.DownloadException;
87
import org.gvsig.remoteclient.wmts.exception.WMTSException;
88
import org.gvsig.remoteclient.wmts.struct.WMTSBoundingBox;
89
import org.gvsig.remoteclient.wmts.struct.WMTSLayer;
90
import org.gvsig.remoteclient.wmts.struct.WMTSTileMatrix;
91
import org.gvsig.remoteclient.wmts.struct.WMTSTileMatrixLimits;
92
import org.gvsig.remoteclient.wmts.struct.WMTSTileMatrixSet;
93
import org.gvsig.remoteclient.wmts.struct.WMTSTileMatrixSetLink;
94
import org.gvsig.remoteclient.wmts.struct.WMTSTileMatrix.Tile;
95
import org.gvsig.tools.ToolsLocator;
96
import org.gvsig.tools.task.Cancellable;
97
import org.gvsig.tools.task.TaskStatus;
98
import org.slf4j.Logger;
99
import org.slf4j.LoggerFactory;
100
/**
101
 * Provider for WMTS service
102
 *
103
 * @author Nacho Brodin (nachobrodin@gmail.com)
104
 */
105
public class WMTSProvider extends DefaultRasterProvider implements RemoteRasterProvider, TiledRasterProvider {
106
        public static String                NAME                     = "Wmts Store";
107
        public static String                DESCRIPTION              = "Wmts Raster file";
108
        public static final String          METADATA_DEFINITION_NAME = "WmtsStore";
109
        private static Logger               logger                   = LoggerFactory.getLogger(WMTSProvider.class);
110
        public static boolean               TILED                    = true;
111
        
112
        //Los tiles se piden de forma secuencial y sin lanzar threads para ello (+Lento)
113
        public static int                   SEQUENTIAL               = 0;
114
        //Los tiles se piden en threads y hay un thread manager para gestionar que no se pidan m?s de cierto n?mero
115
        public static int                   LIMITED_THREADS          = 1;
116
        //Los tiles se piden en threads y se lanzan tantos threads como tiles haya
117
        public static int                   UNLIMITED_THREADS        = 2;
118
        private int                         requestType              = LIMITED_THREADS;
119
        
120
        private static final double         MTS_X_GRADO              = 111319.490793274;
121
        
122
        private Extent                      viewRequest              = null;
123
        private WMTSConnector               connector                = null;
124
        //private static Hashtable<URL, WMTSConnector>    
125
        //                                    drivers                  = new Hashtable<URL, WMTSConnector> ();
126
        private boolean                     open                     = false;
127
        private File                        lastRequest              = null;
128
        private DataStoreTransparency       lastFileTransparency     = null;
129
        private int                         lastWidthRequest         = 0;
130
        private int                         lastHeightRequest        = 0;
131
        private WMTSStatus                  lastStatus               = null;
132
        private boolean                     gridSubsets              = true;
133
        private Extent[]                    extentByLevel            = null; //Only for layers without gridSubsets
134
        private MathUtils                   math                     = RasterLocator.getManager().getMathUtils();
135
        
136
        /**
137
         * This thread manages the number of tiles that have been thrown.
138
         * This number is controlled by the NTHREADS_QUEUE variable.
139
         * 
140
         * @author Nacho Brodin (nachobrodin@gmail.com)
141
         */
142
        public class RequestThreadManager extends Thread {
143
                private TilePipe           pipe           = null;
144
                private ArrayList<Tile>    tiles          = null;
145
                private WMTSStatus         status         = null;
146
                
147
                public RequestThreadManager(TilePipe pipe, ArrayList<Tile> tiles, WMTSStatus status) {
148
                        this.pipe = pipe;
149
                        this.tiles = tiles;
150
                        this.status = status;
151
                }
152
                
153
                public void run() {
154
                        for (int i = 0; i < tiles.size(); i++) {
155
                                Tile tile = tiles.get(i);
156
                                WMTSStatus statusCopy = status.cloneStatus();
157
                                statusCopy.setTileRow(tile.row);
158
                                statusCopy.setTileCol(tile.col);
159
                                if (pipe.getSize() > TilePipe.NTHREADS_QUEUE) {
160
                                        try {
161
                                                synchronized (this) {
162
                                                        wait();                                                        
163
                                                }
164
                                        } catch( InterruptedException e ) {
165
                                        }
166
                                }
167
                                new RequestTileLauncher(pipe, statusCopy, tile).start();
168
                        }
169
                }
170
        }
171
        
172
        /**
173
         * Thread to download a tile
174
         * @author Nacho Brodin (nachobrodin@gmail.com)
175
         */
176
        class RequestTileLauncher extends Thread {
177
                private TilePipe      pipe    = null;
178
                private WMTSStatus    status  = null;
179
                private Tile          tile    = null;
180

    
181
                public RequestTileLauncher(TilePipe pipe, WMTSStatus status, Tile tile) {
182
                        this.pipe = pipe;
183
                        this.status = status;
184
                        this.tile = tile;
185
                }
186

    
187
                public void run() {
188
                        try {
189
                                //File file = getConnector().getTile(status, null);
190
                                URL url = getConnector().getTileURL(status);
191
                                tile.file = getConnector().downloadFile(url, null);
192
                                pipe.setTile(tile);
193
                        } catch (DownloadException e) {
194
                                logger.info("Error downloading files", e);
195
                        } catch (MalformedURLException e) {
196
                                logger.info("Malformed URL", e);
197
                        } catch (WMTSException e) {
198
                                logger.info("", e);
199
                        }
200
                }
201
        }
202
        
203
        /**
204
         * Point information 
205
         * @author Nacho Brodin (nachobrodin@gmail.com)
206
         */
207
        public class PointInfo {
208
                public Point2D worldCoord;
209
                public Point2D tile;
210
                public Point2D pixelInTile;
211
                public int     level;
212
                
213
                public PointInfo(Point2D worldCoord) {
214
                        this.worldCoord = worldCoord;
215
                }
216
        }
217

    
218
        public static void register() {
219
                DataManagerProviderServices dataman = (DataManagerProviderServices) DALLocator.getDataManager();
220
                if (dataman != null && !dataman.getStoreProviders().contains(NAME)) {
221
                        dataman.registerStoreProvider(NAME,
222
                                        WMTSProvider.class, WMTSDataParametersImpl.class);
223
                }
224

    
225
                if (!dataman.getExplorerProviders().contains(WMTSServerExplorer.NAME)) {
226
                        dataman.registerExplorerProvider(WMTSServerExplorer.NAME, WMTSServerExplorer.class, WMTSServerExplorerParameters.class);
227
                }
228
                dataman.registerStoreFactory(NAME, DefaultStoreFactory.class);
229
        }
230
        
231
        public WMTSProvider() throws NotSupportedExtensionException {
232
                super();
233
        }
234
        
235
        /**
236
         * Constructor. Abre el dataset.
237
         * @param proj Proyecci?n
238
         * @param fName Nombre del fichero
239
         * @throws NotSupportedExtensionException
240
         */
241
        public WMTSProvider(String params) throws NotSupportedExtensionException {
242
                super(params);
243
                if(params instanceof String) {
244
                        WMTSDataParameters p = new WMTSDataParametersImpl();
245
                        p.setURI((String)params);
246
                        super.init(p, null, ToolsLocator.getDynObjectManager()
247
                                        .createDynObject(
248
                                                        MetadataLocator.getMetadataManager().getDefinition(
249
                                                                        DataStore.METADATA_DEFINITION_NAME)));
250
                        init(p, null);
251
                }
252
        }
253
        
254
        public WMTSProvider(WMTSDataParameters params,
255
                        DataStoreProviderServices storeServices) throws NotSupportedExtensionException {
256
                super(params, storeServices, ToolsLocator.getDynObjectManager()
257
                                .createDynObject(
258
                                                MetadataLocator.getMetadataManager().getDefinition(
259
                                                                DataStore.METADATA_DEFINITION_NAME)));
260
                init(params, storeServices);
261
        }
262
        
263
        /**
264
         * Gets the connector from the URL
265
         * @return
266
         * @throws RemoteServiceException
267
         */
268
        public WMTSConnector getConnector() throws WMTSException {
269
                if(connector == null) {
270
                        WMTSDataParameters p = (WMTSDataParameters)parameters;
271
                        URL url = null;
272
                        try {
273
                                url = new URL(p.getURI());
274
                        } catch (Exception e) {
275
                                throw new WMTSException("Malformed URL",e);
276
                        }
277
                        try {
278
                                connector = new WMTSConnector(url);
279
                        } catch (ConnectException e) {
280
                                throw new WMTSException("Connect exception",e);
281
                        } catch (IOException e) {
282
                                throw new WMTSException("Connect exception",e);
283
                        }
284
                }
285
                return connector;
286
        }
287

    
288
        /**
289
         * Crea las referencias al fichero y carga
290
         * las estructuras con la informaci?n y los metadatos.
291
         * @param proj Proyecci?n
292
         * @param param Parametros de carga
293
         * @throws NotSupportedExtensionException
294
         */
295
        public void init (DataStoreParameters params,
296
                        DataStoreProviderServices storeServices) throws NotSupportedExtensionException {
297
                setParam(storeServices, params);
298
                if(((WMTSDataParameters)params).getImageFormat().compareTo("image/gif") == 0) {
299
                        setDataType(new int[]{Buffer.TYPE_BYTE});
300
                        bandCount = 1;
301
                } else {
302
                        setDataType(new int[]{Buffer.TYPE_BYTE, Buffer.TYPE_BYTE, Buffer.TYPE_BYTE, Buffer.TYPE_BYTE});
303
                        bandCount = 4;
304
                }
305
                
306
                if(!(param instanceof WMTSDataParameters))
307
                        return;
308
                
309
                gridSubsets = hasGridSubsets((WMTSDataParameters)param);
310
                open = true;
311
        }
312
        
313
        /**
314
         * Returns true if this layer has grid subsets
315
         * @return
316
         */
317
        public boolean hasGridSubsets() {
318
                return gridSubsets;
319
        }
320
        
321
        /**
322
         * Checks if this layer has grid subsets or doesn't
323
         * @param p
324
         * @return
325
         */
326
        @SuppressWarnings("unchecked")
327
        private boolean hasGridSubsets(WMTSDataParameters p) {
328
                ArrayList tileMatrixSetLimits = null;
329
                ArrayList<?> tileMatrixSetLinkList = p.getLayer().getTileMatrixSetLink();
330
                String srs = p.getSRSCode();
331
                for (int i = 0; i < tileMatrixSetLinkList.size(); i++) {
332
                        WMTSTileMatrixSetLink tileMatrixSetLink = (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(i);
333
                        WMTSTileMatrixSet tms = tileMatrixSetLink.getTileMatrixSet();
334
                        ArrayList tmsl = tileMatrixSetLink.getTileMatrixLimits();
335
                        String srsTileSet = tms.getSupportedCRS();
336
                        if(srsTileSet.compareTo(srs) == 0) {
337
                                tileMatrixSetLimits = tmsl;
338
                        }
339
                }
340
                
341
                return tileMatrixSetLimits.size() <= 0 ? false : true; 
342
        }
343
        
344
        /*public static final WMTSConnector getConnectorFromURL(URL url) throws IOException {
345
                WMTSConnector drv = (WMTSConnector) drivers.get(url);
346
                if (drv == null) {
347
                        drv = new WMTSConnector(url);
348
                        drivers.put(url, drv);
349
                }
350
                return drv;
351
        }*/
352
        
353
        /**
354
         * Obtiene el objeto que contiene que contiene la interpretaci?n de
355
         * color por banda
356
         * @return
357
         */
358
        public ColorInterpretation getColorInterpretation() {
359
                if(super.getColorInterpretation() == null) {
360
                        ColorInterpretation colorInterpretation = new DataStoreColorInterpretation();
361
                        colorInterpretation.initColorInterpretation(getBandCount());
362
                        if(getBandCount() >= 3) {
363
                                colorInterpretation.setColorInterpValue(0, DataStoreColorInterpretation.RED_BAND);
364
                                colorInterpretation.setColorInterpValue(1, DataStoreColorInterpretation.GREEN_BAND);
365
                                colorInterpretation.setColorInterpValue(2, DataStoreColorInterpretation.BLUE_BAND);
366
                        }
367
                        if(getBandCount() == 4)
368
                                colorInterpretation.setColorInterpValue(3, DataStoreColorInterpretation.ALPHA_BAND);
369
                        if(getBandCount() > 4 || getBandCount() < 3) {
370
                                for (int i = 0; i < getBandCount(); i++) {
371
                                        colorInterpretation.setColorInterpValue(i, DataStoreColorInterpretation.UNDEF_BAND);
372
                                }
373
                        }
374
                        setColorInterpretation(colorInterpretation);
375
                }
376
                return super.getColorInterpretation();
377
        }
378
        
379
        /*
380
         * (non-Javadoc)
381
         * @see org.gvsig.raster.impl.provider.RasterProvider#isTiled()
382
         */
383
        public boolean isTiled() {
384
                return true;
385
        }
386
        
387
        /*
388
         * (non-Javadoc)
389
         * @see org.gvsig.fmap.dal.coverage.dataset.RasterDataSet#getAffineTransform()
390
         */
391
        public AffineTransform getAffineTransform() {
392
                WMTSDataParameters p = (WMTSDataParameters)parameters;
393
                Extent e = getExtent();
394
                double psX = e.width() / (lastWidthRequest <= 0 ? p.getWidth() : lastWidthRequest);
395
                double psY = -(e.height() / (lastHeightRequest <= 0 ? p.getHeight() : lastHeightRequest));
396
                ownTransformation = new AffineTransform(
397
                                psX, 
398
                                0, 
399
                                0, 
400
                                psY, 
401
                                e.getULX() - (psX / 2),
402
                                e.getULY() - (psY / 2));
403
                externalTransformation = (AffineTransform) ownTransformation.clone();
404
                return ownTransformation;
405
        }
406
        
407
        /**
408
         * Gets the bounding box in world coordinates. If the layer has grid subsets (TileMatrixLimits) then
409
         * this will have a only extent but if the layer doesn't have grid subsets then this will have a different
410
         * extent in each level resolution. In this case we need to know the extent for each level.
411
         * @return Extent
412
         */
413
        public Extent getExtent() {
414
                WMTSDataParameters p = (WMTSDataParameters)parameters;
415
                if(gridSubsets) {
416
                        WMTSLayer layer = p.getLayer();
417
                        WMTSBoundingBox bbox = layer.getWGS84BBox();
418
                        return new ExtentImpl(bbox.toRectangle2D());
419
                } else {
420
                        WMTSTileMatrixSet tileMatrixSet = getTileMatrixSetLink().getTileMatrixSet();
421
                        
422
                        //Si ya se han calculado los niveles es q el extent es v?lido sino el nivel ser? el 0
423
                        double scale = 0D;
424
                        int level = 0;
425
                        if(extentByLevel != null && p.getExtent() != null) {
426
                                scale = getScale(p.getExtent(), p.getWidth());
427
                                try {
428
                                        level = getLevelFromScale(scale, tileMatrixSet);
429
                                } catch (RasterDriverException e) {
430
                                        e.printStackTrace();
431
                                }                                
432
                        }
433
                        
434
                        Extent[] ext = getExtentByResolutionLevel();
435
                        
436
                        if(ext != null && level >= 0 && level < ext.length)
437
                                return ext[level];
438
                }
439
                return null;
440
        }
441
        
442
        /**
443
         * Gets the suffix of the downloaded image
444
         * @return
445
         */
446
        public String getFileSuffix() {
447
                WMTSDataParameters p = (WMTSDataParameters)parameters;
448
                String format = p.getImageFormat();
449
                if (format == null){
450
                        return "xml";
451
                }
452
                if (format.indexOf("png") >= 0){
453
                return "png";
454
                }        
455
            if (format.indexOf("xml") >= 0){
456
                return "xml";
457
            }        
458
            if (format.indexOf("gif") >= 0){
459
                return "gif";
460
            }
461
            if (format.indexOf("tif") >= 0){
462
                return "tif";
463
            }
464
            if (format.indexOf("bmp") >= 0){
465
                return "bmp";
466
            }
467
            if (format.indexOf("jpg") >= 0
468
                || format.indexOf("jpeg") >= 0){
469
                return "jpg";                         
470
            }
471
                return "xml";
472
        }
473

    
474
        /**
475
         * When a layer doesn't have grid subsets this will have a different bounding
476
         * box by resolution level. This function calculates and returns the array of
477
         * extents, one by resolution level.
478
         * @return
479
         */
480
        public Extent[] getExtentByResolutionLevel() {
481
                if(extentByLevel == null) {
482
                        WMTSDataParameters p = (WMTSDataParameters)parameters;
483
                        WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
484
                        WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
485
                        
486
                    double widthMtsTile = 0;
487
                    double heightMtsTile = 0;
488
                        ArrayList<?> tileMatrixList = tileMatrixSet.getTileMatrix();
489
                        extentByLevel = new ExtentImpl[tileMatrixList.size()];
490
                        for (int i = 0; i < tileMatrixList.size(); i++) {
491
                                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixList.get(i);
492
                            if(!p.isProjected()) {
493
                                    widthMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / (MTS_X_GRADO * 1000);
494
                                    heightMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / (MTS_X_GRADO * 1000);
495
                            } else {
496
                                    widthMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / 1000;
497
                                    heightMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / 1000;
498
                            }
499
                            
500
                            double h = Math.abs(tileMatrix.getTopLeftCorner()[0] - (tileMatrix.getTopLeftCorner()[0] - (tileMatrix.getMatrixHeight() * heightMtsTile)));
501
                            Rectangle2D r = new Rectangle2D.Double(
502
                                            tileMatrix.getTopLeftCorner()[1], 
503
                                            tileMatrix.getTopLeftCorner()[0] - h,
504
                                            Math.abs(tileMatrix.getTopLeftCorner()[1] - (tileMatrix.getTopLeftCorner()[1] + (tileMatrix.getMatrixWidth() * widthMtsTile))),
505
                                            h);
506
                            extentByLevel[i] = new ExtentImpl(r);
507
                        }
508
                        
509
                }
510
                return extentByLevel;
511
        }
512
        
513
        /*
514
         * (non-Javadoc)
515
         * @see org.gvsig.raster.impl.provider.RemoteRasterProvider#getLayerExtent(java.lang.String, java.lang.String)
516
         */
517
        public Rectangle2D getLayerExtent(String layerName, String srs) throws RemoteServiceException {
518
                return null;
519
        }
520

    
521
        /*
522
         * (non-Javadoc)
523
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#load()
524
         */
525
        public RasterProvider load() {
526
                return this;
527
        }
528
        
529
        /*
530
         * (non-Javadoc)
531
         * @see org.gvsig.raster.impl.provider.RasterProvider#isOpen()
532
         */
533
        public boolean isOpen() {
534
                return open;
535
        }
536

    
537
        /*
538
         * (non-Javadoc)
539
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#close()
540
         */
541
        public void close() {
542
                open = false;
543
        }
544
        
545
        /*
546
         * (non-Javadoc)
547
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getTransparency()
548
         */
549
        public Transparency getTransparency() {
550
                if(lastFileTransparency == null) {
551
                        lastFileTransparency = new DataStoreTransparency();
552
                        lastFileTransparency.setTransparencyBand(3);
553
                }
554
                return lastFileTransparency;
555
        }
556

    
557
        /*
558
         * (non-Javadoc)
559
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#translateFileName(java.lang.String)
560
         */
561
        public String translateFileName(String fileName) {
562
                return fileName;
563
        }
564

    
565
        /*
566
         * (non-Javadoc)
567
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#setView(org.gvsig.fmap.dal.coverage.datastruct.Extent)
568
         */
569
        public void setView(Extent e) {
570
                viewRequest = e;
571
        }
572

    
573
        /*
574
         * (non-Javadoc)
575
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getView()
576
         */
577
        public Extent getView() {
578
                return viewRequest;
579
        }
580

    
581
        /*
582
         * (non-Javadoc)
583
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWidth()
584
         */
585
        public double getWidth() {
586
                WMTSDataParameters p = (WMTSDataParameters)parameters;
587
                if (lastWidthRequest <= 0) 
588
                        return p.getWidth();
589
                return lastWidthRequest;
590
        }
591

    
592
        /*
593
         * (non-Javadoc)
594
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getHeight()
595
         */
596
        public double getHeight() {
597
                WMTSDataParameters p = (WMTSDataParameters)parameters;
598
                if (lastHeightRequest <= 0) 
599
                        return p.getHeight();
600
                return lastHeightRequest;
601
        }
602

    
603
        /*
604
         * (non-Javadoc)
605
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#readCompleteLine(int, int)
606
         */
607
        public Object readCompleteLine(int line, int band)
608
                throws InvalidSetViewException, FileNotOpenException, RasterDriverException {
609
                return null;
610
        }
611
        
612
        /**
613
         * When the remote layer has fixed size this method downloads the file and return its reference. 
614
         * File layer has in the long side FIXED_SIZE pixels and the bounding box is complete. This file could be
615
         * useful to build an histogram or calculate statistics. This represents a sample of data.
616
         * @return
617
         * @throws RasterDriverException
618
         */
619
        public File getFileLayer() throws RasterDriverException {
620
                return null;
621
        }
622

    
623
        /**
624
         * Reads a complete block of data and returns an tridimensional array of the right type. This function is useful
625
         * to read a file very fast without setting a view. In a WMTS service when the size is fixed then it will read the
626
         * entire image but when the source hasn't pixel size it will read a sample of data. This set of data will have
627
         * the size defined in FIXED_SIZE. 
628
         * 
629
         * @param pos Posici?n donde se empieza  a leer
630
         * @param blockHeight Altura m?xima del bloque leido
631
         * @return Object que es un array tridimendional del tipo de datos del raster. (Bandas X Filas X Columnas)
632
         * @throws InvalidSetViewException
633
         * @throws FileNotOpenException
634
         * @throws RasterDriverException
635
         */
636
        public Object readBlock(int pos, int blockHeight, double scale) 
637
        throws InvalidSetViewException, FileNotOpenException, RasterDriverException, ProcessInterruptedException {
638
                return null;
639
        }
640
        
641
        /*
642
         * (non-Javadoc)
643
         * @see org.gvsig.raster.impl.provider.RemoteRasterProvider#getLastRequestHeight()
644
         */
645
        public double getLastRequestHeight() throws RasterDriverException {
646
                return 0;
647
        }
648
        
649
        /*
650
         * (non-Javadoc)
651
         * @see org.gvsig.raster.impl.provider.RemoteRasterProvider#getLastRequestWidth()
652
         */
653
        public double getLastRequestWidth() throws RasterDriverException {
654
                return 0;
655
        }
656

    
657
        /*
658
         * (non-Javadoc)
659
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getData(int, int, int)
660
         */
661
        public Object getData(int x, int y, int band)
662
                throws InvalidSetViewException, FileNotOpenException, RasterDriverException {
663
                return null;
664
        }
665
        
666
        /**
667
         * Assigns the list of bands RGB and read a window of data
668
         * @param rasterBuf
669
         * @param bandList
670
         * @param lastFile
671
         * @param ulx
672
         * @param uly
673
         * @param lrx
674
         * @param lry
675
         * @return
676
         * @throws RasterDriverException
677
         * @throws ProcessInterruptedException
678
         */
679
        public Buffer getBuffer(Buffer rasterBuf, BandList bandList, File lastFile, 
680
                        double ulx, double uly, double lrx, double lry) throws RasterDriverException, ProcessInterruptedException {
681
                return null;
682
        }
683
        
684
        /**
685
         * Gets the tile matrix from the selected level
686
         * @param level
687
         * @return
688
         */
689
        @SuppressWarnings("unchecked")
690
        private WMTSTileMatrix getTileMatrixByLevel(int level) {
691
                level = adjustLevel(level);
692
                
693
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
694
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
695
                ArrayList tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
696
                
697
                WMTSTileMatrixLimits tileMatrixLimits = null;
698
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(level);
699
                if(hasGridSubsets()) {
700
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(level);
701
                        tileMatrix = tileMatrixLimits.getTileMatrix();
702
                }
703
                return tileMatrix;
704
        }
705
        
706
        /**
707
         * Returns the number of levels
708
         * @return
709
         */
710
        @SuppressWarnings("unchecked")
711
        public int getZoomLevels() {
712
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
713
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
714
                if(hasGridSubsets()) {
715
                        ArrayList tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
716
                        return Math.min(tileMatrixSet.getTileMatrix().size(), tileMatrixSetLimits.size());
717
                }
718
                return tileMatrixSet.getTileMatrix().size();
719
                
720
        }
721
        
722
        /*
723
         * (non-Javadoc)
724
         * @see org.gvsig.raster.impl.provider.RasterProvider#getCoordsInTheNearestLevel(org.gvsig.fmap.dal.coverage.datastruct.Extent, int, int)
725
         */
726
        public Extent getCoordsInTheNearestLevel(Extent extent, int w, int h) {
727
                double[] pixelSizes = getPixelSizeByLevel();
728
                double currentPixelSize = extent.width() / (double)w;
729
                
730
                int level = 0;
731
                for (int i = 0; i < (pixelSizes.length - 1); i++) {
732
                        if(currentPixelSize < pixelSizes[i] && currentPixelSize >= pixelSizes[i + 1]) {
733
                                level = i + 1;
734
                                break;
735
                        }
736
                }
737
                
738
                return getZoomLevelCoordinates(level, extent, w, h);
739
        }
740
        
741
        /*
742
         * (non-Javadoc)
743
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getCoordsInLevel(java.awt.geom.Point2D, int, int, int)
744
         */
745
        public Extent getCoordsInLevel(Point2D viewCenter, int level, int w, int h) {
746
                WMTSDataParameters p = (WMTSDataParameters)param;
747
                level = adjustLevel(level);
748
                WMTSTileMatrix tileMatrix = getTileMatrixByLevel(level);
749
                
750
                boolean proj = p.isProjected();
751
                
752
                double psX = tileMatrix.getWidthMtsTile(proj) / tileMatrix.getTileWidth();
753
                double psY = tileMatrix.getHeightMtsTile(proj) / tileMatrix.getTileHeight();
754
                
755
                double ulx = viewCenter.getX() - ((w / 2) * psX);
756
                double uly = viewCenter.getY() - ((h / 2) * psY);
757
                double lrx = ulx + (w * psX);
758
                double lry = uly + (h * psY);
759
                return new ExtentImpl(ulx, uly, lrx, lry);
760
        }
761
        
762
        /**
763
         * Calculates the extent of a zoom level using other extent as a reference. The new extent is 
764
         * calculated with the same coordinate at the center. 
765
         * @param level
766
         * @param extent
767
         * @param w
768
         * @param h
769
         * @return
770
         */
771
        public Extent getZoomLevelCoordinates(int level, Extent extent, int w, int h) {
772
                double centerX = extent.getCenterX();
773
                double centerY = extent.getCenterY();
774
                return getCoordsInLevel(new Point2D.Double(centerX, centerY), level, w, h);
775
        }
776
        
777
        /**
778
         * Returns a list of pixel sizes by level
779
         * @return
780
         */
781
        public double[] getPixelSizeByLevel() {
782
                WMTSDataParameters p = (WMTSDataParameters)param;
783
                double[] list = new double[getZoomLevels()];
784
                
785
                for (int i = 0; i < getZoomLevels(); i++) {
786
                        WMTSTileMatrix tileMatrix = getTileMatrixByLevel(i);
787
                        list[i] = math.adjustDouble(tileMatrix.getWidthMtsTile(p.isProjected()) / tileMatrix.getTileWidth());
788
                }
789
                return list;
790
        }
791
        
792
        /**
793
         * Adjust de level to the range
794
         * @param level
795
         * @return
796
         */
797
        private int adjustLevel(int level) {
798
                if(level < 0)
799
                        level = 0;
800
                if(level > getZoomLevels())
801
                        level = getZoomLevels();
802
                return level;
803
        }
804
        
805
        /*
806
         * (non-Javadoc)
807
         * @see org.gvsig.raster.impl.provider.TiledRasterProvider#getTile(int, int, int, org.gvsig.fmap.dal.coverage.datastruct.Extent)
808
         */
809
        public org.gvsig.raster.cache.tile.Tile getTile(DefaultRasterQuery q) throws TileGettingException {
810
                //q.getResolutionLevel(), q.getTileCol(), q.getTileRow(), q.getBBox(), q.getCacheStruct()!
811
                
812
                CacheStruct str = getTileServer().getStruct();
813
                
814
                //1-Selecci?n de WMTSTileMatrixSet por srs
815
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
816
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
817
                ArrayList<?> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
818
                
819
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(q.getResolutionLevel());
820
                if(gridSubsets) {
821
                        WMTSTileMatrixLimits tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(q.getResolutionLevel());
822
                        tileMatrix = tileMatrixLimits.getTileMatrix();
823
                }
824
                int bufWidth = tileMatrix.getTileWidth();
825
                int bufHeight = tileMatrix.getTileHeight();
826
                
827
                try {
828
                        Rectangle2D r = q.getBBox().toRectangle2D();//new Rectangle2D.Double(Math.min(minX, maxX), Math.min(minY, maxY), Math.abs(maxX - minX), Math.abs(maxY - minY));
829
                        WMTSStatus status = buildWMTSStatus(r, bufWidth , bufHeight);
830
                        
831
                        int[] size = str.getTileSizeByLevel(q.getResolutionLevel());
832
                        Tile tile = tileMatrix.new Tile(size[0], size[1], 
833
                                        q.getTileRow(), q.getTileCol(), 
834
                                        q.getBBox().getULX(), q.getBBox().getULY(), q.getBBox().getLRX(), q.getBBox().getLRY());
835
                        
836
                        File file = getConnector().getTile(status, null);
837
                        tile.file = file;
838
                        //Creamos un BandList con todas las bandas del fichero
839
                        BandList bandList = new BandListImpl();
840
                        for(int i = 0; i < getBandCount(); i++) {
841
                                try {
842
                                        DatasetBand band = new DatasetBandImpl(getURIOfFirstProvider(), i, getDataType()[i], getBandCount());
843
                                        bandList.addBand(band, i);
844
                                } catch(BandNotFoundInListException e) {
845
                                        //No a?adimos la banda
846
                                }
847
                        }
848
                        return drawTile(tile, null, bandList);
849
                } catch (WMTSException e) {
850
                        throw new TileGettingException("Error getting tiles", e);
851
                } catch (ServerErrorException e) {
852
                        throw new TileGettingException("Error getting tiles", e);
853
                } catch (RasterDriverException e) {
854
                        throw new TileGettingException("Error getting tiles", e);
855
                }
856
        }
857
        
858
        /*
859
         * (non-Javadoc)
860
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(double, double, double, double, int, int, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer, org.gvsig.fmap.dal.coverage.grid.render.TileListener, int)
861
         */
862
        public void getWindow(Extent ex, int bufWidth, int bufHeight, 
863
                        BandList bandList, TileListener listener, Cancellable taskStatus) throws ProcessInterruptedException, RasterDriverException {
864
                Rectangle2D r = ex.toRectangle2D();//new Rectangle2D.Double(Math.min(minX, maxX), Math.min(minY, maxY), Math.abs(maxX - minX), Math.abs(maxY - minY));
865
                WMTSStatus status = buildWMTSStatus(r, bufWidth, bufHeight);
866
                request(status, bandList, listener, requestType);
867
        }
868
        
869
        /*
870
         * (non-Javadoc)
871
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(double, double, double, double, int, int, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer, boolean)
872
         */
873
        public Buffer getWindow(Extent extent, int bufWidth, int bufHeight, 
874
                        BandList bandList, Buffer rasterBuf, boolean adjustToExtent, TaskStatus taskStatus) throws ProcessInterruptedException, RasterDriverException {
875
                Rectangle2D r = extent.toRectangle2D();//new Rectangle2D.Double(Math.min(ulx, lrx), Math.min(lry, uly), Math.abs(lrx - ulx), Math.abs(uly - lry));
876
                WMTSStatus status = buildWMTSStatus(r, bufWidth, bufHeight);
877
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, bandList, null, requestType);
878
                MemoryMatrixBuffer matrixBuffer = new MemoryMatrixBuffer(tileList);
879
                return matrixBuffer.getWindow(extent, rasterBuf);
880
        }
881
        
882
        /*
883
         * (non-Javadoc)
884
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(org.gvsig.fmap.dal.coverage.datastruct.Extent, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer)
885
         */
886
        public Buffer getWindow(Extent extent, BandList bandList, Buffer rasterBuf, TaskStatus taskStatus) 
887
                throws ProcessInterruptedException, RasterDriverException {
888
                lastWidthRequest = rasterBuf.getWidth();
889
                lastHeightRequest = rasterBuf.getHeight();
890
                Rectangle2D r = extent.toRectangle2D();//new Rectangle2D.Double(Math.min(ulx, lrx), Math.min(lry, uly), Math.abs(lrx - ulx), Math.abs(uly - lry));
891
                WMTSStatus status = buildWMTSStatus(r, lastWidthRequest, lastHeightRequest);
892
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, bandList, null, requestType);
893
                MemoryMatrixBuffer matrixBuffer = new MemoryMatrixBuffer(tileList);
894
                return matrixBuffer.getWindow(extent, rasterBuf);
895
        }
896

    
897
        /*
898
         * (non-Javadoc)
899
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(double, double, double, double, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer, boolean)
900
         */
901
        public Buffer getWindow(double ulx, double uly, double w, double h, 
902
                        BandList bandList, Buffer rasterBuf, boolean adjustToExtent, TaskStatus taskStatus) throws ProcessInterruptedException, RasterDriverException {
903
                lastWidthRequest = rasterBuf.getWidth();
904
                lastHeightRequest = rasterBuf.getHeight();
905
                Rectangle2D r = new Rectangle2D.Double(ulx, uly - h, w, h);
906
                WMTSStatus status = buildWMTSStatus(r, lastWidthRequest, lastHeightRequest);
907
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, bandList, null, requestType);
908
                MemoryMatrixBuffer matrixBuffer = new MemoryMatrixBuffer(tileList);
909
                return matrixBuffer.getWindow(new ExtentImpl(ulx, uly, ulx + w, uly - h), rasterBuf);
910
        }
911

    
912
        /*
913
         * (non-Javadoc)
914
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(int, int, int, int, int, int, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer)
915
         */
916
        public Buffer getWindow(int x, int y, int w, int h, BandList bandList, Buffer rasterBuf, TaskStatus status) throws ProcessInterruptedException, RasterDriverException {
917
                lastWidthRequest = rasterBuf.getWidth();
918
                lastHeightRequest = rasterBuf.getHeight();
919
                return null;
920
        }
921
        
922
        /**
923
         * Gets the information from a point 
924
         * @param wcx
925
         * @param wcy
926
         * @param level
927
         * @return
928
         * @throws RasterDriverException
929
         */
930
        public String getFeatureInfo(double wcx, double wcy, int level) throws RasterDriverException {
931
                PointInfo pointInfo = new PointInfo(new Point2D.Double(wcx, wcy));
932
                pointInfo.level = level;
933
                getTileInfo(pointInfo);
934
                
935
                WMTSConnector connector = null;
936
                try {
937
                        connector = getConnector();
938
                        lastStatus.setTileRow((int)pointInfo.tile.getX());
939
                        lastStatus.setTileCol((int)pointInfo.tile.getY());
940
                        
941
                        String fi = connector.getFeatureInfo(lastStatus, (int)pointInfo.pixelInTile.getX(), (int)pointInfo.pixelInTile.getY(), null);
942
                        return fi;
943
                } catch (WMTSException e) {
944
                        throw new RasterDriverException("Error getting the connector object", e);
945
                } catch (ServerErrorException e) {
946
                        throw new RasterDriverException("Error getting the connector object", e);
947
                }
948
        }
949
        
950
        /**
951
         * Gets a tile position from a world coordinates point and a resolution level
952
         * @param point
953
         * @param level
954
         * @return An array with two elements. The first is the row and the second the column
955
         * of the tile in the tile matrix
956
         */
957
        @SuppressWarnings({ "unchecked"})
958
        private void getTileInfo(PointInfo pointInfo) {
959
                WMTSDataParameters p = (WMTSDataParameters)param;
960
                
961
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
962
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
963
                ArrayList tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
964
                
965
                WMTSTileMatrixLimits tileMatrixLimits = null;
966
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(pointInfo.level);
967
                if(hasGridSubsets()) {
968
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(pointInfo.level);
969
                        tileMatrix = tileMatrixLimits.getTileMatrix();
970
                }
971
                
972
                ArrayList<Tile> tiles = null;
973
                if(hasGridSubsets())
974
                        tiles = tileMatrix.contains(p.isProjected(), tileMatrixLimits, pointInfo.worldCoord, getExtent().toRectangle2D());
975
                else
976
                        tiles = tileMatrix.contains(p.isProjected(), pointInfo.worldCoord, getExtent().toRectangle2D());
977
                
978
                //Tile row and column
979
                pointInfo.tile = new Point2D.Double(tiles.get(0).row, tiles.get(0).col);
980
                
981
                //Desplazamiento en pixels dentro del tile
982
                Point2D rasterPoint = tiles.get(0).worldToRaster(pointInfo.worldCoord);
983
                pointInfo.pixelInTile = new Point2D.Double(rasterPoint.getX(), rasterPoint.getY());
984
        }
985
        
986
        /**
987
         * Builds the WMTSStatus object using the parameters and the request bounding box. 
988
         * @param r
989
         * @param bufWidth
990
         * @return
991
         * @throws RasterDriverException
992
         */
993
        @SuppressWarnings("unchecked")
994
        public WMTSStatus buildWMTSStatus(Rectangle2D r, int bufWidth, int bufHeight) throws RasterDriverException {
995
                WMTSDataParameters p = (WMTSDataParameters)param;
996
                
997
                //Mantiene actualizados los par?metros del WMTSStoreParameters con la ?ltima petici?n hecha
998
                p.setExtent(r);
999
                p.setWidth(bufWidth);
1000
                p.setHeight(bufHeight);
1001
                
1002
                lastWidthRequest = bufWidth;
1003
                lastHeightRequest = bufHeight;
1004
                
1005
                //1-Selecci?n de WMTSTileMatrixSet por srs
1006
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
1007
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
1008
                ArrayList tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
1009
                int initialLevel = p.getLayer().getInitialLevel(tileMatrixSet.getIdentifier());
1010
                
1011
                //Esto hace lo mismo que getScale y getLevelFromScale
1012
                /*int level = 0;
1013
                double[] pixelSizes = getPixelSizeByLevel();
1014
                double psViewPort = math.adjustDouble(r.getWidth() / (double)bufWidth);
1015
                for (int i = 0; i < pixelSizes.length - 1; i++) {
1016
                        if(psViewPort <= pixelSizes[i] && psViewPort > pixelSizes[i + 1]) {
1017
                                level = i;
1018
                                break;
1019
                        }
1020
                }*/
1021
                
1022
                //2-Calculo de la escala
1023
                double scale = getScale(r, bufWidth);
1024
                
1025
                //3-Selecci?n del nivel a partir de la escala
1026
                int level = getLevelFromScale(scale, tileMatrixSet);
1027
                
1028
                //Para evitar que se salga del array si la capa tiene menos niveles que el tilematrixset
1029
                int dif = 0;
1030
                if(gridSubsets)
1031
                        dif = (level - initialLevel) >= tileMatrixSetLimits.size() ?  (level - initialLevel) - tileMatrixSetLimits.size() + 1 : 0;
1032
                
1033
                //4-Obtenemos la matriz de tiles y los l?mites si tiene subsets
1034
                WMTSTileMatrixLimits tileMatrixLimits = null;
1035
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(level - dif);
1036
                if(gridSubsets)
1037
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(level - initialLevel - dif);
1038
                
1039
                //5-Selecci?n de tiles que entran en esta bounding box
1040
                ArrayList<Tile> tiles = null;
1041
                if(gridSubsets)
1042
                        tiles = tileMatrix.intersects(p.isProjected(), tileMatrixLimits, r, getExtent().toRectangle2D());
1043
                else
1044
                        tiles = tileMatrix.intersects(p.isProjected(), r, getExtent().toRectangle2D());
1045
                
1046
                //6-Petici?n
1047
                WMTSStatus status = new WMTSStatus();
1048
                status.setTileList(tiles);
1049
                status.setLayer(p.getLayer().getIdentifier());//.substring(p.getLayer().getIdentifier().indexOf("_") + 1));
1050
                status.setFormat(p.getImageFormat());
1051
                status.setInfoFormat(p.getInfoFormat());
1052
                status.setStyle(p.getStyle() != null ? p.getStyle().getIdentifier() : "");
1053
                status.setTileMatrixSet(tileMatrixSet.getIdentifier());
1054
                status.setTileMatrix(tileMatrix.getIdentifier());
1055
                status.setLevel(level - dif);
1056
                this.lastStatus = status;
1057
                return status;
1058
        }
1059
        
1060
        /**
1061
         * Gets the resolution level from the real coordinates
1062
         * @param r
1063
         * @param 
1064
         * @return
1065
         * @throws RasterDriverException
1066
         */
1067
        public int getLevelFromRealCoords(Rectangle2D r, int width) throws RasterDriverException {
1068
                double scale = getScale(r, width);
1069
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
1070
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
1071
                return getLevelFromScale(scale, tileMatrixSet);
1072
        }
1073
        
1074
        /**
1075
         * Gets the resolution level from the scale
1076
         * @param scale
1077
         * @param tileMatrixSet
1078
         * @return
1079
         * @throws RasterDriverException
1080
         */
1081
        public int getLevelFromScale(double scale, WMTSTileMatrixSet tileMatrixSet) throws RasterDriverException {
1082
                //Recorremos los tileMatrix para obtener la escala m?s aproximada
1083
                int levelModifier = 0;
1084
                scale = math.adjustDouble(scale);
1085
                try {
1086
                        for (int resolutionLevel = 0; resolutionLevel < tileMatrixSet.getTileMatrix().size(); resolutionLevel++) {
1087
                                WMTSTileMatrix tm = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(resolutionLevel);
1088
                                double scaleDenominator = math.adjustDouble(tm.getScaleDenominator());
1089
                                if(scale >= scaleDenominator) {
1090
                                        return Math.max(resolutionLevel + levelModifier, 0);
1091
                                }
1092
                        }
1093
                } catch (IndexOutOfBoundsException e) {
1094
                        throw new RasterDriverException("Error in this resolution level", e);
1095
                }
1096
                return 0;
1097
        }
1098
        
1099
        /**
1100
         * Get the tile matrix set using the crs
1101
         * @param srs
1102
         * @return
1103
         */
1104
        public WMTSTileMatrixSetLink getTileMatrixSetLink() {
1105
                WMTSDataParameters p = (WMTSDataParameters)param;
1106
                ArrayList<?> tileMatrixSetLinkList = p.getLayer().getTileMatrixSetLink();
1107
                for (int i = 0; i < tileMatrixSetLinkList.size(); i++) {
1108
                        WMTSTileMatrixSetLink tileMatrixSetLink = (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(i);
1109
                        String srsTileSet = tileMatrixSetLink.getTileMatrixSet().getSupportedCRS();
1110
                        if(srsTileSet.compareTo(p.getSRSCode()) == 0) {
1111
                                return tileMatrixSetLink;
1112
                        }
1113
                }
1114
                if(tileMatrixSetLinkList != null && tileMatrixSetLinkList.size() > 0)
1115
                        return (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(0);
1116
                return null;
1117
        }
1118
        
1119
        /**
1120
         * Gets the scale using the extent and the width in pixels.
1121
         * @param r
1122
         * @param width
1123
         * @return
1124
         */
1125
        private double getScale(Rectangle2D r, int width) {
1126
                WMTSDataParameters p = (WMTSDataParameters)param;
1127
                if(!p.isProjected()) {
1128
                        return (1000 * r.getWidth() * MTS_X_GRADO) / (width * 0.28);
1129
                } else
1130
                        return (1000 * r.getWidth()) / (width * 0.28);
1131
        }
1132
        
1133
        /**
1134
         * Throw a request
1135
         * @param status
1136
         * @param bandList
1137
         * @param listener
1138
         * @param alphaBandNumber 
1139
         * @return returns a buffer if the listener is null. In any other case it return null.
1140
         * @throws RasterDriverException 
1141
         * @throws ProcessInterruptedException 
1142
         */
1143
        @SuppressWarnings("unchecked")
1144
        private synchronized org.gvsig.raster.cache.tile.Tile[] request(
1145
                        WMTSStatus status, BandList bandList, TileListener listener, int requestType) throws RasterDriverException, ProcessInterruptedException {
1146
                //WMTSDataParameters p = (WMTSDataParameters)param;
1147
                WMTSConnector connector = null;
1148
                try {
1149
                        connector = getConnector();
1150
                } catch (WMTSException e) {
1151
                        throw new RasterDriverException("Error getting the connector object", e);
1152
                }
1153
                
1154
                if(connector == null)
1155
                        throw new RasterDriverException("Error getting the connector object");
1156
                
1157
                ArrayList<Tile> tiles = status.getTileList();
1158
                
1159
                TilePipe pipe = new TilePipe();
1160
                //TilePipe2 pipe = new TilePipe2();
1161
                //TileThreadPool pool = null;
1162
                
1163
                //Caso 1: Lanza un thread que gestiona que no se lancen muchos threads a la vez
1164
                if(requestType == LIMITED_THREADS) {
1165
                        RequestThreadManager threadManager = new RequestThreadManager(pipe, tiles, status);
1166
                        pipe.setRequestManager(threadManager);
1167
                        threadManager.start();
1168
                //Caso 2: Lanza todos los threads
1169
                } else if(requestType == UNLIMITED_THREADS) {
1170
                        for (int i = 0; i < tiles.size(); i++) {
1171
                                Tile tile = tiles.get(i);
1172
                                WMTSStatus statusCopy = status.cloneStatus();
1173
                                statusCopy.setTileRow(tile.row);
1174
                                statusCopy.setTileCol(tile.col);
1175
                                new RequestTileLauncher(pipe, statusCopy, tile).start();
1176
                        }
1177
                }
1178
                
1179
                org.gvsig.raster.cache.tile.Tile[] tileList = new org.gvsig.raster.cache.tile.Tile[tiles.size()]; 
1180
                
1181
                if(requestType == LIMITED_THREADS || requestType == UNLIMITED_THREADS) {
1182
                        int nCollected = 0;
1183
                        while (nCollected < tiles.size()) {
1184
                                Tile tile = pipe.getTile();
1185
                                tileList[nCollected] = drawTile(tile, listener, bandList);
1186
                                nCollected ++;
1187
                        }
1188
                }
1189
                
1190
                if(requestType == SEQUENTIAL) {
1191
                        for (int i = 0; i < tiles.size(); i++) {
1192
                                Tile tile = tiles.get(i);
1193
                                status.setTileRow(tile.row);
1194
                                status.setTileCol(tile.col);
1195
                                //TODO:Cancelaci?n
1196
                                try {
1197
                                        File file = connector.getTile(status, null);
1198
                                        tile.file = file;
1199
                                        tileList[i] = drawTile(tile, listener, bandList);
1200
                                } catch (WMTSException e) {
1201
                                        throw new RasterDriverException("Error getting tiles", e);
1202
                                } catch (ServerErrorException e) {
1203
                                        throw new RasterDriverException("Error getting tiles", e);
1204
                                }
1205
                        }
1206
                }
1207
                if(listener != null) 
1208
                        listener.endReading();
1209
                
1210
                return tileList;
1211
        }
1212
        
1213
        /**
1214
         * Reads a tile with gdal and calls the method nextBuffer
1215
         * @param tile
1216
         * @param listener
1217
         * @param bandList
1218
         * @return
1219
         * @throws RasterDriverException
1220
         */
1221
        private synchronized org.gvsig.raster.cache.tile.Tile drawTile(Tile tile, TileListener listener, BandList bandList) throws RasterDriverException {
1222
                WMTSDataParameters p = (WMTSDataParameters)param;
1223
                try {
1224
                        String serverName = bandList.getBand(0).getFileName();
1225
                        for (int j = 0; j < bandList.getBandCount(); j++) {
1226
                                bandList.getBand(j).setFileName(tile.file.getPath());
1227
                        }
1228
                        
1229
                        DefaultRasterProvider driver = DefaultProviderServices.loadProvider(tile.file);
1230
                        colorTable = driver.getColorTable();
1231
                        bandCount = driver.getBandCount();
1232
                        lastFileTransparency = (DataStoreTransparency)driver.getTransparency();
1233
                        Buffer rasterBuf = DefaultRasterManager.getInstance().createBuffer(getDataType()[0], tile.wPx, tile.hPx, 3, true);
1234
                        
1235
                        DefaultRasterQuery q = (DefaultRasterQuery)RasterLocator.getManager().createQuery();
1236
                        q.setAreaOfInterest(0, 0, tile.wPx, tile.hPx);
1237
                        q.setBandList(bandList);
1238
                        q.setBuffer(rasterBuf);
1239
                        Buffer buf = driver.getDataSet(q);
1240
                        
1241
                        buf.setDataExtent(new Rectangle2D.Double(Math.min(tile.ulx, tile.lrx), Math.min(tile.uly, tile.lry), Math.abs(tile.ulx - tile.lrx), Math.abs(tile.uly - tile.lry)));
1242
                        
1243
                        Buffer alphaBand = null;
1244
                        if(p.getAlphaBand() != -1 && listener != null && p.getAlphaBand() < bandCount) {
1245
                                alphaBand = DefaultRasterManager.getInstance().createBuffer(getDataType()[0], tile.wPx, tile.hPx, 1, true);
1246
                                int[] oldDB = bandList.getDrawableBands();
1247
                                bandList.setDrawableBands(new int[]{p.getAlphaBand()});
1248
                                q.setBandList(bandList);
1249
                                q.setBuffer(alphaBand);
1250
                                alphaBand = driver.getDataSet(q);
1251
                                bandList.setDrawableBands(oldDB);
1252
                        }
1253

    
1254
                        for (int j = 0; j < bandList.getBandCount(); j++) {
1255
                                bandList.getBand(j).setFileName(serverName);
1256
                        }
1257

    
1258
                        driver.close();
1259

    
1260

    
1261
                        TileCacheManager m = TileCacheLocator.getManager();
1262
                        org.gvsig.raster.cache.tile.Tile t = m.createTile(-1, tile.row, tile.col);
1263
                        t.setData(new Object[]{buf, alphaBand});
1264
                        t.setUl(new Point2D.Double(tile.ulx, tile.uly));
1265
                        t.setLr(new Point2D.Double(tile.lrx, tile.lry));
1266
                        t.setDownloaderParams("AffineTransform", getAffineTransform());
1267
                        t.setDownloaderParams("Tiling", new Boolean(true));
1268
                        if(listener != null) 
1269
                                listener.tileReady(t);
1270
                        else 
1271
                                return t;
1272

    
1273
                } catch (ProcessInterruptedException e) {
1274
                } catch (TileGettingException e) {
1275
                        throw new RasterDriverException("Error throwing a tile", e);
1276
                } catch (ProviderNotRegisteredException e) {
1277
                        throw new RasterDriverException("Error throwing a tile", e);
1278
                } catch (InitializeException e) {
1279
                        throw new RasterDriverException("Error throwing a tile", e);
1280
                }
1281
                return null;
1282
        }
1283

    
1284
        /*
1285
         * (non-Javadoc)
1286
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getBlockSize()
1287
         */
1288
        public int getBlockSize() {
1289
                return 0;
1290
        }
1291

    
1292
        /*
1293
         * (non-Javadoc)
1294
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#setAffineTransform(java.awt.geom.AffineTransform)
1295
         */
1296
        public void setAffineTransform(AffineTransform t){
1297
                
1298
        }
1299

    
1300
        /*
1301
         * (non-Javadoc)
1302
         * @see org.gvsig.raster.impl.provider.RasterProvider#getOverviewCount(int)
1303
         */
1304
        public int getOverviewCount(int band) throws BandAccessException, RasterDriverException {
1305
                return 0;
1306
        }
1307

    
1308
        /*
1309
         * (non-Javadoc)
1310
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getOverviewWidth(int, int)
1311
         */
1312
        public int getOverviewWidth(int band, int overview) throws BandAccessException, RasterDriverException {
1313
                return 0;
1314
        }
1315

    
1316
        /*
1317
         * (non-Javadoc)
1318
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getOverviewHeight(int, int)
1319
         */
1320
        public int getOverviewHeight(int band, int overview) throws BandAccessException, RasterDriverException {
1321
                return 0;
1322
        }
1323

    
1324
        /*
1325
         * (non-Javadoc)
1326
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#isOverviewsSupported()
1327
         */
1328
        public boolean isOverviewsSupported() {
1329
                return false;
1330
        }
1331

    
1332
        /*
1333
         * (non-Javadoc)
1334
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#isReproyectable()
1335
         */
1336
        public boolean isReproyectable() {
1337
                return false;
1338
        }
1339

    
1340
        /*
1341
         * (non-Javadoc)
1342
         * @see org.gvsig.fmap.dal.raster.spi.CoverageStoreProvider#getName()
1343
         */
1344
        public String getName() {
1345
                return NAME;
1346
        }
1347
        
1348
        /**
1349
         * Convierte un punto desde coordenadas pixel a coordenadas del mundo.
1350
         * @param pt Punto a transformar
1351
         * @return punto transformado en coordenadas del mundo
1352
         */
1353
        public Point2D rasterToWorld(Point2D pt) {
1354
                Point2D p = new Point2D.Double();
1355
                getAffineTransform().transform(pt, p);
1356
                return p;
1357
        }
1358

    
1359
        /**
1360
         * Convierte un punto desde del mundo a coordenadas pixel.
1361
         * @param pt Punto a transformar
1362
         * @return punto transformado en coordenadas pixel
1363
         */
1364
        public Point2D worldToRaster(Point2D pt) {
1365
                Point2D p = new Point2D.Double();
1366
                try {
1367
                        getAffineTransform().inverseTransform(pt, p);
1368
                } catch (NoninvertibleTransformException e) {
1369
                        return pt;
1370
                }
1371
                return p;
1372
        }
1373
        
1374
        /*
1375
         * (non-Javadoc)
1376
         * @see org.gvsig.raster.impl.provider.RasterProvider#setStatus(org.gvsig.raster.impl.provider.RasterProvider)
1377
         */
1378
        public void setStatus(RasterProvider provider) {
1379
                if(provider instanceof WMTSProvider) {
1380
                }
1381
        }
1382
        
1383
        /*
1384
         * (non-Javadoc)
1385
         * @see org.gvsig.raster.impl.provider.RemoteRasterProvider#getLastRequest()
1386
         */
1387
        public File getLastRequest() {
1388
                return lastRequest;
1389
        }
1390
        
1391
        /**
1392
         * ASigna el par?metro de inicializaci?n del driver.
1393
         */
1394
        @Override
1395
        public void setParam(DataStoreProviderServices storeServices, DataStoreParameters param) {
1396
                if(param instanceof WMTSDataParameters)
1397
                        this.uri = ((WMTSDataParameters)param).getURI();
1398
                this.param = param;
1399
                this.storeServices = storeServices;
1400
        }
1401
        
1402
        /*
1403
         * (non-Javadoc)
1404
         * @see org.gvsig.raster.impl.provider.RasterProvider#getInfoByPoint(double, double)
1405
         */
1406
        public String getInfoByPoint(double x, double y, ICancellable cancellable) throws RemoteServiceException {
1407
                WMTSDataParameters p = (WMTSDataParameters)param;
1408
                int level;
1409
                try {
1410
                        level = getLevelFromRealCoords(p.getExtent(), lastWidthRequest);
1411
                        return getFeatureInfo(x, y, level);
1412
                } catch (RasterDriverException e) {
1413
                        throw new RemoteServiceException(e);
1414
                }
1415
        }
1416
        
1417
        /*
1418
         * (non-Javadoc)
1419
         * @see org.gvsig.raster.impl.provider.RasterProvider#getNearestLevel(double)
1420
         */
1421
        public int getNearestLevel(double pixelSize) {
1422
                double[] pixelSizes = getPixelSizeByLevel();
1423
                for (int i = 0; i < pixelSizes.length - 1; i++) {
1424
                        if(pixelSize <= pixelSizes[i] && pixelSize > pixelSizes[i + 1]) {
1425
                                return i;
1426
                        }
1427
                }
1428
                if(pixelSize < pixelSizes[getZoomLevels() - 1])
1429
                        return getZoomLevels() - 1;
1430
                return 0;
1431
        }
1432
        
1433
        /*
1434
         * (non-Javadoc)
1435
         * @see org.gvsig.raster.impl.provider.RasterProvider#getTileServer()
1436
         */
1437
        public TileServer getTileServer() {
1438
                if(tileServer == null) {
1439
                        tileServer = new WMTSTileServer(this, getTileMatrixSetLink());
1440
                }
1441
                return tileServer;
1442
        }
1443
        
1444
        /*
1445
         * (non-Javadoc)
1446
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getTileSize(int)
1447
         */
1448
        public int[] getTileSize(int level) {
1449
                return getTileServer().getStruct().getTileSizeByLevel(level);
1450
        }
1451

    
1452
        /*
1453
         * (non-Javadoc)
1454
         * @see org.gvsig.raster.impl.provider.RasterProvider#isRasterEnclosed()
1455
         */
1456
        public boolean isRasterEnclosed() {
1457
                return true;
1458
        }
1459
        
1460
        /*
1461
         * (non-Javadoc)
1462
         * @see org.gvsig.raster.impl.provider.RemoteRasterProvider#getBufferLastRequest()
1463
         */
1464
        public Buffer getBufferLastRequest() throws ProcessInterruptedException, RasterDriverException {
1465
                return null;
1466
        }
1467
        
1468
        /**
1469
         * Gets the srs code
1470
         * @return
1471
         */
1472
        public String getSRSCode() {
1473
                WMTSDataParameters p = (WMTSDataParameters)param;
1474
                return p.getSRSCode();
1475
        }
1476

    
1477
        /*
1478
         * (non-Javadoc)
1479
         * @see org.gvsig.raster.impl.provider.TiledRasterProvider#getInternalProvider()
1480
         */
1481
        public RasterProvider getInternalProvider() {
1482
                return this;
1483
        }
1484
        
1485
        /*
1486
         * (non-Javadoc)
1487
         * @see org.gvsig.fmap.dal.coverage.store.props.Histogramable#getHistogramComputer()
1488
         */
1489
        public HistogramComputer getHistogramComputer() throws HistogramException, InterruptedException {
1490
                if (histogram == null)
1491
                        histogram = new RemoteStoreHistogram(this);
1492
                return histogram;
1493
        }
1494
}