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

History | View | Annotate | Download (46.9 KB)

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

    
24
import java.awt.geom.AffineTransform;
25
import java.awt.geom.NoninvertibleTransformException;
26
import java.awt.geom.Point2D;
27
import java.awt.geom.Rectangle2D;
28
import java.io.File;
29
import java.io.IOException;
30
import java.net.MalformedURLException;
31
import java.net.URL;
32
import java.util.ArrayList;
33
import java.util.Hashtable;
34

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

    
171
                public RequestTileLauncher(TilePipe pipe, WMTSStatus status, Tile tile) {
172
                        this.pipe = pipe;
173
                        this.status = status;
174
                        this.tile = tile;
175
                }
176

    
177
                public void run() {
178
                        try {
179
                                //File file = getConnector().getTile(status, null);
180
                                URL url = getConnector().getTileURL(status);
181
                                tile.file = getConnector().downloadFile(url, null);
182
                                pipe.setTile(tile);
183
                        } catch (DownloadException e) {
184
                        //} catch (ServerErrorException e) {
185
                        } catch (MalformedURLException e) {
186
                                // TODO Auto-generated catch block
187
                                e.printStackTrace();
188
                        } catch (WMTSException e) {
189
                                // TODO Auto-generated catch block
190
                                e.printStackTrace();
191
                        }
192
                }
193
        }
194
        
195
        /**
196
         * Point information 
197
         * @author Nacho Brodin (nachobrodin@gmail.com)
198
         */
199
        public class PointInfo {
200
                public Point2D worldCoord;
201
                public Point2D tile;
202
                public Point2D pixelInTile;
203
                public int     level;
204
                
205
                public PointInfo(Point2D worldCoord) {
206
                        this.worldCoord = worldCoord;
207
                }
208
        }
209

    
210
        public static void register() {
211
                ExtensionPointManager extensionPoints = ToolsLocator.getExtensionPointManager();
212
                ExtensionPoint point = extensionPoints.get("RasterReader");
213
                point.append("wmts", "", WMTSProvider.class);
214
                
215
                DataManagerProviderServices dataman = (DataManagerProviderServices) DALLocator.getDataManager();
216
                if (dataman != null && !dataman.getStoreProviders().contains(NAME)) {
217
                        dataman.registerStoreProvider(NAME,
218
                                        WMTSProvider.class, WMTSDataParametersImpl.class);
219
                }
220

    
221
                if (!dataman.getExplorerProviders().contains(WMTSServerExplorerImpl.NAME)) {
222
                        dataman.registerExplorerProvider(WMTSServerExplorer.NAME, WMTSServerExplorerImpl.class, DefaultWMTSServerExplorerParameters.class);
223
                }
224
                dataman.registerStoreFactory(NAME, DefaultStoreFactory.class);
225
        }
226
        
227
        public WMTSProvider() throws NotSupportedExtensionException {
228
                super();
229
        }
230
        
231
        /**
232
         * Constructor. Abre el dataset.
233
         * @param proj Proyecci?n
234
         * @param fName Nombre del fichero
235
         * @throws NotSupportedExtensionException
236
         */
237
        public WMTSProvider(String params) throws NotSupportedExtensionException {
238
                super(params);
239
                if(params instanceof String) {
240
                        WMTSDataParametersImpl p = new WMTSDataParametersImpl();
241
                        p.setHost((String)params);
242
                        super.init(p, null, ToolsLocator.getDynObjectManager()
243
                                        .createDynObject(
244
                                                        MetadataLocator.getMetadataManager().getDefinition(
245
                                                                        DataStore.METADATA_DEFINITION_NAME)));
246
                        init(p, null);
247
                }
248
        }
249
        
250
        public WMTSProvider(WMTSDataParametersImpl params,
251
                        AbstractRasterDataStore storeServices) throws NotSupportedExtensionException {
252
                super(params, storeServices, ToolsLocator.getDynObjectManager()
253
                                .createDynObject(
254
                                                MetadataLocator.getMetadataManager().getDefinition(
255
                                                                DataStore.METADATA_DEFINITION_NAME)));
256
                init(params, storeServices);
257
        }
258
        
259
        /**
260
         * Gets the connector from the URL
261
         * @return
262
         * @throws RemoteServiceException
263
         */
264
        public WMTSConnector getConnector() throws WMTSException {
265
                WMTSDataParametersImpl p = (WMTSDataParametersImpl)parameters;
266
                URL url = null;
267
                try {
268
                        url = new URL(p.getHost());
269
                } catch (Exception e) {
270
                        throw new WMTSException("Malformed URL",e);
271
                }
272
                try {
273
                        return WMTSProvider.getConnectorFromURL(url);
274
                } catch (IOException e) {
275
                        throw new WMTSException("Error getting the connector",e);
276
                }
277
        }
278
        
279
        /**
280
         * Crea las referencias al fichero y carga
281
         * las estructuras con la informaci?n y los metadatos.
282
         * @param proj Proyecci?n
283
         * @param param Parametros de carga
284
         * @throws NotSupportedExtensionException
285
         */
286
        public void init (DataStoreParameters params,
287
                        DataStoreProviderServices storeServices) throws NotSupportedExtensionException {
288
                setParam(params);
289
                if(((WMTSDataParameters)params).getImageFormat().compareTo("image/gif") == 0) {
290
                        setDataType(new int[]{Buffer.TYPE_BYTE});
291
                        bandCount = 1;
292
                } else {
293
                        setDataType(new int[]{Buffer.TYPE_BYTE, Buffer.TYPE_BYTE, Buffer.TYPE_BYTE, Buffer.TYPE_BYTE});
294
                        bandCount = 4;
295
                }
296
                
297
                if(!(param instanceof WMTSDataParameters))
298
                        return;
299
                
300
                gridSubsets = hasGridSubsets((WMTSDataParameters)param);
301
        }
302
        
303
        /**
304
         * Returns true if this layer has grid subsets
305
         * @return
306
         */
307
        public boolean hasGridSubsets() {
308
                return gridSubsets;
309
        }
310
        
311
        /**
312
         * Checks if this layer has grid subsets or doesn't
313
         * @param p
314
         * @return
315
         */
316
        @SuppressWarnings("unchecked")
