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

History | View | Annotate | Download (47.2 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.URL;
35
import java.util.List;
36

    
37
import javax.swing.ImageIcon;
38

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

    
190
                public RequestTileLauncher(TilePipe pipe, WMTSStatus status, WMTSTile tile) {
191
                        this.pipe = pipe;
192
                        this.status = status;
193
                        this.tile = tile;
194
                }
195

    
196
                public void run() {
197
                        try {
198
                                //File file = getConnector().getTile(status, null);
199
                                URL url = getOGCClient().getTileURL(status);
200
                                tile.setFile(getOGCClient().downloadFile(url, null));
201
                                pipe.setTile(tile);
202
                        } catch (DownloadException e) {
203
                                logger.info("Error downloading files", e);
204
                        } catch (MalformedURLException e) {
205
                                logger.info("Malformed URL", e);
206
                        } catch (WMTSException e) {
207
                                logger.info("", e);
208
                        }
209
                }
210
        }
211
        
212
        /**
213
         * Point information 
214
         * @author Nacho Brodin (nachobrodin@gmail.com)
215
         */
216
        public class PointInfo {
217
                public Point2D worldCoord;
218
                public Point2D tile;
219
                public Point2D pixelInTile;
220
                public int     level;
221
                
222
                public PointInfo(Point2D worldCoord) {
223
                        this.worldCoord = worldCoord;
224
                }
225
        }
226

    
227
        public static void register() {
228
                DataManagerProviderServices dataman = (DataManagerProviderServices) DALLocator.getDataManager();
229
                if (dataman != null && !dataman.getStoreProviders().contains(NAME)) {
230
                        dataman.registerStoreProvider(NAME,
231
                                        WMTSProvider.class, WMTSDataParametersImpl.class);
232
                }
233

    
234
                if (!dataman.getExplorerProviders().contains(WMTSServerExplorer.NAME)) {
235
                        dataman.registerExplorerProvider(WMTSServerExplorer.NAME, WMTSServerExplorer.class, WMTSServerExplorerParameters.class);
236
                }
237
                dataman.registerStoreFactory(NAME, DefaultStoreFactory.class);
238
        }
239
        
240
        public WMTSProvider() throws NotSupportedExtensionException {
241
                super();
242
        }
243
        
244
        /**
245
         * Constructor. Abre el dataset.
246
         * @param proj Proyecci?n
247
         * @param fName Nombre del fichero
248
         * @throws NotSupportedExtensionException
249
         */
250
        public WMTSProvider(String params) throws NotSupportedExtensionException {
251
                super(params);
252
                if(params instanceof String) {
253
                        WMTSDataParameters p = new WMTSDataParametersImpl();
254
                        p.setURI((String)params);
255
                        super.init(p, null, ToolsLocator.getDynObjectManager()
256
                                        .createDynObject(
257
                                                        MetadataLocator.getMetadataManager().getDefinition(
258
                                                                        DataStore.METADATA_DEFINITION_NAME)));
259
                        init(p, null);
260
                }
261
        }
262
        
263
        public WMTSProvider(WMTSDataParameters params,
264
                        DataStoreProviderServices storeServices) throws NotSupportedExtensionException {
265
                super(params, storeServices, ToolsLocator.getDynObjectManager()
266
                                .createDynObject(
267
                                                MetadataLocator.getMetadataManager().getDefinition(
268
                                                                DataStore.METADATA_DEFINITION_NAME)));
269
                init(params, storeServices);
270
        }
271
        
272
        /**
273
         * Gets the connector from the URL
274
         * @return
275
         * @throws RemoteServiceException
276
         */
277
        public WMTSClient getOGCClient() throws WMTSException {
278
                if(ogcClient == null) {
279
                        WMTSDataParameters p = (WMTSDataParameters)parameters;
280
                        ogcClient = p.getOGCClient();
281
                        if(ogcClient != null)
282
                                return ogcClient;
283
                        
284
                        URL url = null;
285
                        try {
286
                                url = new URL(p.getURI());
287
                        } catch (Exception e) {
288
                                throw new WMTSException("Malformed URL",e);
289
                        }
290
                        try {
291
                                ogcClient = WMTSOGCLocator.getManager().createWMTSClient(url.toString());
292
                                ogcClient.connect(true, new ICancellable() {
293
                                        
294
                                        public boolean isCanceled() {
295
                                                return false;
296
                                        }
297
                                        
298
                                        public Object getID() {
299
                                                return null;
300
                                        }
301
                                });
302
                        } catch (ConnectException e) {
303
                                throw new WMTSException("Connect exception",e);
304
                        } catch (IOException e) {
305
                                throw new WMTSException("Connect exception",e);
306
                        }
307
                }
308
                return ogcClient;
309
        }
310

    
311
        /**
312
         * Crea las referencias al fichero y carga
313
         * las estructuras con la informaci?n y los metadatos.
314
         * @param proj Proyecci?n
315
         * @param param Parametros de carga
316
         * @throws NotSupportedExtensionException
317
         */
318
        public void init (DataStoreParameters params,
319
                        DataStoreProviderServices storeServices) throws NotSupportedExtensionException {
320
                setParam(storeServices, params);
321
                if(((WMTSDataParameters)params).getImageFormat().compareTo("image/gif") == 0) {
322
                        setDataType(new int[]{Buffer.TYPE_BYTE});
323
                        bandCount = 1;
324
                } else {
325
                        setDataType(new int[]{Buffer.TYPE_BYTE, Buffer.TYPE_BYTE, Buffer.TYPE_BYTE, Buffer.TYPE_BYTE});
326
                        bandCount = 4;
327
                }
328
                
329
                if(!(param instanceof WMTSDataParameters))
330
                        return;
331
                
332
                gridSubsets = hasGridSubsets((WMTSDataParameters)param);
333
                open = true;
334
        }
335
        
336
        /**
337
         * Returns true if this layer has grid subsets
338
         * @return
339
         */
340
        public boolean hasGridSubsets() {
341
                return gridSubsets;
342
        }
343
        
344
        /**
345
         * Checks if this layer has grid subsets or doesn't
346
         * @param p
347
         * @return
348
         */
