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

History | View | Annotate | Download (49.3 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.WMTSBoundingBox;
100
import org.gvsig.raster.wmts.ogc.struct.WMTSLayer;
101
import org.gvsig.raster.wmts.ogc.struct.WMTSTile;
102
import org.gvsig.raster.wmts.ogc.struct.WMTSTileMatrix;
103
import org.gvsig.raster.wmts.ogc.struct.WMTSTileMatrixLimits;
104
import org.gvsig.raster.wmts.ogc.struct.WMTSTileMatrixSet;
105
import org.gvsig.raster.wmts.ogc.struct.WMTSTileMatrixSetLink;
106
import org.gvsig.tools.ToolsLocator;
107
import org.slf4j.Logger;
108
import org.slf4j.LoggerFactory;
109
/**
110
 * Provider for WMTS service
111
 *
112
 * @author Nacho Brodin (nachobrodin@gmail.com)
113
 */
114
public class WMTSProvider extends AbstractRasterProvider implements RemoteRasterProvider, TiledRasterProvider {
115
        public static String                NAME                     = "Wmts Store";
116
        public static String                DESCRIPTION              = "Wmts Raster file";
117
        public static final String          METADATA_DEFINITION_NAME = "WmtsStore";
118
        private static Logger               logger                   = LoggerFactory.getLogger(WMTSProvider.class);
119
        public static boolean               TILED                    = true;
120
        
121
        //Los tiles se piden de forma secuencial y sin lanzar threads para ello (+Lento)
122
        public static int                   SEQUENTIAL               = 0;
123
        //Los tiles se piden en threads y hay un thread manager para gestionar que no se pidan m?s de cierto n?mero
124
        public static int                   LIMITED_THREADS          = 1;
125
        //Los tiles se piden en threads y se lanzan tantos threads como tiles haya
126
        public static int                   UNLIMITED_THREADS        = 2;
127
        private int                         requestType              = LIMITED_THREADS;
128
        
129
        private static final double         MTS_X_GRADO              = 111319.490793274;
130
        
131
        private Extent                      viewRequest              = null;
132
        private WMTSClient                  ogcClient                = null;
133
        //private static Hashtable<URL, WMTSConnector>    
134
        //                                    drivers                  = new Hashtable<URL, WMTSConnector> ();
135
        private boolean                     open                     = false;
136
        private File                        lastRequest              = null;
137
        private DataStoreTransparency       lastFileTransparency     = null;
138
        private int                         lastWidthRequest         = 0;
139
        private int                         lastHeightRequest        = 0;
140
        private WMTSStatus                  lastStatus               = null;
141
        private boolean                     gridSubsets              = true;
142
        private Extent[]                    extentByLevel            = null; //Only for layers without gridSubsets
143
        private Extent                      bbox                     = null;
144
        private MathUtils                   math                     = RasterLocator.getManager().getMathUtils();
145
        
146
        /**
147
         * This thread manages the number of tiles that have been thrown.
148
         * This number is controlled by the NTHREADS_QUEUE variable.
149
         * 
150
         * @author Nacho Brodin (nachobrodin@gmail.com)
151
         */
152
        public class RequestThreadManager extends Thread {
153
                private TilePipe               pipe           = null;
154
                private List<WMTSTile>         tiles          = null;
155
                private WMTSStatus             status         = null;
156
                
157
                public RequestThreadManager(TilePipe pipe, List<WMTSTile> tiles, WMTSStatus status) {
158
                        this.pipe = pipe;
159
                        this.tiles = tiles;
160
                        this.status = status;
161
                }
162
                
163
                public void run() {
164
                        for (int i = 0; i < tiles.size(); i++) {
165
                                WMTSTile tile = tiles.get(i);
166
                                WMTSStatus statusCopy = status.cloneStatus();
167
                                statusCopy.setTileRow(tile.getRow());
168
                                statusCopy.setTileCol(tile.getCol());
169
                                if (pipe.getSize() > TilePipe.NTHREADS_QUEUE) {
170
                                        try {
171
                                                synchronized (this) {
172
                                                        wait();                                                        
173
                                                }
174
                                        } catch( InterruptedException e ) {
175
                                        }
176
                                }
177
                                new RequestTileLauncher(pipe, statusCopy, tile).start();
178
                        }
179
                }
180
        }
181
        
182
        /**
183
         * Thread to download a tile
184
         * @author Nacho Brodin (nachobrodin@gmail.com)
185
         */
186
        class RequestTileLauncher extends Thread {
187
                private TilePipe      pipe    = null;
188
                private WMTSStatus    status  = null;
189
                private WMTSTile      tile    = null;
190

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

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

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

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

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

    
493
        /**
494
         * When a layer doesn't have grid subsets this will have a different bounding
495
         * box by resolution level. This function calculates and returns the array of
496
         * extents, one by resolution level.
497
         * @return
498
         */
499
        public Extent[] getExtentByResolutionLevel() {
500
                if(extentByLevel == null) {
501
                        WMTSDataParameters p = (WMTSDataParameters)parameters;
502
                        WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
503
                        WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
504
                        
505
                    double widthMtsTile = 0;
506
                    double heightMtsTile = 0;
507
                        List<WMTSTileMatrix> tileMatrixList = tileMatrixSet.getTileMatrix();
508
                        extentByLevel = new ExtentImpl[tileMatrixList.size()];
509
                        double minX = 0;
510
                        double minY = 0;
511
                        double maxX = 0;
512
                        double maxY = 0;
513
                        for (int i = 0; i < tileMatrixList.size(); i++) {
514
                                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixList.get(i);
515
                            if(!p.isProjected()) {
516
                                    widthMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / (MTS_X_GRADO * 1000);
517
                                    heightMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / (MTS_X_GRADO * 1000);
518
                            } else {
519
                                    widthMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / 1000;
520
                                    heightMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / 1000;
521
                            }
522
                            
523
                            double h = Math.abs(tileMatrix.getTopLeftCorner()[0] - (tileMatrix.getTopLeftCorner()[0] - (tileMatrix.getMatrixHeight() * heightMtsTile)));
524
                            Rectangle2D r = new Rectangle2D.Double(
525
                                            tileMatrix.getTopLeftCorner()[1], 
526
                                            tileMatrix.getTopLeftCorner()[0] - h,
527
                                            Math.abs(tileMatrix.getTopLeftCorner()[1] - (tileMatrix.getTopLeftCorner()[1] + (tileMatrix.getMatrixWidth() * widthMtsTile))),
528
                                            h);
529
                            extentByLevel[i] = new ExtentImpl(r);
530
                            if(i == 0) {
531
                                    minX = extentByLevel[i].getMin().getX();
532
                                    minY = extentByLevel[i].getMin().getY();
533
                                    maxX = extentByLevel[i].getMax().getX();
534
                                    maxY = extentByLevel[i].getMax().getY();
535
                            } else {
536
                                    minX = Math.min(minX, extentByLevel[i].getMin().getX());
537
                                    minY = Math.min(minY, extentByLevel[i].getMin().getY());
538
                                    maxX = Math.max(maxX, extentByLevel[i].getMax().getX());
539
                                    maxY = Math.max(maxY, extentByLevel[i].getMax().getY());
540
                            }
541
                        }
542
                        bbox = new ExtentImpl(minX, maxY, maxX, minY);
543
                }
544
                return extentByLevel;
545
        }
546
        
547
        public Rectangle2D getLayerExtent(String layerName, String srs) throws RemoteServiceException {
548
                return null;
549
        }
550

    
551
        public RasterProvider load() {
552
                return this;
553
        }
554
        
555
        public boolean isOpen() {
556
                return open;
557
        }
558

    
559
        public void close() {
560
                open = false;
561
        }
562
        
563
        public Transparency getTransparency() {
564
                if(lastFileTransparency == null) {
565
                        lastFileTransparency = new DataStoreTransparency(getColorInterpretation());
566
                        lastFileTransparency.setTransparencyBand(3);
567
                }
568
                return lastFileTransparency;
569
        }
570
        
571
        public NoData getNoDataValue() {
572
                NoData nodata = super.getNoDataValue();
573
                if(nodata != null)
574
                        nodata.setNoDataTransparent(false);
575
                return noData;
576
        }
577

    
578
        public String translateFileName(String fileName) {
579
                return fileName;
580
        }
581

    
582
        public void setView(Extent e) {
583
                viewRequest = e;
584
        }
585

    
586
        public Extent getView() {
587
                return viewRequest;
588
        }
589

    
590
        public double getWidth() {
591
                WMTSDataParameters p = (WMTSDataParameters)parameters;
592
                if (lastWidthRequest <= 0) 
593
                        return p.getWidth();
594
                return lastWidthRequest;
595
        }
596

    
597
        public double getHeight() {
598
                WMTSDataParameters p = (WMTSDataParameters)parameters;
599
                if (lastHeightRequest <= 0) 
600
                        return p.getHeight();
601
                return lastHeightRequest;
602
        }
603

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

    
620
        /**
621
         * Reads a complete block of data and returns an tridimensional array of the right type. This function is useful
622
         * to read a file very fast without setting a view. In a WMTS service when the size is fixed then it will read the
623
         * entire image but when the source hasn't pixel size it will read a sample of data. This set of data will have
624
         * the size defined in FIXED_SIZE. 
625
         * 
626
         * @param pos Posici?n donde se empieza  a leer
627
         * @param blockHeight Altura m?xima del bloque leido
628
         * @return Object que es un array tridimendional del tipo de datos del raster. (Bandas X Filas X Columnas)
629
         * @throws InvalidSetViewException
630
         * @throws FileNotOpenException
631
         * @throws RasterDriverException
632
         */
633
        public Object readBlock(int pos, int blockHeight, double scale) 
634
        throws InvalidSetViewException, FileNotOpenException, RasterDriverException, ProcessInterruptedException {
635
                return null;
636
        }
637
        
638
        public Object getData(int x, int y, int band)
639
                throws InvalidSetViewException, FileNotOpenException, RasterDriverException {
640
                return null;
641
        }
642
        
643
        /**
644
         * Assigns the list of bands RGB and read a window of data
645
         * @param rasterBuf
646
         * @param bandList
647
         * @param lastFile
648
         * @param ulx
649
         * @param uly
650
         * @param lrx
651
         * @param lry
652
         * @return
653
         * @throws RasterDriverException
654
         * @throws ProcessInterruptedException
655
         */
656
        public Buffer getBuffer(Buffer rasterBuf, BandList bandList, File lastFile, 
657
                        double ulx, double uly, double lrx, double lry) throws RasterDriverException, ProcessInterruptedException {
658
                return null;
659
        }
660
        
661
        /**
662
         * Gets the tile matrix from the selected level
663
         * @param level
664
         * @return
665
         */
666
        private WMTSTileMatrix getTileMatrixByLevel(int level) {
667
                level = adjustLevel(level);
668
                
669
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
670
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
671
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
672
                
673
                WMTSTileMatrixLimits tileMatrixLimits = null;
674
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(level);
675
                if(hasGridSubsets()) {
676
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(level);
677
                        tileMatrix = tileMatrixLimits.getTileMatrix();
678
                }
679
                return tileMatrix;
680
        }
681
        
682
        /**
683
         * Returns the number of levels
684
         * @return
685
         */
686
        public int getZoomLevels() {
687
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
688
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
689
                if(hasGridSubsets()) {
690
                        List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
691
                        return Math.min(tileMatrixSet.getTileMatrix().size(), tileMatrixSetLimits.size());
692
                }
693
                return tileMatrixSet.getTileMatrix().size();
694
                
695
        }
696
        
697
        public Extent getCoordsInTheNearestLevel(Extent extent, int w, int h) {
698
                double[] pixelSizes = getPixelSizeByLevel();
699
                double currentPixelSize = extent.width() / (double)w;
700
                
701
                int level = 0;
702
                for (int i = 0; i < (pixelSizes.length - 1); i++) {
703
                        if(currentPixelSize < pixelSizes[i] && currentPixelSize >= pixelSizes[i + 1]) {
704
                                level = i + 1;
705
                                break;
706
                        }
707
                }
708
                
709
                return getZoomLevelCoordinates(level, extent, w, h);
710
        }
711
        
712
        public Extent getCoordsInLevel(Point2D viewCenter, int level, int w, int h) {
713
                WMTSDataParameters p = (WMTSDataParameters)param;
714
                level = adjustLevel(level);
715
                WMTSTileMatrix tileMatrix = getTileMatrixByLevel(level);
716
                
717
                boolean proj = p.isProjected();
718
                
719
                double psX = tileMatrix.getWidthWCTile(proj) / tileMatrix.getTileWidth();
720
                double psY = tileMatrix.getHeightWCTile(proj) / tileMatrix.getTileHeight();
721
                
722
                double ulx = viewCenter.getX() - ((w / 2) * psX);
723
                double uly = viewCenter.getY() - ((h / 2) * psY);
724
                double lrx = ulx + (w * psX);
725
                double lry = uly + (h * psY);
726
                return new ExtentImpl(ulx, uly, lrx, lry);
727
        }
728
        
729
        /**
730
         * Calculates the extent of a zoom level using other extent as a reference. The new extent is 
731
         * calculated with the same coordinate at the center. 
732
         * @param level
733
         * @param extent
734
         * @param w
735
         * @param h
736
         * @return
737
         */
738
        public Extent getZoomLevelCoordinates(int level, Extent extent, int w, int h) {
739
                double centerX = extent.getCenterX();
740
                double centerY = extent.getCenterY();
741
                return getCoordsInLevel(new Point2D.Double(centerX, centerY), level, w, h);
742
        }
743
        
744
        /**
745
         * Returns a list of pixel sizes by level
746
         * @return
747
         */
748
        public double[] getPixelSizeByLevel() {
749
                WMTSDataParameters p = (WMTSDataParameters)param;
750
                double[] list = new double[getZoomLevels()];
751
                
752
                for (int i = 0; i < getZoomLevels(); i++) {
753
                        WMTSTileMatrix tileMatrix = getTileMatrixByLevel(i);
754
                        list[i] = math.adjustDouble(tileMatrix.getWidthWCTile(p.isProjected()) / tileMatrix.getTileWidth());
755
                }
756
                return list;
757
        }
758
        
759
        /**
760
         * Adjust de level to the range
761
         * @param level
762
         * @return
763
         */
764
        private int adjustLevel(int level) {
765
                if(level < 0)
766
                        level = 0;
767
                if(level > getZoomLevels())
768
                        level = getZoomLevels();
769
                return level;
770
        }
771
        
772
        public org.gvsig.raster.cache.tile.Tile getTile(SpiRasterQuery q) throws TileGettingException {
773
                //q.getResolutionLevel(), q.getTileCol(), q.getTileRow(), q.getBBox(), q.getCacheStruct()!
774
                
775
                CacheStruct str = getTileServer().getStruct();
776
                
777
                //1-Selecci?n de WMTSTileMatrixSet por srs
778
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
779
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
780
                List<WMTSTileMatrixLimits> tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
781
                
782
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(q.getResolutionLevel());
783
                if(gridSubsets) {
784
                        WMTSTileMatrixLimits tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(q.getResolutionLevel());
785
                        tileMatrix = tileMatrixLimits.getTileMatrix();
786
                }
787
                int bufWidth = tileMatrix.getTileWidth();
788
                int bufHeight = tileMatrix.getTileHeight();
789
                
790
                try {
791
                        Extent adjBbox = q.getAdjustedRequestBoundingBox();
792
                        Rectangle2D r = adjBbox.toRectangle2D();//new Rectangle2D.Double(Math.min(minX, maxX), Math.min(minY, maxY), Math.abs(maxX - minX), Math.abs(maxY - minY));
793
                        WMTSStatus status = buildWMTSStatus(r, bufWidth , bufHeight);
794
                        
795
                        int[] size = str.getTileSizeByLevel(q.getResolutionLevel());
796
                        WMTSTile tile = WMTSOGCLocator.getManager().createTile(
797
                                        size, 
798
                                        new int[]{q.getTileRow(), q.getTileCol()}, 
799
                                        new double[]{adjBbox.getULX(), adjBbox.getULY(), adjBbox.getLRX(), adjBbox.getLRY()});
800
                        
801
                        File file = getOGCClient().getTile(status, null);
802
                        tile.setFile(file);
803
                        //Creamos un BandList con todas las bandas del fichero
804
                        BandList bandList = new BandListImpl();
805
                        for(int i = 0; i < getBandCount(); i++) {
806
                                try {
807
                                        DatasetBand band = new DatasetBandImpl(getURIOfFirstProvider(), i, getDataType()[i], getBandCount());
808
                                        bandList.addBand(band);
809
                                } catch(BandNotFoundInListException e) {
810
                                        //No a?adimos la banda
811
                                }
812
                        }
813
                        return drawTile(tile, null, bandList);
814
                } catch (WMTSException e) {
815
                        throw new TileGettingException("Error getting tiles", e);
816
                } catch (ServerErrorException e) {
817
                        throw new TileGettingException("Error getting tiles", e);
818
                } catch (RasterDriverException e) {
819
                        throw new TileGettingException("Error getting tiles", e);
820
                }
821
        }
822
        
823
        @Override
824
        public void loadBuffer(SpiRasterQuery q) 
825
                        throws ProcessInterruptedException, RasterDriverException {
826
                Rectangle2D r = q.getAdjustedRequestBoundingBox().toRectangle2D();//new Rectangle2D.Double(Math.min(minX, maxX), Math.min(minY, maxY), Math.abs(maxX - minX), Math.abs(maxY - minY));
827
                WMTSStatus status = buildWMTSStatus(r, q.getAdjustedWidth(), q.getAdjustedBufHeight());
828
                request(status, q.getBandList(), q.getTileListener(), requestType);
829
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, q.getBandList(), null, requestType);
830
                MemoryTileMatrixBuffer matrixBuffer = new MemoryTileMatrixBuffer(tileList);
831
                Buffer b = matrixBuffer.getWindow(q.getAdjustedRequestBoundingBox(), q.getBufWidth(), q.getBufHeight(), q.getBandList().getDrawableBandsCount());
832
                q.setBufferResult(b);
833
        }
834
        
835
        /*public void getWindow(Extent ex, int bufWidth, int bufHeight, 
836
                        BandList bandList, TileListener listener, TaskStatus taskStatus) throws ProcessInterruptedException, RasterDriverException {
837
                Rectangle2D r = ex.toRectangle2D();//new Rectangle2D.Double(Math.min(minX, maxX), Math.min(minY, maxY), Math.abs(maxX - minX), Math.abs(maxY - minY));
838
                WMTSStatus status = buildWMTSStatus(r, bufWidth, bufHeight);
839
                request(status, bandList, listener, requestType);
840
        }
841
        
842
        public Buffer getWindow(Extent extent, int bufWidth, int bufHeight, 
843
                        BandList bandList, Buffer rasterBuf, boolean adjustToExtent, TaskStatus taskStatus) throws ProcessInterruptedException, RasterDriverException {
844
                Rectangle2D r = extent.toRectangle2D();//new Rectangle2D.Double(Math.min(ulx, lrx), Math.min(lry, uly), Math.abs(lrx - ulx), Math.abs(uly - lry));
845
                WMTSStatus status = buildWMTSStatus(r, bufWidth, bufHeight);
846
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, bandList, null, requestType);
847
                MemoryTileMatrixBuffer matrixBuffer = new MemoryTileMatrixBuffer(tileList);
848
                return matrixBuffer.getWindow(extent, rasterBuf);
849
        }
850
        
851
        public Buffer getWindow(Extent extent, BandList bandList, Buffer rasterBuf, TaskStatus taskStatus) 
852
                throws ProcessInterruptedException, RasterDriverException {
853
                lastWidthRequest = rasterBuf.getWidth();
854
                lastHeightRequest = rasterBuf.getHeight();
855
                Rectangle2D r = extent.toRectangle2D();//new Rectangle2D.Double(Math.min(ulx, lrx), Math.min(lry, uly), Math.abs(lrx - ulx), Math.abs(uly - lry));
856
                WMTSStatus status = buildWMTSStatus(r, lastWidthRequest, lastHeightRequest);
857
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, bandList, null, requestType);
858
                MemoryTileMatrixBuffer matrixBuffer = new MemoryTileMatrixBuffer(tileList);
859
                return matrixBuffer.getWindow(extent, rasterBuf);
860
        }
861

862
        public Buffer getWindow(double ulx, double uly, double w, double h, 
863
                        BandList bandList, Buffer rasterBuf, boolean adjustToExtent, TaskStatus taskStatus) throws ProcessInterruptedException, RasterDriverException {
864
                lastWidthRequest = rasterBuf.getWidth();
865
                lastHeightRequest = rasterBuf.getHeight();
866
                Rectangle2D r = new Rectangle2D.Double(ulx, uly - h, w, h);
867
                WMTSStatus status = buildWMTSStatus(r, lastWidthRequest, lastHeightRequest);
868
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, bandList, null, requestType);
869
                MemoryTileMatrixBuffer matrixBuffer = new MemoryTileMatrixBuffer(tileList);
870
                return matrixBuffer.getWindow(new ExtentImpl(ulx, uly, ulx + w, uly - h), rasterBuf);
871
        }
872

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

    
1215
                        try {
1216
                                store.close();
1217
                        } catch (CloseException e) {
1218
                                logger.info("I cannot close the DataStore", e);
1219
                        }
1220

    
1221

    
1222
                        TileCacheManager m = TileCacheLocator.getManager();
1223
                        org.gvsig.raster.cache.tile.Tile t = m.createTile(-1, tile.getRow(), tile.getCol());
1224
                        t.setData(new Object[]{buf, alphaBand});
1225
                        t.setUl(new Point2D.Double(tile.getULX(), tile.getULY()));
1226
                        t.setLr(new Point2D.Double(tile.getLRX(), tile.getLRY()));
1227
                        t.setDownloaderParams("AffineTransform", getAffineTransform());
1228
                        t.setDownloaderParams("Tiling", new Boolean(true));
1229
                        if(listener != null) 
1230
                                listener.tileReady(t);
1231
                        else 
1232
                                return t;
1233

    
1234
                } catch (ProcessInterruptedException e) {
1235
                } catch (TileGettingException e) {
1236
                        throw new RasterDriverException("Error throwing a tile", e);
1237
                } catch (ProviderNotRegisteredException e) {
1238
                        throw new RasterDriverException("Error throwing a tile", e);
1239
                } catch (InitializeException e) {
1240
                        throw new RasterDriverException("Error throwing a tile", e);
1241
                } catch (QueryException e) {
1242
                        throw new RasterDriverException("Error throwing a tile", e);
1243
                }
1244
                return null;
1245
        }
1246
        
1247
        public Image getImageLegend() {
1248
                try {
1249
                        File file = getOGCClient().getLegendGraphic(
1250
                                        ((WMTSDataParameters)param).getLayer(),
1251
                                        ((WMTSDataParameters)param).getStyle(), 
1252
                                        new ICancellable() {
1253
                                                public boolean isCanceled() {
1254
                                                        return false;
1255
                                                }
1256
                                                
1257
                                                public Object getID() {
1258
                                                        return null;
1259
                                                }
1260
                                        });
1261
                        Image img = null;
1262
                        if ((file != null) && (file.length() > 0)) {
1263
                                img = new ImageIcon(file.getAbsolutePath()).getImage();
1264
                        }
1265
                        return img;
1266
                } catch (Exception e) {
1267
                        logger.info("Problems in GetLegendGraphic", e);
1268
                }
1269
                return null;
1270
        }
1271

    
1272
        public int getBlockSize() {
1273
                return 0;
1274
        }
1275

    
1276
        public void setAffineTransform(AffineTransform t){
1277
                
1278
        }
1279

    
1280
        public int getOverviewCount(int band) throws BandAccessException, RasterDriverException {
1281
                return 0;
1282
        }
1283

    
1284
        public int getOverviewWidth(int band, int overview) throws BandAccessException, RasterDriverException {
1285
                return 0;
1286
        }
1287

    
1288
        public int getOverviewHeight(int band, int overview) throws BandAccessException, RasterDriverException {
1289
                return 0;
1290
        }
1291

    
1292
        public boolean isOverviewsSupported() {
1293
                return false;
1294
        }
1295

    
1296
        public boolean isReproyectable() {
1297
                return false;
1298
        }
1299

    
1300
        public String getName() {
1301
                return NAME;
1302
        }
1303
        
1304
        /**
1305
         * Convierte un punto desde coordenadas pixel a coordenadas del mundo.
1306
         * @param pt Punto a transformar
1307
         * @return punto transformado en coordenadas del mundo
1308
         */
1309
        public Point2D rasterToWorld(Point2D pt) {
1310
                Point2D p = new Point2D.Double();
1311
                getAffineTransform().transform(pt, p);
1312
                return p;
1313
        }
1314

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

    
1385
        public boolean isRasterEnclosed() {
1386
                return true;
1387
        }
1388
        
1389
        public Buffer getBufferLastRequest() throws ProcessInterruptedException, RasterDriverException {
1390
                return null;
1391
        }
1392
        
1393
        /**
1394
         * Gets the srs code
1395
         * @return
1396
         */
1397
        public String getSRSCode() {
1398
                WMTSDataParameters p = (WMTSDataParameters)param;
1399
                return p.getSRSCode();
1400
        }
1401

    
1402
        public RasterProvider getInternalProvider() {
1403
                return this;
1404
        }
1405
        
1406
        public HistogramComputer getHistogramComputer() {
1407
                if (histogram == null)
1408
                        histogram = new RemoteStoreHistogram(this);
1409
                return histogram;
1410
        }
1411
}