317
        private boolean hasGridSubsets(WMTSDataParameters p) {
318
                ArrayList tileMatrixSetLimits = null;
319
                ArrayList<?> tileMatrixSetLinkList = p.getLayer().getTileMatrixSetLink();
320
                String srs = p.getSRSCode();
321
                for (int i = 0; i < tileMatrixSetLinkList.size(); i++) {
322
                        WMTSTileMatrixSetLink tileMatrixSetLink = (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(i);
323
                        WMTSTileMatrixSet tms = tileMatrixSetLink.getTileMatrixSet();
324
                        ArrayList tmsl = tileMatrixSetLink.getTileMatrixLimits();
325
                        String srsTileSet = tms.getSupportedCRS();
326
                        if(srsTileSet.compareTo(srs) == 0) {
327
                                tileMatrixSetLimits = tmsl;
328
                        }
329
                }
330
                
331
                return tileMatrixSetLimits.size() <= 0 ? false : true; 
332
        }
333
        
334
        public static final WMTSConnector getConnectorFromURL(URL url) throws IOException {
335
                WMTSConnector drv = (WMTSConnector) drivers.get(url);
336
                if (drv == null) {
337
                        drv = new WMTSConnector(url);
338
                        drivers.put(url, drv);
339
                }
340
                return drv;
341
        }
342
        
343
        /**
344
         * Obtiene el objeto que contiene que contiene la interpretaci?n de
345
         * color por banda
346
         * @return
347
         */
348
        public DataStoreColorInterpretation getColorInterpretation() {
349
                if(colorInterpretation == null) {
350
                        colorInterpretation = new DataStoreColorInterpretation();
351
                        colorInterpretation.initColorInterpretation(getBandCount());
352
                        colorInterpretation.setColorInterpValue(0, DataStoreColorInterpretation.RED_BAND);
353
                        colorInterpretation.setColorInterpValue(1, DataStoreColorInterpretation.GREEN_BAND);
354
                        colorInterpretation.setColorInterpValue(2, DataStoreColorInterpretation.BLUE_BAND);
355
                }
356
                return colorInterpretation;
357
        }
358
        
359
        /*
360
         * (non-Javadoc)
361
         * @see org.gvsig.raster.impl.provider.RasterProvider#isTiled()
362
         */
363
        public boolean isTiled() {
364
                return true;
365
        }
366
        
367
        /*
368
         * (non-Javadoc)
369
         * @see org.gvsig.fmap.dal.coverage.dataset.RasterDataSet#getAffineTransform()
370
         */
371
        public AffineTransform getAffineTransform() {
372
                WMTSDataParametersImpl p = (WMTSDataParametersImpl)parameters;
373
                Extent e = getExtent();
374
                double psX = e.width() / (lastWidthRequest <= 0 ? p.getWidth() : lastWidthRequest);
375
                double psY = -(e.height() / (lastHeightRequest <= 0 ? p.getHeight() : lastHeightRequest));
376
                ownTransformation = new AffineTransform(
377
                                psX, 
378
                                0, 
379
                                0, 
380
                                psY, 
381
                                e.getULX() - (psX / 2),
382
                                e.getULY() - (psY / 2));
383
                externalTransformation = (AffineTransform) ownTransformation.clone();
384
                return ownTransformation;
385
        }
386
        
387
        /**
388
         * Gets the bounding box in world coordinates. If the layer has grid subsets (TileMatrixLimits) then
389
         * this will have a only extent but if the layer doesn't have grid subsets then this will have a different
390
         * extent in each level resolution. In this case we need to know the extent for each level.
391
         * @return Extent
392
         */
393
        public Extent getExtent() {
394
                WMTSDataParametersImpl p = (WMTSDataParametersImpl)parameters;
395
                if(gridSubsets) {
396
                        WMTSLayer layer = p.getLayer();
397
                        WMTSBoundingBox bbox = layer.getWGS84BBox();
398
                        return new ExtentImpl(bbox.toRectangle2D());
399
                } else {
400
                        WMTSTileMatrixSet tileMatrixSet = getTileMatrixSetLink().getTileMatrixSet();
401
                        
402
                        //Si ya se han calculado los niveles es q el extent es v?lido sino el nivel ser? el 0
403
                        double scale = 0D;
404
                        int level = 0;
405
                        if(extentByLevel != null && p.getExtent() != null) {
406
                                scale = getScale(p.getExtent(), p.getWidth());
407
                                try {
408
                                        level = getLevelFromScale(scale, tileMatrixSet);
409
                                } catch (RasterDriverException e) {
410
                                        e.printStackTrace();
411
                                }                                
412
                        }
413
                        
414
                        Extent[] ext = getExtentByResolutionLevel();
415
                        
416
                        if(ext != null && level >= 0 && level < ext.length)
417
                                return ext[level];
418
                }
419
                return null;
420
        }
421
        
422
        /**
423
         * Gets the suffix of the downloaded image
424
         * @return
425
         */
426
        public String getFileSuffix() {
427
                WMTSDataParametersImpl p = (WMTSDataParametersImpl)parameters;
428
                String format = p.getImageFormat();
429
                if (format == null){
430
                        return "xml";
431
                }
432
                if (format.indexOf("png") >= 0){
433
                return "png";
434
                }        
435
            if (format.indexOf("xml") >= 0){
436
                return "xml";
437
            }        
438
            if (format.indexOf("gif") >= 0){
439
                return "gif";
440
            }
441
            if (format.indexOf("tif") >= 0){
442
                return "tif";
443
            }
444
            if (format.indexOf("bmp") >= 0){
445
                return "bmp";
446
            }
447
            if (format.indexOf("jpg") >= 0
448
                || format.indexOf("jpeg") >= 0){
449
                return "jpg";                         
450
            }
451
                return "xml";
452
        }
453

    
454
        /**
455
         * When a layer doesn't have grid subsets this will have a different bounding
456
         * box by resolution level. This function calculates and returns the array of
457
         * extents, one by resolution level.
458
         * @return
459
         */
460
        public Extent[] getExtentByResolutionLevel() {
461
                if(extentByLevel == null) {
462
                        WMTSDataParametersImpl p = (WMTSDataParametersImpl)parameters;
463
                        WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
464
                        WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
465
                        
466
                    double widthMtsTile = 0;
467
                    double heightMtsTile = 0;
468
                        ArrayList<?> tileMatrixList = tileMatrixSet.getTileMatrix();
469
                        extentByLevel = new ExtentImpl[tileMatrixList.size()];
470
                        for (int i = 0; i < tileMatrixList.size(); i++) {
471
                                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixList.get(i);
472
                            if(!p.isProjected()) {
473
                                    widthMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / (MTS_X_GRADO * 1000);
474
                                    heightMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / (MTS_X_GRADO * 1000);
475
                            } else {
476
                                    widthMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / 1000;
477
                                    heightMtsTile = (tileMatrix.getScaleDenominator() * tileMatrix.getTileWidth() * 0.28) / 1000;
478
                            }
479
                            
480
                            double h = Math.abs(tileMatrix.getTopLeftCorner()[0] - (tileMatrix.getTopLeftCorner()[0] - (tileMatrix.getMatrixHeight() * heightMtsTile)));
481
                            Rectangle2D r = new Rectangle2D.Double(
482
                                            tileMatrix.getTopLeftCorner()[1], 
483
                                            tileMatrix.getTopLeftCorner()[0] - h,
484
                                            Math.abs(tileMatrix.getTopLeftCorner()[1] - (tileMatrix.getTopLeftCorner()[1] + (tileMatrix.getMatrixWidth() * widthMtsTile))),
485
                                            h);
486
                            extentByLevel[i] = new ExtentImpl(r);
487
                        }
488
                        
489
                }
490
                return extentByLevel;
491
        }
492
        
493
        /*
494
         * (non-Javadoc)
495
         * @see org.gvsig.raster.impl.provider.RemoteRasterProvider#getLayerExtent(java.lang.String, java.lang.String)
496
         */
497
        public Rectangle2D getLayerExtent(String layerName, String srs) throws RemoteServiceException {
498
                return null;
499
        }
500

    
501
        /*
502
         * (non-Javadoc)
503
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#load()
504
         */
505
        public RasterProvider load() {
506
                return this;
507
        }
508
        
509
        /*
510
         * (non-Javadoc)
511
         * @see org.gvsig.raster.impl.provider.RasterProvider#isOpen()
512
         */
513
        public boolean isOpen() {
514
                return open;
515
        }
516

    
517
        /*
518
         * (non-Javadoc)
519
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#close()
520
         */
521
        public void close() {
522
                open = false;
523
        }
524
        
525
        /*
526
         * (non-Javadoc)
527
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getTransparency()
528
         */
529
        public Transparency getTransparency() {
530
                if(lastFileTransparency == null) {
531
                        lastFileTransparency = new DataStoreTransparency();
532
                        lastFileTransparency.setTransparencyBand(3);
533
                }
534
                return lastFileTransparency;
535
        }
536

    
537
        /*
538
         * (non-Javadoc)
539
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#translateFileName(java.lang.String)
540
         */
541
        public String translateFileName(String fileName) {
542
                return fileName;
543
        }
544

    
545
        /*
546
         * (non-Javadoc)
547
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#setView(org.gvsig.fmap.dal.coverage.datastruct.Extent)
548
         */
549
        public void setView(Extent e) {
550
                viewRequest = e;
551
        }
552

    
553
        /*
554
         * (non-Javadoc)
555
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getView()
556
         */
557
        public Extent getView() {
558
                return viewRequest;
559
        }
560

    
561
        /*
562
         * (non-Javadoc)
563
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWidth()
564
         */
565
        public double getWidth() {
566
                WMTSDataParametersImpl p = (WMTSDataParametersImpl)parameters;
567
                if (lastWidthRequest <= 0) 
568
                        return p.getWidth();
569
                return lastWidthRequest;
570
        }
571

    
572
        /*
573
         * (non-Javadoc)
574
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getHeight()
575
         */
576
        public double getHeight() {
577
                WMTSDataParametersImpl p = (WMTSDataParametersImpl)parameters;
578
                if (lastHeightRequest <= 0) 
579
                        return p.getHeight();
580
                return lastHeightRequest;
581
        }
582

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

    
603
        /**
604
         * Reads a complete block of data and returns an tridimensional array of the right type. This function is useful
605
         * to read a file very fast without setting a view. In a WMS service when the size is fixed then it will read the
606
         * entire image but when the source hasn't pixel size it will read a sample of data. This set of data will have
607
         * the size defined in FIXED_SIZE. 
608
         * 
609
         * @param pos Posici?n donde se empieza  a leer
610
         * @param blockHeight Altura m?xima del bloque leido
611
         * @return Object que es un array tridimendional del tipo de datos del raster. (Bandas X Filas X Columnas)
612
         * @throws InvalidSetViewException
613
         * @throws FileNotOpenException
614
         * @throws RasterDriverException
615
         */
616
        public Object readBlock(int pos, int blockHeight) 
617
        throws InvalidSetViewException, FileNotOpenException, RasterDriverException, ProcessInterruptedException {
618
                return null;
619
        }
620

    
621
        /*
622
         * (non-Javadoc)
623
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getData(int, int, int)
624
         */
625
        public Object getData(int x, int y, int band)
626
                throws InvalidSetViewException, FileNotOpenException, RasterDriverException {
627
                return null;
628
        }
629
        
630
        /**
631
         * Assigns the list of bands RGB and read a window of data
632
         * @param rasterBuf
633
         * @param bandList
634
         * @param lastFile
635
         * @param ulx
636
         * @param uly
637
         * @param lrx
638
         * @param lry
639
         * @return
640
         * @throws RasterDriverException
641
         * @throws ProcessInterruptedException
642
         */
643
        public Buffer getBuffer(Buffer rasterBuf, BandList bandList, File lastFile, 
644
                        double ulx, double uly, double lrx, double lry) throws RasterDriverException, ProcessInterruptedException {
645
                return null;
646
        }
647
        
648
        /**
649
         * Gets the tile matrix from the selected level
650
         * @param level
651
         * @return
652
         */
653
        @SuppressWarnings("unchecked")
654
        private WMTSTileMatrix getTileMatrixByLevel(int level) {
655
                level = adjustLevel(level);
656
                
657
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
658
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
659
                ArrayList tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
660
                
661
                WMTSTileMatrixLimits tileMatrixLimits = null;
662
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(level);
663
                if(hasGridSubsets()) {
664
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(level);
665
                        tileMatrix = tileMatrixLimits.getTileMatrix();
666
                }
667
                return tileMatrix;
668
        }
669
        
670
        /**
671
         * Returns the number of levels
672
         * @return
673
         */
674
        @SuppressWarnings("unchecked")
675
        public int getZoomLevels() {
676
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
677
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
678
                if(hasGridSubsets()) {
679
                        ArrayList tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
680
                        return Math.min(tileMatrixSet.getTileMatrix().size(), tileMatrixSetLimits.size());
681
                }
682
                return tileMatrixSet.getTileMatrix().size();
683
                
684
        }
685
        
686
        /*
687
         * (non-Javadoc)
688
         * @see org.gvsig.raster.impl.provider.RasterProvider#getCoordsInTheNearestLevel(org.gvsig.fmap.dal.coverage.datastruct.Extent, int, int)
689
         */
690
        public Extent getCoordsInTheNearestLevel(Extent extent, int w, int h) {
691
                double[] pixelSizes = getPixelSizeByLevel();
692
                double currentPixelSize = extent.width() / (double)w;
693
                
694
                int level = 0;
695
                for (int i = 0; i < (pixelSizes.length - 1); i++) {
696
                        if(currentPixelSize < pixelSizes[i] && currentPixelSize >= pixelSizes[i + 1]) {
697
                                level = i + 1;
698
                                break;
699
                        }
700
                }
701
                
702
                return getZoomLevelCoordinates(level, extent, w, h);
703
        }
704
        
705
        /*
706
         * (non-Javadoc)
707
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getCoordsInLevel(java.awt.geom.Point2D, int, int, int)
708
         */
709
        public Extent getCoordsInLevel(Point2D viewCenter, int level, int w, int h) {
710
                WMTSDataParameters p = (WMTSDataParameters)param;
711
                level = adjustLevel(level);
712
                WMTSTileMatrix tileMatrix = getTileMatrixByLevel(level);
713
                
714
                boolean proj = p.isProjected();
715
                
716
                double psX = tileMatrix.getWidthMtsTile(proj) / tileMatrix.getTileWidth();
717
                double psY = tileMatrix.getHeightMtsTile(proj) / tileMatrix.getTileHeight();
718
                
719
                double ulx = viewCenter.getX() - ((w / 2) * psX);
720
                double uly = viewCenter.getY() - ((h / 2) * psY);
721
                double lrx = ulx + (w * psX);
722
                double lry = uly + (h * psY);
723
                return new ExtentImpl(ulx, uly, lrx, lry);
724
        }
725
        
726
        /**
727
         * Calculates the extent of a zoom level using other extent as a reference. The new extent is 
728
         * calculated with the same coordinate at the center. 
729
         * @param level
730
         * @param extent
731
         * @param w
732
         * @param h
733
         * @return
734
         */
735
        public Extent getZoomLevelCoordinates(int level, Extent extent, int w, int h) {
736
                double centerX = extent.getCenterX();
737
                double centerY = extent.getCenterY();
738
                return getCoordsInLevel(new Point2D.Double(centerX, centerY), level, w, h);
739
        }
740
        
741
        /**
742
         * Returns a list of pixel sizes by level
743
         * @return
744
         */
745
        public double[] getPixelSizeByLevel() {
746
                WMTSDataParameters p = (WMTSDataParameters)param;
747
                double[] list = new double[getZoomLevels()];
748
                
749
                for (int i = 0; i < getZoomLevels(); i++) {
750
                        WMTSTileMatrix tileMatrix = getTileMatrixByLevel(i);
751
                        list[i] = math.adjustDouble(tileMatrix.getWidthMtsTile(p.isProjected()) / tileMatrix.getTileWidth());
752
                }
753
                return list;
754
        }
755
        
756
        /**
757
         * Adjust de level to the range
758
         * @param level
759
         * @return
760
         */
761
        private int adjustLevel(int level) {
762
                if(level < 0)
763
                        level = 0;
764
                if(level > getZoomLevels())
765
                        level = getZoomLevels();
766
                return level;
767
        }
768
        
769
        /*
770
         * (non-Javadoc)
771
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(double, double, double, double, int, int, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer, org.gvsig.fmap.dal.coverage.grid.render.TileListener, int)
772
         */
773
        public void getWindow(Extent ex, int bufWidth, int bufHeight, 
774
                        BandList bandList, TileListener listener) throws ProcessInterruptedException, RasterDriverException {
775
                Rectangle2D r = ex.toRectangle2D();//new Rectangle2D.Double(Math.min(minX, maxX), Math.min(minY, maxY), Math.abs(maxX - minX), Math.abs(maxY - minY));
776
                WMTSStatus status = buildWMTSStatus(r, bufWidth, bufHeight);
777
                request(status, bandList, listener);
778
        }
779
        
780
        /*
781
         * (non-Javadoc)
782
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(double, double, double, double, int, int, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer, boolean)
783
         */
784
        public Buffer getWindow(Extent extent, 
785
                        int bufWidth, int bufHeight, BandList bandList, Buffer rasterBuf, boolean adjustToExtent) throws ProcessInterruptedException, RasterDriverException {
786
                Rectangle2D r = extent.toRectangle2D();//new Rectangle2D.Double(Math.min(ulx, lrx), Math.min(lry, uly), Math.abs(lrx - ulx), Math.abs(uly - lry));
787
                WMTSStatus status = buildWMTSStatus(r, bufWidth, bufHeight);
788
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, bandList, null);
789
                MemoryMatrixBuffer matrixBuffer = new MemoryMatrixBuffer(tileList);
790
                return matrixBuffer.getWindow(extent, rasterBuf);
791
        }