349
        private boolean hasGridSubsets(WMTSDataParameters p) {
350
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = null;
351
                List<WMTSTileMatrixSetLink> tileMatrixSetLinkList = p.getLayer().getTileMatrixSetLink();
352
                String srs = p.getSRSCode();
353
                for (int i = 0; i < tileMatrixSetLinkList.size(); i++) {
354
                        WMTSTileMatrixSetLink tileMatrixSetLink = (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(i);
355
                        WMTSTileMatrixSet tms = tileMatrixSetLink.getTileMatrixSet();
356
                        List<WMTSTileMatrixLimits> tmsl = tileMatrixSetLink.getTileMatrixLimits();
357
                        String srsTileSet = tms.getSupportedCRS();
358
                        if(areSrsEquals(srsTileSet, srs)) {
359
                                tileMatrixSetLimits = tmsl;
360
                        }
361
                }
362
                
363
                return (tileMatrixSetLimits == null || tileMatrixSetLimits.size() <= 0) ? false : true; 
364
        }
365
        
366
        private boolean areSrsEquals(String sourceSrs, String appSrs) {
367
                if(sourceSrs.compareTo(appSrs) == 0)
368
                        return true;
369
                if(sourceSrs.contains("CRS:84") || sourceSrs.contains("CRS84")) { 
370
                        if(appSrs.equals("EPSG:4326"))
371
                                return true;
372
                }
373
                return false;
374
        }
375
        
376
        /*public static final WMTSConnector getConnectorFromURL(URL url) throws IOException {
377
                WMTSConnector drv = (WMTSConnector) drivers.get(url);
378
                if (drv == null) {
379
                        drv = new WMTSConnector(url);
380
                        drivers.put(url, drv);
381
                }
382
                return drv;
383
        }*/
384
        
385
        /**
386
         * Obtiene el objeto que contiene que contiene la interpretaci?n de
387
         * color por banda
388
         * @return
389
         */
390
        public ColorInterpretation getColorInterpretation() {
391
                if(super.getColorInterpretation() == null) {
392
                        ColorInterpretation colorInterpretation = new DataStoreColorInterpretation(getBandCount());
393
                        
394
                        if(getBandCount() == 1) 
395
                                colorInterpretation = DataStoreColorInterpretation.createGrayInterpretation();
396
                        
397
                        if(getBandCount() == 3) 
398
                                colorInterpretation = DataStoreColorInterpretation.createRGBInterpretation();
399
                        
400
                        if(getBandCount() == 4)
401
                                colorInterpretation = DataStoreColorInterpretation.createRGBAInterpretation();
402
                        
403
                        if(getBandCount() > 4 || getBandCount() == 2) {
404
                                for (int i = 0; i < getBandCount(); i++) {
405
                                        colorInterpretation.setColorInterpValue(i, DataStoreColorInterpretation.UNDEF_BAND);
406
                                }
407
                        }
408
                        setColorInterpretation(colorInterpretation);
409
                }
410
                return super.getColorInterpretation();
411
        }
412
        
413
        public boolean isTiled() {
414
                return true;
415
        }
416
        
417
        public AffineTransform getAffineTransform() {
418
                WMTSDataParameters p = (WMTSDataParameters)parameters;
419
                Extent e = getExtent();
420
                double psX = e.width() / (lastWidthRequest <= 0 ? p.getWidth() : lastWidthRequest);
421
                double psY = -(e.height() / (lastHeightRequest <= 0 ? p.getHeight() : lastHeightRequest));
422
                ownTransformation = new AffineTransform(
423
                                psX, 
424
                                0, 
425
                                0, 
426
                                psY, 
427
                                e.getULX() - (psX / 2),
428
                                e.getULY() - (psY / 2));
429
                externalTransformation = (AffineTransform) ownTransformation.clone();
430
                return ownTransformation;
431
        }
432
        
433
        /**
434
         * <p>
435
         * Gets the bounding box in world coordinates. 
436
         * If the layer has defined the BoundingBox tag, we will take this bounding box as entire 
437
         * extension of this layer, else we'll see if the tag WGS84BoundingBox is defined (it can be approximated).
438
         * In this case we'll take WGS84BoundingBox as entire extension.
439
         * </p>
440
         * <br>
441
         * Note: 
442
         * <br>
443
         * <p>
444
         * If the layer has grid subsets (TileMatrixLimits) then
445
         * this will have a only extent but if the layer doesn't have grid subsets then this will have a different
446
         * extent in each level resolution. In this case we need to know the extent for each level.
447
         * </p>
448
         * @return Extent
449
         */
450
        public Extent getExtent() {
451
                WMTSDataParameters p = (WMTSDataParameters)parameters;
452
                WMTSLayer layer = p.getLayer();
453

    
454
                if(layer.getBBox() != null)
455
                        return new ExtentImpl(layer.getBBox().toRectangle2D());
456
                
457
                if(layer.getWGS84BBox() != null) {
458
                        String crsCode = p.getSRSCode();
459
                        Rectangle2D r = layer.getWGS84BBoxTransformed(crsCode);
460
                        if(r != null)
461
                                return new ExtentImpl(r);
462
                }
463
                        
464
                if(bbox == null)
465
                        getExtentByResolutionLevel();
466
                return bbox;
467
                
468
                /*if(gridSubsets) {
469
                        WMTSBoundingBox bbox = layer.getWGS84BBox();
470
                        return new ExtentImpl(bbox.toRectangle2D());
471
                } else {
472
                        if(bbox == null)
473
                                getExtentByResolutionLevel();
474
                        return bbox;
475
                }*/
476
        }
477
        
478
        /**
479
         * Gets the suffix of the downloaded image
480
         * @return
481
         */
482
        public String getFileSuffix() {
483
                WMTSDataParameters p = (WMTSDataParameters)parameters;
484
                String format = p.getImageFormat();
485
                if (format == null){
486
                        return "xml";
487
                }
488
                if (format.indexOf("png") >= 0){
489
                return "png";
490
                }        
491
            if (format.indexOf("xml") >= 0){
492
                return "xml";
493
            }        
494
            if (format.indexOf("gif") >= 0){
495
                return "gif";
496
            }
497
            if (format.indexOf("tif") >= 0){
498
                return "tif";
499
            }
500
            if (format.indexOf("bmp") >= 0){
501
                return "bmp";
502
            }
503
            if (format.indexOf("jpg") >= 0
504
                || format.indexOf("jpeg") >= 0){
505
                return "jpg";                         
506
            }
507
                return "xml";
508
        }
509

    
510
        /**
511
         * When a layer doesn't have grid subsets this will have a different bounding
512
         * box by resolution level. This function calculates and returns the array of
513
         * extents, one by resolution level.
514
         * @return
515
         */
516
        public Extent[] getExtentByResolutionLevel() {
517
                if(extentByLevel == null) {
518
                        WMTSDataParameters p = (WMTSDataParameters)parameters;
519
                        WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
520
                        WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
521
                        
522
                    double widthMtsTile = 0;
523
                    double heightMtsTile = 0;
524
                        List<WMTSTileMatrix> tileMatrixList = tileMatrixSet.getTileMatrix();
525
                        extentByLevel = new ExtentImpl[tileMatrixList.size()];
526
                        double minX = 0;
527
                        double minY = 0;
528
                        double maxX = 0;
529
                        double maxY = 0;
530
                        for (int i = 0; i < tileMatrixList.size(); i++) {
531
                                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixList.get(i);
532
                            if(!p.isProjected()) {
533
                                    widthMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / (MTS_X_GRADO * 1000);
534
                                    heightMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileHeight() * 0.28) / (MTS_X_GRADO * 1000);
535
                            } else {
536
                                    widthMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / 1000;
537
                                    heightMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileHeight() * 0.28) / 1000;
538
                            }
539
                            
540
                            //TODO: Revisar!!! Creo que el top left sale al rev?s en el de la nasa
541
                            
542
                            double h = Math.abs(tileMatrix.getTopLeftCorner()[1] - (tileMatrix.getTopLeftCorner()[1] - (tileMatrix.getMatrixHeight() * heightMtsTile)));
543
                            Rectangle2D r = new Rectangle2D.Double(
544
                                            tileMatrix.getTopLeftCorner()[0], 
545
                                            tileMatrix.getTopLeftCorner()[1] - h,
546
                                            Math.abs(tileMatrix.getTopLeftCorner()[0] - (tileMatrix.getTopLeftCorner()[0] + (tileMatrix.getMatrixWidth() * widthMtsTile))),
547
                                            h);
548
                            extentByLevel[i] = new ExtentImpl(r);
549
                            if(i == 0) {
550
                                    minX = extentByLevel[i].getMin().getX();
551
                                    minY = extentByLevel[i].getMin().getY();
552
                                    maxX = extentByLevel[i].getMax().getX();
553
                                    maxY = extentByLevel[i].getMax().getY();
554
                            } else {
555
                                    minX = Math.min(minX, extentByLevel[i].getMin().getX());
556
                                    minY = Math.min(minY, extentByLevel[i].getMin().getY());
557
                                    maxX = Math.max(maxX, extentByLevel[i].getMax().getX());
558
                                    maxY = Math.max(maxY, extentByLevel[i].getMax().getY());
559
                            }
560
                        }
561
                        bbox = new ExtentImpl(minX, maxY, maxX, minY);
562
                }
