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

History | View | Annotate | Download (48.2 KB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1203
                        for (int j = 0; j < bandList.getBandCount(); j++) {
1204
                                bandList.getBand(j).setFileName(serverName);
1205
                        }
1206

    
1207
                        driver.close();
1208

    
1209

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

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

    
1258
        public int getBlockSize() {
1259
                return 0;
1260
        }
1261

    
1262
        public void setAffineTransform(AffineTransform t){
1263
                
1264
        }
1265

    
1266
        public int getOverviewCount(int band) throws BandAccessException, RasterDriverException {
1267
                return 0;
1268
        }
1269

    
1270
        public int getOverviewWidth(int band, int overview) throws BandAccessException, RasterDriverException {
1271
                return 0;
1272
        }
1273

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

    
1278
        public boolean isOverviewsSupported() {
1279
                return false;
1280
        }
1281

    
1282
        public boolean isReproyectable() {
1283
                return false;
1284
        }
1285

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

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

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

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