792
        
793
        /*
794
         * (non-Javadoc)
795
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(org.gvsig.fmap.dal.coverage.datastruct.Extent, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer)
796
         */
797
        public Buffer getWindow(Extent extent, BandList bandList, Buffer rasterBuf) 
798
                throws ProcessInterruptedException, RasterDriverException {
799
                lastWidthRequest = rasterBuf.getWidth();
800
                lastHeightRequest = rasterBuf.getHeight();
801
                Rectangle2D r = extent.toRectangle2D();//new Rectangle2D.Double(Math.min(ulx, lrx), Math.min(lry, uly), Math.abs(lrx - ulx), Math.abs(uly - lry));
802
                WMTSStatus status = buildWMTSStatus(r, lastWidthRequest, lastHeightRequest);
803
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, bandList, null);
804
                MemoryMatrixBuffer matrixBuffer = new MemoryMatrixBuffer(tileList);
805
                return matrixBuffer.getWindow(extent, rasterBuf);
806
        }
807

    
808
        /*
809
         * (non-Javadoc)
810
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(double, double, double, double, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer, boolean)
811
         */
812
        public Buffer getWindow(double ulx, double uly, double w, double h, 
813
                        BandList bandList, Buffer rasterBuf, boolean adjustToExtent) throws ProcessInterruptedException, RasterDriverException {
814
                lastWidthRequest = rasterBuf.getWidth();
815
                lastHeightRequest = rasterBuf.getHeight();
816
                Rectangle2D r = new Rectangle2D.Double(ulx, uly - h, w, h);
817
                WMTSStatus status = buildWMTSStatus(r, lastWidthRequest, lastHeightRequest);
818
                org.gvsig.raster.cache.tile.Tile[] tileList = request(status, bandList, null);
819
                MemoryMatrixBuffer matrixBuffer = new MemoryMatrixBuffer(tileList);
820
                return matrixBuffer.getWindow(new ExtentImpl(ulx, uly, ulx + w, uly - h), rasterBuf);
821
        }