563
                return extentByLevel;
564
        }
565
        
566
        public Rectangle2D getLayerExtent(String layerName, String srs) throws RemoteServiceException {
567
                return null;
568
        }
569

    
570
        public RasterProvider load() {
571
                return this;
572
        }
573
        
574
        public boolean isOpen() {
575
                return open;
576
        }
577

    
578
        public void close() {
579
                open = false;
580
        }
581
        
582
        public Transparency getTransparency() {
583
                if(lastFileTransparency == null) {
584
                        lastFileTransparency = new DataStoreTransparency(getColorInterpretation());
585
                        lastFileTransparency.setTransparencyBand(3);
586
                }
587
                return lastFileTransparency;
588
        }
589
        
590
        public NoData getNoDataValue() {
591
                NoData nodata = super.getNoDataValue();
592
                if(nodata != null)
593
                        nodata.setNoDataTransparent(false);
594
                return noData;
595
        }
596

    
597
        public String translateFileName(String fileName) {
598
                return fileName;
599
        }
600

    
601
        public void setView(Extent e) {
602
                viewRequest = e;
603
        }
604

    
605
        public Extent getView() {
606
                return viewRequest;
607
        }
608

    
609
        public double getWidth() {
610
                WMTSDataParameters p = (WMTSDataParameters)parameters;
611
                if (lastWidthRequest <= 0) 
612
                        return p.getWidth();
613
                return lastWidthRequest;
614
        }
615

    
616
        public double getHeight() {
617
                WMTSDataParameters p = (WMTSDataParameters)parameters;
618
                if (lastHeightRequest <= 0) 
619
                        return p.getHeight();
620
                return lastHeightRequest;
621
        }
622

    
623
        public Object readCompleteLine(int line, int band)
624
                throws InvalidSetViewException, FileNotOpenException, RasterDriverException {
625
                return null;
626
        }
627
        
628
        /**
629
         * When the remote layer has fixed size this method downloads the file and return its reference. 
630
         * File layer has in the long side FIXED_SIZE pixels and the bounding box is complete. This file could be
631
         * useful to build an histogram or calculate statistics. This represents a sample of data.
632
         * @return
633
         * @throws RasterDriverException
634
         */
635
        public File getFileLayer() throws RasterDriverException {
636
                return null;
637
        }
638

    
639
        /**
640
         * Reads a complete block of data and returns an tridimensional array of the right type. This function is useful
641
         * to read a file very fast without setting a view. In a WMTS service when the size is fixed then it will read the
642
         * entire image but when the source hasn't pixel size it will read a sample of data. This set of data will have
643
         * the size defined in FIXED_SIZE. 
644
         * 
645
         * @param pos Posici?n donde se empieza  a leer
646
         * @param blockHeight Altura m?xima del bloque leido
647
         * @return Object que es un array tridimendional del tipo de datos del raster. (Bandas X Filas X Columnas)
648
         * @throws InvalidSetViewException
649
         * @throws FileNotOpenException
650
         * @throws RasterDriverException
651
         */
652
        public Object readBlock(int pos, int blockHeight, double scale) 
653
        throws InvalidSetViewException, FileNotOpenException, RasterDriverException, ProcessInterruptedException {
654
                return null;
655
        }
656
        
657
        public Object getData(int x, int y, int band)
658
                throws InvalidSetViewException, FileNotOpenException, RasterDriverException {
659
                return null;
660
        }
661
        
