Statistics
| Revision:

gvsig-raster / org.gvsig.raster.wmts / branches / org.gvsig.raster.wmts_dataaccess_refactoring / org.gvsig.raster.wmts.io / src / main / java / org / gvsig / raster / wmts / io / WMTSProvider.java @ 2289

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

    
36
import javax.swing.ImageIcon;
37

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

    
185
                public RequestTileLauncher(TilePipe pipe, WMTSStatus status, WMTSTile tile) {
186
                        this.pipe = pipe;
187
                        this.status = status;
188
                        this.tile = tile;
189
                }
190

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

    
222
        public static void register() {
223
                DataManagerProviderServices dataman = (DataManagerProviderServices) DALLocator.getDataManager();
224
                if (dataman != null && !dataman.getStoreProviders().contains(NAME)) {
225
                        dataman.registerStoreProvider(NAME,
226
                                        WMTSProvider.class, WMTSDataParametersImpl.class);
227
                }
228

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

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

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

    
543
        public RasterProvider load() {
544
                return this;
545
        }
546
        
547
        public boolean isOpen() {
548
                return open;
549
        }
550

    
551
        public void close() {
552
                open = false;
553
        }
554
        
555
        public Transparency getTransparency() {
556
                if(lastFileTransparency == null) {
557
                        lastFileTransparency = new DataStoreTransparency();
558
                        lastFileTransparency.setTransparencyBand(3);
559
                }
560
                return lastFileTransparency;
561
        }
562

    
563
        public String translateFileName(String fileName) {
564
                return fileName;
565
        }
566

    
567
        public void setView(Extent e) {
568
                viewRequest = e;
569
        }
570

    
571
        public Extent getView() {
572
                return viewRequest;
573
        }
574

    
575
        public double getWidth() {
576
                WMTSDataParameters p = (WMTSDataParameters)parameters;
577
                if (lastWidthRequest <= 0) 
578
                        return p.getWidth();
579
                return lastWidthRequest;
580
        }
581

    
582
        public double getHeight() {
583
                WMTSDataParameters p = (WMTSDataParameters)parameters;
584
                if (lastHeightRequest <= 0) 
585
                        return p.getHeight();
586
                return lastHeightRequest;
587
        }
588

    
589
        public Object readCompleteLine(int line, int band)
590
                throws InvalidSetViewException, FileNotOpenException, RasterDriverException {
591
                return null;
592
        }
593
        
594
        /**
595
         * When the remote layer has fixed size this method downloads the file and return its reference. 
596
         * File layer has in the long side FIXED_SIZE pixels and the bounding box is complete. This file could be
597
         * useful to build an histogram or calculate statistics. This represents a sample of data.
598
         * @return
599
         * @throws RasterDriverException
600
         */
601
        public File getFileLayer() throws RasterDriverException {
602
                return null;
603
        }
604

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

    
840
        public Buffer getWindow(double ulx, double uly, double w, double h, 
841
                        BandList bandList, Buffer rasterBuf, boolean adjustToExtent, TaskStatus taskStatus) throws ProcessInterruptedException, RasterDriverException {
842
                lastWidthRequest = rasterBuf.getWidth();
843
                lastHeightRequest = rasterBuf.getHeight();
844
                Rectangle2D r = new Rectangle2D.Double(ulx, uly - h, w, h);
845
                WMTSStatus status = buildWMTSStatus(r, lastWidthRequest, lastHeightRequest);
846
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, bandList, null, requestType);
847
                MemoryTileMatrixBuffer matrixBuffer = new MemoryTileMatrixBuffer(tileList);
848
                return matrixBuffer.getWindow(new ExtentImpl(ulx, uly, ulx + w, uly - h), rasterBuf);
849
        }
850

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

    
1208
                        for (int j = 0; j < bandList.getBandCount(); j++) {
1209
                                bandList.getBand(j).setFileName(serverName);
1210
                        }
1211

    
1212
                        driver.close();
1213

    
1214

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

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

    
1263
        public int getBlockSize() {
1264
                return 0;
1265
        }
1266

    
1267
        public void setAffineTransform(AffineTransform t){
1268
                
1269
        }
1270

    
1271
        public int getOverviewCount(int band) throws BandAccessException, RasterDriverException {
1272
                return 0;
1273
        }
1274

    
1275
        public int getOverviewWidth(int band, int overview) throws BandAccessException, RasterDriverException {
1276
                return 0;
1277
        }
1278

    
1279
        public int getOverviewHeight(int band, int overview) throws BandAccessException, RasterDriverException {
1280
                return 0;
1281
        }
1282

    
1283
        public boolean isOverviewsSupported() {
1284
                return false;
1285
        }
1286

    
1287
        public boolean isReproyectable() {
1288
                return false;
1289
        }
1290

    
1291
        public String getName() {
1292
                return NAME;
1293
        }
1294
        
1295
        /**
1296
         * Convierte un punto desde coordenadas pixel a coordenadas del mundo.
1297
         * @param pt Punto a transformar
1298
         * @return punto transformado en coordenadas del mundo
1299
         */
1300
        public Point2D rasterToWorld(Point2D pt) {
1301
                Point2D p = new Point2D.Double();
1302
                getAffineTransform().transform(pt, p);
1303
                return p;
1304
        }
1305

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

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

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