822

    
823
        /*
824
         * (non-Javadoc)
825
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(int, int, int, int, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer)
826
         */
827
        public Buffer getWindow(int x, int y, BandList bandList, Buffer rasterBuf) throws ProcessInterruptedException, RasterDriverException {
828
                lastWidthRequest = rasterBuf.getWidth();
829
                lastHeightRequest = rasterBuf.getHeight();
830
                return null;
831
        }
832

    
833
        /*
834
         * (non-Javadoc)
835
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getWindowRaster(int, int, int, int, int, int, org.gvsig.fmap.dal.coverage.datastruct.BandList, org.gvsig.fmap.dal.coverage.dataset.Buffer)
836
         */
837
        public Buffer getWindow(int x, int y, int w, int h, int bufWidth, int bufHeight, BandList bandList, Buffer rasterBuf) throws ProcessInterruptedException, RasterDriverException {
838
                lastWidthRequest = rasterBuf.getWidth();
839
                lastHeightRequest = rasterBuf.getHeight();
840
                return null;
841
        }
842
        
843
        /**
844
         * Gets the information from a point 
845
         * @param wcx
846
         * @param wcy
847
         * @param level
848
         * @return
849
         * @throws RasterDriverException
850
         */
851
        public String getFeatureInfo(double wcx, double wcy, int level) throws RasterDriverException {
852
                PointInfo pointInfo = new PointInfo(new Point2D.Double(wcx, wcy));
853
                pointInfo.level = level;
854
                getTileInfo(pointInfo);
855
                
856
                WMTSConnector connector = null;
857
                try {
858
                        connector = getConnector();
859
                        lastStatus.setTileRow((int)pointInfo.tile.getX());
860
                        lastStatus.setTileCol((int)pointInfo.tile.getY());
861
                        
862
                        String fi = connector.getFeatureInfo(lastStatus, (int)pointInfo.pixelInTile.getX(), (int)pointInfo.pixelInTile.getY(), null);
863
                        return fi;
864
                } catch (WMTSException e) {
865
                        throw new RasterDriverException("Error getting the connector object", e);
866
                } catch (ServerErrorException e) {
867
                        throw new RasterDriverException("Error getting the connector object", e);
868
                }
869
        }