662
        /**
663
         * Assigns the list of bands RGB and read a window of data
664
         * @param rasterBuf
665
         * @param bandList
666
         * @param lastFile
667
         * @param ulx
668
         * @param uly
669
         * @param lrx
670
         * @param lry
671
         * @return
672
         * @throws RasterDriverException
673
         * @throws ProcessInterruptedException
674
         */
675
        public Buffer getBuffer(Buffer rasterBuf, BandList bandList, File lastFile, 
676
                        double ulx, double uly, double lrx, double lry) throws RasterDriverException, ProcessInterruptedException {
677
                return null;
678
        }
679
        
680
        /**
681
         * Gets the tile matrix from the selected level
682
         * @param level
683
         * @return
684
         */
685
        private WMTSTileMatrix getTileMatrixByLevel(int level) {
686
                level = adjustLevel(level);
687
                
688
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
689
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
690
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
691
                
692
                WMTSTileMatrixLimits tileMatrixLimits = null;
693
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(level);
694
                if(hasGridSubsets()) {
695
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(level);
696
                        tileMatrix = tileMatrixLimits.getTileMatrix();
697
                }
698
                return tileMatrix;
699
        }
700
        
701
        /**
702
         * Returns the number of levels
703
         * @return
704
         */
705
        public int getZoomLevels() {
706
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
707
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
708
                if(hasGridSubsets()) {
709
                        List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
710
                        return Math.min(tileMatrixSet.getTileMatrix().size(), tileMatrixSetLimits.size());
711
                }
712
                return tileMatrixSet.getTileMatrix().size();
713
                
714
        }
715
        
716
        public Extent getCoordsInTheNearestLevel(Extent extent, int w, int h) {
717
                double[] pixelSizes = getPixelSizeByLevel();
718
                double currentPixelSize = extent.width() / (double)w;
719
                
720
                int level = 0;
721
                for (int i = 0; i < (pixelSizes.length - 1); i++) {
722
                        if(currentPixelSize < pixelSizes[i] && currentPixelSize >= pixelSizes[i + 1]) {
723
                                level = i + 1;
724
                                break;
725
                        }
726
                }
727
                
728
                return getZoomLevelCoordinates(level, extent, w, h);
729
        }
730
        
731
        public Extent getCoordsInLevel(Point2D viewCenter, int level, int w, int h) {
732
                WMTSDataParameters p = (WMTSDataParameters)param;
733
                level = adjustLevel(level);
734
                WMTSTileMatrix tileMatrix = getTileMatrixByLevel(level);
735
                
736
                boolean proj = p.isProjected();
737
                
738
                double psX = tileMatrix.getWidthWCTile(proj) / tileMatrix.getTileWidth();
739
                double psY = tileMatrix.getHeightWCTile(proj) / tileMatrix.getTileHeight();
740
                
741
                double ulx = viewCenter.getX() - ((w / 2) * psX);
742
                double uly = viewCenter.getY() - ((h / 2) * psY);
743
                double lrx = ulx + (w * psX);
744
                double lry = uly + (h * psY);
745
                return new ExtentImpl(ulx, uly, lrx, lry);
746
        }
747
        
748
        /**
749
         * Calculates the extent of a zoom level using other extent as a reference. The new extent is 
750
         * calculated with the same coordinate at the center. 
751
         * @param level
752
         * @param extent
753
         * @param w
754
         * @param h
755
         * @return
756
         */
757
        public Extent getZoomLevelCoordinates(int level, Extent extent, int w, int h) {
758
                double centerX = extent.getCenterX();
759
                double centerY = extent.getCenterY();
760
                return getCoordsInLevel(new Point2D.Double(centerX, centerY), level, w, h);
761
        }
762
        
763
        /**
764
         * Returns a list of pixel sizes by level
765
         * @return
766
         */
767
        public double[] getPixelSizeByLevel() {
768
                WMTSDataParameters p = (WMTSDataParameters)param;
769
                double[] list = new double[getZoomLevels()];
770
                
771
                for (int i = 0; i < getZoomLevels(); i++) {
772
                        WMTSTileMatrix tileMatrix = getTileMatrixByLevel(i);
773
                        list[i] = math.adjustDouble(tileMatrix.getWidthWCTile(p.isProjected()) / tileMatrix.getTileWidth());
774
                }
775
                return list;
776
        }
777
        
778
        /**
779
         * Adjust de level to the range
780
         * @param level
781
         * @return
782
         */
783
        private int adjustLevel(int level) {
784
                if(level < 0)
785
                        level = 0;
786
                if(level > getZoomLevels())
787
                        level = getZoomLevels();
788
                return level;
789
        }
790
        
791
        public org.gvsig.raster.cache.tile.Tile getTile(SpiRasterQuery q) throws TileGettingException {
792
                //q.getResolutionLevel(), q.getTileCol(), q.getTileRow(), q.getBBox(), q.getCacheStruct()!
793
                
794
                CacheStruct str = getTileServer().getStruct();
795
                
796
                //1-Selecci?n de WMTSTileMatrixSet por srs
797
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
798
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
799
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
800
                
801
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(q.getResolutionLevel());
802
                if(gridSubsets) {
803
                        WMTSTileMatrixLimits tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(q.getResolutionLevel());
804
                        tileMatrix = tileMatrixLimits.getTileMatrix();
805
                }
806
                int bufWidth = tileMatrix.getTileWidth();
807
                int bufHeight = tileMatrix.getTileHeight();
808
                
809
                try {
810
                        Extent adjBbox = q.getAdjustedRequestBoundingBox();
811
                        Rectangle2D r = adjBbox.toRectangle2D();//new Rectangle2D.Double(Math.min(minX, maxX), Math.min(minY, maxY), Math.abs(maxX - minX), Math.abs(maxY - minY));
812
                        WMTSStatus status = buildWMTSStatus(r, bufWidth , bufHeight);
813
                        
814
                        int[] size = str.getTileSizeByLevel(q.getResolutionLevel());
815
                        WMTSTile tile = WMTSOGCLocator.getManager().createTile(
816
                                        size, 
817
                                        new int[]{q.getTileRow(), q.getTileCol()}, 
818
                                        new double[]{adjBbox.getULX(), adjBbox.getULY(), adjBbox.getLRX(), adjBbox.getLRY()});
819
                        
820
                        File file = getOGCClient().getTile(status, null);
821
                        tile.setFile(file);
822
                        //Creamos un BandList con todas las bandas del fichero
823
                        BandList bandList = new BandListImpl();
824
                        for(int i = 0; i < getBandCount(); i++) {
825
                                try {
826
                                        DatasetBand band = new DatasetBandImpl(getURIOfFirstProvider(), i, getDataType()[i], getBandCount());
827
                                        bandList.addBand(band);
828
                                } catch(BandNotFoundInListException e) {
829
                                        //No a?adimos la banda
830
                                }
831
                        }
832
                        return drawTile(tile, null, bandList);
833
                } catch (WMTSException e) {
834
                        throw new TileGettingException("Error getting tiles", e);
835
                } catch (ServerErrorException e) {
836
                        throw new TileGettingException("Error getting tiles", e);
837
                } catch (RasterDriverException e) {
838
                        throw new TileGettingException("Error getting tiles", e);
839
                }
840
        }