870
        
871
        /**
872
         * Gets a tile position from a world coordinates point and a resolution level
873
         * @param point
874
         * @param level
875
         * @return An array with two elements. The first is the row and the second the column
876
         * of the tile in the tile matrix
877
         */
878
        @SuppressWarnings({ "unchecked"})
879
        private void getTileInfo(PointInfo pointInfo) {
880
                WMTSDataParameters p = (WMTSDataParameters)param;
881
                
882
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
883
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
884
                ArrayList tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
885
                
886
                WMTSTileMatrixLimits tileMatrixLimits = null;
887
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(pointInfo.level);
888
                if(hasGridSubsets()) {
889
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(pointInfo.level);
890
                        tileMatrix = tileMatrixLimits.getTileMatrix();
891
                }
892
                
893
                ArrayList<Tile> tiles = null;
894
                if(hasGridSubsets())
895
                        tiles = tileMatrix.contains(p.isProjected(), tileMatrixLimits, pointInfo.worldCoord, getExtent().toRectangle2D());
896
                else
897
                        tiles = tileMatrix.contains(p.isProjected(), pointInfo.worldCoord, getExtent().toRectangle2D());
898
                
899
                //Tile row and column
900
                pointInfo.tile = new Point2D.Double(tiles.get(0).row, tiles.get(0).col);
901
                
902
                //Desplazamiento en pixels dentro del tile
903
                Point2D rasterPoint = tiles.get(0).worldToRaster(pointInfo.worldCoord);
904
                pointInfo.pixelInTile = new Point2D.Double(rasterPoint.getX(), rasterPoint.getY());
905
        }
906
        
907
        /**
908
         * Builds the WMTSStatus object using the parameters and the request bounding box. 
909
         * @param r
910
         * @param bufWidth
911
         * @return
912
         * @throws RasterDriverException
913
         */
914
        @SuppressWarnings("unchecked")
915
        public WMTSStatus buildWMTSStatus(Rectangle2D r, int bufWidth, int bufHeight) throws RasterDriverException {
916
                WMTSDataParameters p = (WMTSDataParameters)param;
917
                
918
                //Mantiene actualizados los par?metros del WMTSStoreParameters con la ?ltima petici?n hecha
919
                p.setExtent(r);
920
                p.setWidth(bufWidth);
921
                p.setHeight(bufHeight);
922
                
923
                lastWidthRequest = bufWidth;
924
                lastHeightRequest = bufHeight;
925
                
926
                //1-Selecci?n de WMTSTileMatrixSet por srs
927
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
928
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
929
                ArrayList tileMatrixSetLimits = tileMatrixSetLink.getTileMatrixLimits();
930
                
931
                
932
                //Esto hace lo mismo que getScale y getLevelFromScale
933
                /*int level = 0;
934
                double[] pixelSizes = getPixelSizeByLevel();
935
                double psViewPort = math.adjustDouble(r.getWidth() / (double)bufWidth);
936
                for (int i = 0; i < pixelSizes.length - 1; i++) {
937
                        if(psViewPort <= pixelSizes[i] && psViewPort > pixelSizes[i + 1]) {
938
                                level = i;
939
                                break;
940
                        }
941
                }*/
942
                
943
                //2-Calculo de la escala
944
                double scale = getScale(r, bufWidth);
945
                
946
                //3-Selecci?n del nivel a partir de la escala
947
                int level = getLevelFromScale(scale, tileMatrixSet);
948

    
949
                //4-Obtenemos la matriz de tiles y los l?mites si tiene subsets
950
                WMTSTileMatrixLimits tileMatrixLimits = null;
951
                WMTSTileMatrix tileMatrix = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(level);
952
                if(gridSubsets)
953
                        tileMatrixLimits = (WMTSTileMatrixLimits)tileMatrixSetLimits.get(level);
954
                
955
                //5-Selecci?n de tiles que entran en esta bounding box
956
                ArrayList<Tile> tiles = null;
957
                if(gridSubsets)
958
                        tiles = tileMatrix.intersects(p.isProjected(), tileMatrixLimits, r, getExtent().toRectangle2D());
959
                else
960
                        tiles = tileMatrix.intersects(p.isProjected(), r, getExtent().toRectangle2D());
961
                
962
                //6-Petici?n
963
                WMTSStatus status = new WMTSStatus();
964
                status.setTileList(tiles);
965
                status.setLayer(p.getLayer().getIdentifier());
966
                status.setFormat(p.getImageFormat());
967
                status.setInfoFormat(p.getInfoFormat());
968
                status.setStyle(p.getStyle() != null ? p.getStyle().getIdentifier() : "");
969
                status.setTileMatrixSet(tileMatrixSet.getIdentifier());
970
                status.setTileMatrix(tileMatrix.getIdentifier());
971
                status.setLevel(level);
972
                this.lastStatus = status;
973
                return status;
974
        }
975
        
976
        /**
977
         * Gets the resolution level from the real coordinates
978
         * @param r
979
         * @param 
980
         * @return
981
         * @throws RasterDriverException
982
         */
983
        public int getLevelFromRealCoords(Rectangle2D r, int width) throws RasterDriverException {
984
                double scale = getScale(r, width);
985
                WMTSTileMatrixSetLink tileMatrixSetLink = getTileMatrixSetLink();
986
                WMTSTileMatrixSet tileMatrixSet = tileMatrixSetLink.getTileMatrixSet();
987
                return getLevelFromScale(scale, tileMatrixSet);
988
        }
989
        
990
        /**
991
         * Gets the resolution level from the scale
992
         * @param scale
993
         * @param tileMatrixSet
994
         * @return
995
         * @throws RasterDriverException
996
         */
997
        public int getLevelFromScale(double scale, WMTSTileMatrixSet tileMatrixSet) throws RasterDriverException {
998
                //Recorremos los tileMatrix para obtener la escala m?s aproximada
999
                int levelModifier = 0;
1000
                scale = math.adjustDouble(scale);
1001
                try {
1002
                        for (int resolutionLevel = 0; resolutionLevel < tileMatrixSet.getTileMatrix().size(); resolutionLevel++) {
1003
                                WMTSTileMatrix tm = (WMTSTileMatrix)tileMatrixSet.getTileMatrix().get(resolutionLevel);
1004
                                double scaleDenominator = math.adjustDouble(tm.getScaleDenominator());
1005
                                if(scale >= scaleDenominator) {
1006
                                        return Math.max(resolutionLevel + levelModifier, 0);
1007
                                }
1008
                        }
1009
                } catch (IndexOutOfBoundsException e) {
1010
                        throw new RasterDriverException("Error in this resolution level", e);
1011
                }
1012
                return 0;
1013
        }
1014
        
1015
        /**
1016
         * Get the tile matrix set using the crs
1017
         * @param srs
1018
         * @return
1019
         */