841
        
842
        @Override
843
        public void loadBuffer(SpiRasterQuery q) 
844
                        throws ProcessInterruptedException, RasterDriverException {
845
                Rectangle2D r = q.getAdjustedRequestBoundingBox().toRectangle2D();//new Rectangle2D.Double(Math.min(minX, maxX), Math.min(minY, maxY), Math.abs(maxX - minX), Math.abs(maxY - minY));
846
                WMTSStatus status = buildWMTSStatus(r, q.getAdjustedWidth(), q.getAdjustedBufHeight());
847
                request(status, q.getBandList(), q.getTileListener(), requestType);
848
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, q.getBandList(), null, requestType);
849
                MemoryTileMatrixBuffer matrixBuffer = new MemoryTileMatrixBuffer(tileList);
850
                Buffer b = matrixBuffer.getWindow(q.getAdjustedRequestBoundingBox(), q.getBufWidth(), q.getBufHeight(), q.getBandList().getDrawableBandsCount());
851
                q.setBufferResult(b);
852
        }
853
        
854
        /**
855
         * Gets the information from a point 
856
         * @param wcx
857
         * @param wcy
858
         * @param level
859
         * @return
860
         * @throws RasterDriverException
861
         */
862
        public String getFeatureInfo(double wcx, double wcy, int level) throws RasterDriverException {
863
                PointInfo pointInfo = new PointInfo(new Point2D.Double(wcx, wcy));
864
                pointInfo.level = level;
865
                getTileInfo(pointInfo);
866
                
867
                WMTSClient ogcClient = null;
868
                try {
869
                        ogcClient = getOGCClient();
870
                        lastStatus.setTileRow((int)pointInfo.tile.getX());
871
                        lastStatus.setTileCol((int)pointInfo.tile.getY());
872
                        
873
                        String fi = ogcClient.getFeatureInfo(lastStatus, (int)pointInfo.pixelInTile.getX(), (int)pointInfo.pixelInTile.getY(), null);
874
                        return fi;
875
                } catch (WMTSException e) {
876
                        throw new RasterDriverException("Error getting the connector object", e);
877
                } 
878
        }
879
        
880
        /**
881
         * Gets a tile position from a world coordinates point and a resolution level
882
         * @param point
883
         * @param level
884
         * @return An array with two elements. The first is the row and the second the column
885
         * of the tile in the tile matrix
886
         */
887
        private void getTileInfo(PointInfo pointInfo) {
888
                WMTSDataParameters p = (WMTSDataParameters)param;
889
                
890
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
891
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
892
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
893
                
894
                WMTSTileMatrixLimits tileMatrixLimits = null;
895
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(pointInfo.level);
896
                if(hasGridSubsets()) {
897
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(pointInfo.level);
898
                        tileMatrix = tileMatrixLimits.getTileMatrix();
899
                }
900
                
901
                List<WMTSTile> tiles = null;
902
                if(hasGridSubsets())
903
                        tiles = tileMatrix.contains(p.isProjected(), tileMatrixLimits, pointInfo.worldCoord, getExtent().toRectangle2D());
904
                else
905
                        tiles = tileMatrix.contains(p.isProjected(), pointInfo.worldCoord, getExtent().toRectangle2D());
906
                
907
                //Tile row and column
908
                pointInfo.tile = new Point2D.Double(tiles.get(0).getRow(), tiles.get(0).getCol());
909
                
910
                //Desplazamiento en pixels dentro del tile
911
                Point2D rasterPoint = tiles.get(0).worldToRaster(pointInfo.worldCoord);
912
                pointInfo.pixelInTile = new Point2D.Double(rasterPoint.getX(), rasterPoint.getY());
913
        }
914
        
915
        /**
916
         * Builds the WMTSStatus object using the parameters and the request bounding box. 
917
         * @param r
918
         * @param bufWidth
919
         * @return
920
         * @throws RasterDriverException
921
         */
922
        public WMTSStatus buildWMTSStatus(Rectangle2D r, int bufWidth, int bufHeight) throws RasterDriverException {
923
                WMTSDataParameters p = (WMTSDataParameters)param;
924
                
925
                //Mantiene actualizados los par?metros del WMTSStoreParameters con la ?ltima petici?n hecha
926
                p.setExtent(r);
927
                p.setWidth(bufWidth);
928
                p.setHeight(bufHeight);
929
                
930
                lastWidthRequest = bufWidth;
931
                lastHeightRequest = bufHeight;
932
                
933
                //1-Selecci?n de WMTSTileMatrixSet por srs
934
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
935
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
936
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
937
                int initialLevel = p.getLayer().getInitialLevel(tileMatrixSet.getIdentifier());
938
                
939
                //Esto hace lo mismo que getScale y getLevelFromScale
940
                /*int level = 0;
941
                double[] pixelSizes = getPixelSizeByLevel();
942
                double psViewPort = math.adjustDouble(r.getWidth() / (double)bufWidth);
943
                for (int i = 0; i < pixelSizes.length - 1; i++) {
944
                        if(psViewPort <= pixelSizes[i] && psViewPort > pixelSizes[i + 1]) {
945
                                level = i;
946
                                break;
947
                        }
948
                }*/
949
                
950
                //2-Calculo de la escala
951
                double scale = getScale(r, bufWidth);
952
                
953
                //3-Selecci?n del nivel a partir de la escala
954
                int level = getLevelFromScale(scale, tileMatrixSet);
955
                
956
                //Para evitar que se salga del array si la capa tiene menos niveles que el tilematrixset
957
                int dif = 0;
958
                if(gridSubsets)
959
                        dif = (level - initialLevel) >= tileMatrixSetLimits.size() ?  (level - initialLevel) - tileMatrixSetLimits.size() + 1 : 0;
960
                
961
                //4-Obtenemos la matriz de tiles y los l?mites si tiene subsets
962
                @SuppressWarnings("unused")
963
                WMTSTileMatrixLimits tileMatrixLimits = null;
964
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(level - dif);
965
                if(gridSubsets)
966
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(level - initialLevel - dif);
967
                
968
                //5-Selecci?n de tiles que entran en esta bounding box
969
                List<WMTSTile> tiles = null;
970
                /*if(gridSubsets)
971
                        tiles = tileMatrix.intersects(p.isProjected(), tileMatrixLimits, r, getExtent().toRectangle2D());
972
                else*/
973
                Extent[] extList = getExtentByResolutionLevel();
974
                tiles = tileMatrix.intersects(p.isProjected(), r, extList[level].toRectangle2D());
975
                
976
                //6-Petici?n
977
                WMTSStatus status = null;
978
                try {
979
                        status = getOGCClient().createStatus();
980
                } catch (WMTSException e) {
981
                        throw new RasterDriverException("Error creating WMTSStatus", e);
982
                }
983
                WMTSLayer wmtsLayer = p.getLayer();
984
                status.setTileList(tiles);
985
                status.setLayer(wmtsLayer.getIdentifier());//.substring(p.getLayer().getIdentifier().indexOf("_") + 1));
986
                
987
                status.setFormat(p.getImageFormat());
988
                status.setInfoFormat(p.getInfoFormat());
989
                status.setStyle(p.getStyle() != null ? p.getStyle().getIdentifier() : "");
990
                status.setTileMatrixSet(tileMatrixSet.getIdentifier());
991
                status.setTileMatrix(tileMatrix.getIdentifier());
992
                status.setLevel(level - dif);
993
                status.setDimension(p.getDimension());
994
                status.setValueForDimension(p.getDimensionSelectedValue());
995
                
996
                wmtsLayer.buildResourceURLListFromTemplate(status);
997
                this.lastStatus = status;
998
                
999
                return status;
1000
        }
1001
        
1002
        /**
1003
         * Gets the resolution level from the real coordinates
1004
         * @param r
1005
         * @param 
1006
         * @return
1007
         * @throws RasterDriverException
1008
         */
1009
        public int getLevelFromRealCoords(Rectangle2D r, int width) throws RasterDriverException {
1010
                double scale = getScale(r, width);
1011
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
1012
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
1013
                return getLevelFromScale(scale, tileMatrixSet);
1014
        }
1015
        
1016
        /**
1017
         * Gets the resolution level from the scale
1018
         * @param scale
1019
         * @param tileMatrixSet
1020
         * @return
1021
         * @throws RasterDriverException
1022
         */
1023
        public int getLevelFromScale(double scale, WMTSTileMatrixSet tileMatrixSet) throws RasterDriverException {
1024
                //Recorremos los tileMatrix para obtener la escala m?s aproximada
1025
                int levelModifier = 0;
1026
                scale = math.adjustDouble(scale);
1027
                try {
1028
                        for (int resolutionLevel = 0; resolutionLevel < tileMatrixSet.getTileMatrix().size(); resolutionLevel++) {
1029
                                WMTSTileMatrix tm = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(resolutionLevel);
1030
                                double scaleDenominator = math.adjustDouble(tm.getScaleDenominator());
1031
                                if(scale >= scaleDenominator) {
1032
                                        return Math.max(resolutionLevel + levelModifier, 0);
1033
                                }
1034
                        }
1035
                } catch (IndexOutOfBoundsException e) {
1036
                        throw new RasterDriverException("Error in this resolution level", e);
1037
                }
1038
                return 0;
1039
        }
1040
        
1041
        /**
1042
         * Get the tile matrix set using the crs
1043
         * @param srs
1044
         * @return
1045
         */