1020
        public WMTSTileMatrixSetLink getTileMatrixSetLink() {
1021
                WMTSDataParameters p = (WMTSDataParameters)param;
1022
                ArrayList<?> tileMatrixSetLinkList = p.getLayer().getTileMatrixSetLink();
1023
                for (int i = 0; i < tileMatrixSetLinkList.size(); i++) {
1024
                        WMTSTileMatrixSetLink tileMatrixSetLink = (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(i);
1025
                        String srsTileSet = tileMatrixSetLink.getTileMatrixSet().getSupportedCRS();
1026
                        if(srsTileSet.compareTo(p.getSRSCode()) == 0) {
1027
                                return tileMatrixSetLink;
1028
                        }
1029
                }
1030
                if(tileMatrixSetLinkList != null && tileMatrixSetLinkList.size() > 0)
1031
                        return (WMTSTileMatrixSetLink)tileMatrixSetLinkList.get(0);
1032
                return null;
1033
        }
1034
        
1035
        /**
1036
         * Gets the scale using the extent and the width in pixels.
1037
         * @param r
1038
         * @param width
1039
         * @return
1040
         */
1041
        private double getScale(Rectangle2D r, int width) {
1042
                WMTSDataParameters p = (WMTSDataParameters)param;
1043
                if(!p.isProjected()) {
1044
                        return (1000 * r.getWidth() * MTS_X_GRADO) / (width * 0.28);
1045
                } else
1046
                        return (1000 * r.getWidth()) / (width * 0.28);
1047
        }
1048
        
1049
        /**
1050
         * Throw a request
1051
         * @param status
1052
         * @param bandList
1053
         * @param listener
1054
         * @param alphaBandNumber 
1055
         * @return returns a buffer if the listener is null. In any other case it return null.
1056
         * @throws RasterDriverException 
1057
         * @throws ProcessInterruptedException 
1058
         */
1059
        @SuppressWarnings("unchecked")
1060
        private synchronized org.gvsig.raster.cache.tile.Tile[] request(WMTSStatus status, BandList bandList, TileListener listener) throws RasterDriverException, ProcessInterruptedException {
1061
                //WMTSDataParameters p = (WMTSDataParameters)param;
1062
                WMTSConnector connector = null;
1063
                try {
1064
                        connector = getConnector();
1065
                } catch (WMTSException e) {
1066
                        throw new RasterDriverException("Error getting the connector object", e);
1067
                }
1068
                
1069
                if(connector == null)
1070
                        throw new RasterDriverException("Error getting the connector object");
1071
                
1072
                ArrayList<Tile> tiles = status.getTileList();
1073
                
1074
                TilePipe pipe = new TilePipe();
1075
                //TilePipe2 pipe = new TilePipe2();
1076
                //TileThreadPool pool = null;
1077
                
1078
                //Caso 1: Lanza un thread que gestiona que no se lancen muchos threads a la vez
1079
                if(requestType == LIMITED_THREADS) {
1080
                        RequestThreadManager threadManager = new RequestThreadManager(pipe, tiles, status);
1081
                        pipe.setRequestManager(threadManager);
1082
                        threadManager.start();
1083
                //Caso 2: Lanza todos los threads
1084
                } else if(requestType == UNLIMITED_THREADS) {
1085
                        for (int i = 0; i < tiles.size(); i++) {
1086
                                Tile tile = tiles.get(i);
1087
                                WMTSStatus statusCopy = status.cloneStatus();
1088
                                statusCopy.setTileRow(tile.row);
1089
                                statusCopy.setTileCol(tile.col);
1090
                                new RequestTileLauncher(pipe, statusCopy, tile).start();
1091
                        }
1092
                }
1093
                
1094
                org.gvsig.raster.cache.tile.Tile[] tileList = new org.gvsig.raster.cache.tile.Tile[tiles.size()]; 
1095
                
1096
                if(requestType == LIMITED_THREADS || requestType == UNLIMITED_THREADS) {
1097
                        int nCollected = 0;
1098
                        while (nCollected < tiles.size()) {
1099
                                Tile tile = pipe.getTile();
1100
                                tileList[nCollected] = drawTile(tile, listener, bandList);
1101
                                nCollected ++;
1102
                        }
1103
                }
1104
                
1105
                if(requestType == SEQUENTIAL) {
1106
                        for (int i = 0; i < tiles.size(); i++) {
1107
                                Tile tile = tiles.get(i);
1108
                                status.setTileRow(tile.row);
1109
                                status.setTileCol(tile.col);
1110
                                //TODO:Cancelaci?n
1111
                                try {
1112
                                        File file = connector.getTile(status, null);
1113
                                        tile.file = file;
1114
                                        tileList[i] = drawTile(tile, listener, bandList);
1115
                                } catch (WMTSException e) {
1116
                                        throw new RasterDriverException("Error getting tiles", e);
1117
                                } catch (ServerErrorException e) {
1118
                                        throw new RasterDriverException("Error getting tiles", e);
1119
                                }
1120
                        }
1121
                }
1122
                if(listener != null) 
1123
                        listener.endReading();
1124
                
1125
                return tileList;
1126
        }
1127
        
1128
        /**
1129
         * Reads a tile with gdal and calls the method nextBuffer
1130
         * @param tile
1131
         * @param listener
1132
         * @param bandList
1133
         * @return
1134
         * @throws RasterDriverException
1135
         */
1136
        private synchronized org.gvsig.raster.cache.tile.Tile drawTile(Tile tile, TileListener listener, BandList bandList) throws RasterDriverException {
1137
                WMTSDataParameters p = (WMTSDataParameters)param;
1138
                try {
1139
                        String serverName = bandList.getBand(0).getFileName();
1140
                        for (int j = 0; j < bandList.getBandCount(); j++) {
1141
                                bandList.getBand(j).setFileName(tile.file.getPath());
1142
                        }
1143
                        
1144
                        GdalProvider driver = new GdalProvider(tile.file.getPath());
1145
                        colorTable = driver.getColorTable();
1146
                        bandCount = driver.getBandCount();
1147
                        lastFileTransparency = driver.getTransparency();
1148
                        Buffer rasterBuf = DefaultRasterManager.getInstance().createBuffer(getDataType()[0], tile.wPx, tile.hPx, 3, true);
1149
                        Buffer buf = driver.getWindow(0, 0, bandList, rasterBuf);
1150
                        
1151
                        buf.setDataExtent(new Rectangle2D.Double(Math.min(tile.ulx, tile.lrx), Math.min(tile.uly, tile.lry), Math.abs(tile.ulx - tile.lrx), Math.abs(tile.uly - tile.lry)));
1152
                        
1153
                        Buffer alphaBand = null;
1154
                        if(p.getAlphaBand() != -1 && listener != null && p.getAlphaBand() < bandCount) {
1155
                                alphaBand = DefaultRasterManager.getInstance().createBuffer(getDataType()[0], tile.wPx, tile.hPx, 1, true);
1156
                                int[] oldDB = bandList.getDrawableBands();
1157
                                bandList.setDrawableBands(new int[]{p.getAlphaBand()});
1158
                                alphaBand = driver.getWindow(0, 0, bandList, alphaBand);
1159
                                bandList.setDrawableBands(oldDB);
1160
                        }
1161

    
1162
                        for (int j = 0; j < bandList.getBandCount(); j++) {
1163
                                bandList.getBand(j).setFileName(serverName);
1164
                        }
1165

    
1166
                        driver.close();
1167

    
1168

    
1169
                        TileCacheManager m = TileCacheLocator.getManager();
1170
                        org.gvsig.raster.cache.tile.Tile t = m.createTile(-1, tile.row, tile.col);
1171
                        t.setData(new Object[]{buf, alphaBand});
1172
                        t.setUl(new Point2D.Double(tile.ulx, tile.uly));
1173
                        t.setLr(new Point2D.Double(tile.lrx, tile.lry));
1174
                        t.setDownloaderParams("AffineTransform", getAffineTransform());
1175
                        t.setDownloaderParams("Tiling", new Boolean(true));
1176
                        if(listener != null) 
1177
                                listener.tileReady(t);
1178
                        else 
1179
                                return t;
1180

    
1181
                } catch (NotSupportedExtensionException e) {
1182
                        throw new RasterDriverException("Error getting tiles", e);
1183
                } catch (ProcessInterruptedException e) {
1184
                } catch (TileGettingException e) {
1185
                        throw new RasterDriverException("Error throwing a tile", e);
1186
                }
1187
                return null;
1188
        }
1189

    
1190
        /*
1191
         * (non-Javadoc)
1192
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getBlockSize()
1193
         */
1194
        public int getBlockSize() {
1195
                return 0;
1196
        }
1197

    
1198
        /*
1199
         * (non-Javadoc)
1200
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#setAffineTransform(java.awt.geom.AffineTransform)
1201
         */
1202
        public void setAffineTransform(AffineTransform t){
1203
                
1204
        }
1205

    
1206
        /*
1207
         * (non-Javadoc)
1208
         * @see org.gvsig.raster.impl.provider.RasterProvider#getOverviewCount(int)
1209
         */
1210
        public int getOverviewCount(int band) throws BandAccessException, RasterDriverException {
1211
                return 0;
1212
        }
1213

    
1214
        /*
1215
         * (non-Javadoc)
1216
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getOverviewWidth(int, int)
1217
         */
1218
        public int getOverviewWidth(int band, int overview) throws BandAccessException, RasterDriverException {
1219
                return 0;
1220
        }
1221

    
1222
        /*
1223
         * (non-Javadoc)
1224
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getOverviewHeight(int, int)
1225
         */
1226
        public int getOverviewHeight(int band, int overview) throws BandAccessException, RasterDriverException {
1227
                return 0;
1228
        }
1229

    
1230
        /*
1231
         * (non-Javadoc)
1232
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#overviewsSupport()
1233
         */
1234
        public boolean overviewsSupport() {
1235
                return false;
1236
        }
1237

    
1238
        /*
1239
         * (non-Javadoc)
1240
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#isReproyectable()
1241
         */
1242
        public boolean isReproyectable() {
1243
                return false;
1244
        }
1245

    
1246
        /*
1247
         * (non-Javadoc)
1248
         * @see org.gvsig.fmap.dal.raster.spi.CoverageStoreProvider#getName()
1249
         */
1250
        public String getName() {
1251
                return NAME;
1252
        }
1253
        
1254
        /**
1255
         * Convierte un punto desde coordenadas pixel a coordenadas del mundo.
1256
         * @param pt Punto a transformar
1257
         * @return punto transformado en coordenadas del mundo
1258
         */
1259
        public Point2D rasterToWorld(Point2D pt) {
1260
                Point2D p = new Point2D.Double();
1261
                getAffineTransform().transform(pt, p);
1262
                return p;
1263
        }
1264

    
1265
        /**
1266
         * Convierte un punto desde del mundo a coordenadas pixel.
1267
         * @param pt Punto a transformar
1268
         * @return punto transformado en coordenadas pixel
1269
         */
1270
        public Point2D worldToRaster(Point2D pt) {
1271
                Point2D p = new Point2D.Double();
1272
                try {
1273
                        getAffineTransform().inverseTransform(pt, p);
1274
                } catch (NoninvertibleTransformException e) {
1275
                        return pt;
1276
                }
1277
                return p;
1278
        }
1279
        
1280
        /*
1281
         * (non-Javadoc)
1282
         * @see org.gvsig.raster.impl.provider.RasterProvider#setStatus(org.gvsig.raster.impl.provider.RasterProvider)
1283
         */
1284
        public void setStatus(RasterProvider provider) {
1285
                if(provider instanceof WMTSProvider) {
1286
                }
1287
        }
1288
        
1289
        /*
1290
         * (non-Javadoc)
1291
         * @see org.gvsig.raster.impl.provider.RemoteRasterProvider#getLastRequest()
1292
         */
1293
        public File getLastRequest() {
1294
                return lastRequest;
1295
        }
1296
        
1297
        /**
1298
         * ASigna el par?metro de inicializaci?n del driver.
1299
         */
1300
        @Override
1301
        public void setParam(DataStoreParameters param) {
1302
                if(param instanceof WMTSDataParameters)
1303
                        this.name = ((WMTSDataParameters)param).getHost();
1304
                this.param = param;
1305
        }
1306
        
1307
        /*
1308
         * (non-Javadoc)
1309
         * @see org.gvsig.raster.impl.provider.RasterProvider#getInfoByPoint(double, double)
1310
         */
1311
        public String getInfoByPoint(double x, double y, ICancellable cancellable) throws RemoteServiceException {
1312
                WMTSDataParametersImpl p = (WMTSDataParametersImpl)param;
1313
                int level;
1314
                try {
1315
                        level = getLevelFromRealCoords(p.getExtent(), lastWidthRequest);
1316
                        return getFeatureInfo(x, y, level);
1317
                } catch (RasterDriverException e) {
1318
                        throw new RemoteServiceException(e);
1319
                }
1320
        }
1321
        
1322
        /*
1323
         * (non-Javadoc)
1324
         * @see org.gvsig.raster.impl.provider.RasterProvider#getNearestLevel(double)
1325
         */
1326
        public int getNearestLevel(double pixelSize) {
1327
                double[] pixelSizes = getPixelSizeByLevel();
1328
                for (int i = 0; i < pixelSizes.length - 1; i++) {
1329
                        if(pixelSize <= pixelSizes[i] && pixelSize > pixelSizes[i + 1]) {
1330
                                return i;
1331
                        }
1332
                }
1333
                if(pixelSize < pixelSizes[getZoomLevels() - 1])
1334
                        return getZoomLevels() - 1;
1335
                return 0;
1336
        }
1337
        
1338
        /*
1339
         * (non-Javadoc)
1340
         * @see org.gvsig.raster.impl.provider.RasterProvider#getTileServer()
1341
         */
1342
        public TileServer getTileServer() {
1343
                if(tileServer == null) {
1344
                        tileServer = new WMTSTileServer(this, getTileMatrixSetLink());
1345
                }
1346
                return tileServer;
1347
        }
1348
        
1349
        /*
1350
         * (non-Javadoc)
1351
         * @see org.gvsig.raster.impl.provider.DefaultRasterProvider#getTileSize(int)
1352
         */
1353
        public int[] getTileSize(int level) {
1354
                return getTileServer().getStruct().getTileSizeByLevel(level);
1355
        }
1356

    
1357
        /*
1358
         * (non-Javadoc)
1359
         * @see org.gvsig.raster.impl.provider.RasterProvider#isRasterEnclosed()
1360
         */
1361
        public boolean isRasterEnclosed() {
1362
                return true;
1363
        }
1364
        
1365
        /*
1366
         * (non-Javadoc)
1367
         * @see org.gvsig.raster.impl.provider.RemoteRasterProvider#getBufferLastRequest()
1368
         */
1369
        public Buffer getBufferLastRequest() throws ProcessInterruptedException, RasterDriverException {
1370
                return null;
1371
        }
1372
}