1046
        public WMTSTileMatrixSetLink getTileMatrixSetLink() {
1047
                WMTSDataParameters p = (WMTSDataParameters)param;
1048
                List<WMTSTileMatrixSetLink> tileMatrixSetLinkList = p.getLayer().getTileMatrixSetLink();
1049
                for (int i = 0; i < tileMatrixSetLinkList.size(); i++) {
1050
                        WMTSTileMatrixSetLink tileMatrixSetLink = (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(i);
1051
                        String srsTileSet = tileMatrixSetLink.getTileMatrixSet().getSupportedCRS();
1052
                        if(srsTileSet.compareTo(p.getSRSCode()) == 0) {
1053
                                return tileMatrixSetLink;
1054
                        }
1055
                }
1056
                if(tileMatrixSetLinkList != null && tileMatrixSetLinkList.size() > 0)
1057
                        return (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(0);
1058
                return null;
1059
        }
1060
        
1061
        /**
1062
         * Gets the scale using the extent and the width in pixels.
1063
         * @param r
1064
         * @param width
1065
         * @return
1066
         */
1067
        private double getScale(Rectangle2D r, int width) {
1068
                WMTSDataParameters p = (WMTSDataParameters)param;
1069
                if(!p.isProjected()) {
1070
                        return (r.getWidth() * MTS_X_GRADO) / (width * 0.00028);
1071
                } else
1072
                        return (r.getWidth()) / (width * 0.00028);
1073
        }
1074
        
1075
        /**
1076
         * Throw a request
1077
         * @param status
1078
         * @param bandList
1079
         * @param listener
1080
         * @param alphaBandNumber 
1081
         * @return returns a buffer if the listener is null. In any other case it return null.
1082
         * @throws RasterDriverException 
1083
         * @throws ProcessInterruptedException 
1084
         */
1085
        private synchronized org.gvsig.raster.cache.tile.Tile[] request(
1086
                        WMTSStatus status, BandList bandList, TileListener listener, int requestType) throws RasterDriverException, ProcessInterruptedException {
1087
                //WMTSDataParameters p = (WMTSDataParameters)param;
1088
                WMTSClient ogcClient = null;
1089
                try {
1090
                        ogcClient = getOGCClient();
1091
                } catch (WMTSException e) {
1092
                        throw new RasterDriverException("Error getting the connector object", e);
1093
                }
1094
                
1095
                if(ogcClient == null)
1096
                        throw new RasterDriverException("Error getting the connector object");
1097
                
1098
                List<WMTSTile> tiles = status.getTileList();
1099
                
1100
                TilePipe pipe = new TilePipe();
1101
                //TilePipe2 pipe = new TilePipe2();
1102
                //TileThreadPool pool = null;
1103
                
1104
                //Caso 1: Lanza un thread que gestiona que no se lancen muchos threads a la vez
1105
                if(requestType == LIMITED_THREADS) {
1106
                        RequestThreadManager threadManager = new RequestThreadManager(pipe, tiles, status);
1107
                        pipe.setRequestManager(threadManager);
1108
                        threadManager.start();
1109
                //Caso 2: Lanza todos los threads
1110
                } else if(requestType == UNLIMITED_THREADS) {
1111
                        for (int i = 0; i < tiles.size(); i++) {
1112
                                WMTSTile tile = tiles.get(i);
1113
                                WMTSStatus statusCopy = status.cloneStatus();
1114
                                statusCopy.setTileRow(tile.getRow());
1115
                                statusCopy.setTileCol(tile.getCol());
1116
                                new RequestTileLauncher(pipe, statusCopy, tile).start();
1117
                        }
1118
                }
1119
                
1120
                org.gvsig.raster.cache.tile.Tile[] tileList = new org.gvsig.raster.cache.tile.Tile[tiles.size()]; 
1121
                
1122
                if(requestType == LIMITED_THREADS || requestType == UNLIMITED_THREADS) {
1123
                        int nCollected = 0;
1124
                        while (nCollected < tiles.size()) {
1125
                                WMTSTile tile = pipe.getTile();
1126
                                tileList[nCollected] = drawTile(tile, listener, bandList);
1127
                                nCollected ++;
1128
                        }
1129
                }
1130
                
1131
                if(requestType == SEQUENTIAL) {
1132
                        for (int i = 0; i < tiles.size(); i++) {
1133
                                WMTSTile tile = tiles.get(i);
1134
                                status.setTileRow(tile.getRow());
1135
                                status.setTileCol(tile.getCol());
1136
                                //TODO:Cancelaci?n
1137
                                try {
1138
                                        File file = ogcClient.getTile(status, null);
1139
                                        tile.setFile(file);
1140
                                        tileList[i] = drawTile(tile, listener, bandList);
1141
                                } catch (WMTSException e) {
1142
                                        throw new RasterDriverException("Error getting tiles", e);
1143
                                } catch (ServerErrorException e) {
1144
                                        throw new RasterDriverException("Error getting tiles", e);
1145
                                }
1146
                        }
1147
                }
1148
                if(listener != null) 
1149
                        listener.endReading();
1150
                
1151
                return tileList;
1152
        }
1153
        
1154
        /**
1155
         * Reads a tile with gdal and calls the method nextBuffer
1156
         * @param tile
1157
         * @param listener
1158
         * @param bandList
1159
         * @return
1160
         * @throws RasterDriverException
1161
         */
1162
        private synchronized org.gvsig.raster.cache.tile.Tile drawTile(WMTSTile tile, TileListener listener, BandList bandList) throws RasterDriverException {
1163
                WMTSDataParameters p = (WMTSDataParameters)param;
1164
                try {
1165
                        AbstractRasterProvider driver = DefaultProviderServices.loadProvider(tile.getFile());
1166
                        colorTable = driver.getColorTable();
1167
                        bandCount = driver.getBandCount();
1168
                        lastFileTransparency = (DataStoreTransparency)driver.getTransparency();
1169
                        
1170
                        RasterQuery q = RasterLocator.getManager().createQuery();
1171
                        q.setAreaOfInterest(new Rectangle(0, 0, tile.getWidthPx(), tile.getHeightPx()));
1172
                        int[] drawableBands = bandList.getDrawableBands();
1173
                        if(drawableBands.length > 3)
1174
                                drawableBands = new int[]{drawableBands[0], drawableBands[1], drawableBands[2]};
1175
                        q.setDrawableBands(bandList.getDrawableBands());
1176
                        RasterDataStore store = new DefaultRasterStore();
1177
                        store.setProvider(driver);
1178
                        Buffer buf = store.query(q);
1179
                        
1180
                        buf.setDataExtent(new Rectangle2D.Double(
1181
                                        Math.min(tile.getULX(), tile.getLRX()), 
1182
                                        Math.min(tile.getULY(), tile.getLRY()), 
1183
                                        Math.abs(tile.getULX() - tile.getLRX()), 
1184
                                        Math.abs(tile.getULY() - tile.getLRY())));
1185
                        
1186
                        Buffer alphaBand = null;
1187
                        if(p.getAlphaBand() != -1 && listener != null && p.getAlphaBand() < bandCount) {
1188
                                q = RasterLocator.getManager().createQuery();
1189
                                q.setAreaOfInterest(new Rectangle(0, 0, tile.getWidthPx(), tile.getHeightPx()));
1190
                                q.setDrawableBands(new int[]{p.getAlphaBand()});
1191
                                alphaBand = store.query(q);
1192
                        }
1193

    
1194
                        try {
1195
                                store.close();
1196
                        } catch (CloseException e) {
1197
                                logger.info("I cannot close the DataStore", e);
1198
                        }
1199

    
1200

    
1201
                        TileCacheManager m = TileCacheLocator.getManager();
1202
                        org.gvsig.raster.cache.tile.Tile t = m.createTile(-1, tile.getRow(), tile.getCol());
1203
                        t.setData(new Object[]{buf, alphaBand});
1204
                        t.setUl(new Point2D.Double(tile.getULX(), tile.getULY()));
1205
                        t.setLr(new Point2D.Double(tile.getLRX(), tile.getLRY()));
1206
                        t.setDownloaderParams("AffineTransform", getAffineTransform());
1207
                        t.setDownloaderParams("Tiling", new Boolean(true));
1208
                        if(listener != null) 
1209
                                listener.tileReady(t);
1210
                        else 
1211
                                return t;
1212

    
1213
                } catch (ProcessInterruptedException e) {
1214
                } catch (TileGettingException e) {
1215
                        throw new RasterDriverException("Error throwing a tile", e);
1216
                } catch (ProviderNotRegisteredException e) {
1217
                        throw new RasterDriverException("Error throwing a tile", e);
1218
                } catch (InitializeException e) {
1219
                        throw new RasterDriverException("Error throwing a tile", e);
1220
                } catch (QueryException e) {
1221
                        throw new RasterDriverException("Error throwing a tile", e);
1222
                }
1223
                return null;
1224
        }
1225
        
1226
        public Image getImageLegend() {
1227
                try {
1228
                        File file = getOGCClient().getLegendGraphic(
1229
                                        ((WMTSDataParameters)param).getLayer(),
1230
                                        ((WMTSDataParameters)param).getStyle(), 
1231
                                        new ICancellable() {
1232
                                                public boolean isCanceled() {
1233
                                                        return false;
1234
                                                }
1235
                                                
1236
                                                public Object getID() {
1237
                                                        return null;
1238
                                                }
1239
                                        });
1240
                        Image img = null;
1241
                        if ((file != null) && (file.length() > 0)) {
1242
                                img = new ImageIcon(file.getAbsolutePath()).getImage();
1243
                        }
1244
                        return img;
1245
                } catch (Exception e) {
1246
                        logger.info("Problems in GetLegendGraphic", e);
1247
                }
1248
                return null;
1249
        }
1250

    
1251
        public int getBlockSize() {
1252
                return 0;
1253
        }
1254

    
1255
        public void setAffineTransform(AffineTransform t){
1256
                
1257
        }
1258

    
1259
        public int getOverviewCount(int band) throws BandAccessException, RasterDriverException {
1260
                return 0;
1261
        }
1262

    
1263
        public int getOverviewWidth(int band, int overview) throws BandAccessException, RasterDriverException {
1264
                return 0;
1265
        }
1266

    
1267
        public int getOverviewHeight(int band, int overview) throws BandAccessException, RasterDriverException {
1268
                return 0;
1269
        }
1270

    
1271
        public boolean isOverviewsSupported() {
1272
                return false;
1273
        }
1274

    
1275
        public boolean isReproyectable() {
1276
                return false;
1277
        }
1278

    
1279
        public String getProviderName() {
1280
                return NAME;
1281
        }
1282

    
1283
        public String getName() {
1284
            return this.getParameters().getLayer().getTitle();
1285
        }
1286

    
1287
        public WMTSDataParameters getParameters() {
1288
                return (WMTSDataParameters)this.param;
1289
        }
1290
        
1291
        /**
1292
         * Convierte un punto desde coordenadas pixel a coordenadas del mundo.
1293
         * @param pt Punto a transformar
1294
         * @return punto transformado en coordenadas del mundo
1295
         */
1296
        public Point2D rasterToWorld(Point2D pt) {
1297
                Point2D p = new Point2D.Double();
1298
                getAffineTransform().transform(pt, p);
1299
                return p;
1300
        }
1301

    
1302
        /**
1303
         * Convierte un punto desde del mundo a coordenadas pixel.
1304
         * @param pt Punto a transformar
1305
         * @return punto transformado en coordenadas pixel
1306
         */
1307
        public Point2D worldToRaster(Point2D pt) {
1308
                Point2D p = new Point2D.Double();
1309
                try {
1310
                        getAffineTransform().inverseTransform(pt, p);
1311
                } catch (NoninvertibleTransformException e) {
1312
                        return pt;
1313
                }
1314
                return p;
1315
        }
1316
        
1317
        public void setStatus(RasterProvider provider) {
1318
                if(provider instanceof WMTSProvider) {
1319
                }
1320
        }
1321
        
1322
        public File getLastRequest() {
1323
                return lastRequest;
1324
        }
1325
        
1326
        /**
1327
         * ASigna el par?metro de inicializaci?n del driver.
1328
         */
1329
        @Override
1330
        public void setParam(DataStoreProviderServices storeServices, DataStoreParameters param) {
1331
                if(param instanceof WMTSDataParameters)
1332
                        this.uri = ((WMTSDataParameters)param).getURI();
1333
                this.param = param;
1334
                this.storeServices = storeServices;
1335
        }
1336
        
1337
        public String getInfoByPoint(int x, int y, Extent bbox, int w, int h, ICancellable cancellable) throws InfoByPointException {
1338
                int level;
1339
                try {
1340
                        level = getLevelFromRealCoords(bbox.toRectangle2D(), w);
1341
                        return getFeatureInfo(x, y, level);
1342
                } catch (RasterDriverException e) {
1343
                        throw new InfoByPointException("Error in getFeatureInfo", e);
1344
                }
1345
        }
1346
        
1347
        public int getNearestLevel(double pixelSize) {
1348
                double[] pixelSizes = getPixelSizeByLevel();
1349
                for (int i = 0; i < pixelSizes.length - 1; i++) {
1350
                        if(pixelSize <= pixelSizes[i] && pixelSize > pixelSizes[i + 1]) {
1351
                                return i;
1352
                        }
1353
                }
1354
                if(pixelSize < pixelSizes[getZoomLevels() - 1])
1355
                        return getZoomLevels() - 1;
1356
                return 0;
1357
        }
1358
        
1359
        public TileServer getTileServer() {
1360
                if(tileServer == null) {
1361
                        DefaultRasterStore store = new DefaultRasterStore();
1362
                        store.setProvider(this);
1363
                        tileServer = new WMTSTileServer(store, getTileMatrixSetLink());
1364
                }
1365
                return tileServer;
1366
        }
1367
        
1368
        public int[] getTileSize(int level) {
1369
                return getTileServer().getStruct().getTileSizeByLevel(level);
1370
        }
1371

    
1372
        public boolean isRasterEnclosed() {
1373
                return true;
1374
        }
1375
        
1376
        public Buffer getBufferLastRequest() throws ProcessInterruptedException, RasterDriverException {
1377
                return null;
1378
        }
1379
        
1380
        /**
1381
         * Gets the srs code
1382
         * @return
1383
         */
1384
        public String getSRSCode() {
1385
                WMTSDataParameters p = (WMTSDataParameters)param;
1386
                return p.getSRSCode();
1387
        }
1388

    
1389
        public RasterProvider getInternalProvider() {
1390
                return this;
1391
        }
1392
        
1393
        public HistogramComputer getHistogramComputer() {
1394
                if (histogram == null)
1395
                        histogram = new RemoteStoreHistogram(this);
1396
                return histogram;
1397
        }
1398
}