Statistics
| Revision:

gvsig-raster / org.gvsig.raster / branches / org.gvsig.raster.2.4 / org.gvsig.raster / org.gvsig.raster.gdal / org.gvsig.raster.gdal.provider / src / main / java / org / gvsig / raster / gdal / provider / RasterGdalStoreProvider.java @ 6302

History | View | Annotate | Download (18.6 KB)

1
/* gvSIG. Desktop Geographic Information System.
2
 *
3
 * Copyright ? 2007-2016 gvSIG Association
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18
 * MA  02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us
21
 * at info AT gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.raster.gdal.provider;
24

    
25
import java.io.File;
26
import java.util.ArrayList;
27
import java.util.Arrays;
28
import java.util.List;
29
import java.util.Vector;
30

    
31
import org.apache.commons.io.FilenameUtils;
32
import org.cresques.cts.IProjection;
33
import org.gdal.gdal.Band;
34
import org.gdal.gdal.Dataset;
35
import org.gdal.gdal.GCP;
36
import org.gdal.gdal.gdal;
37
import org.gdal.gdalconst.gdalconstConstants;
38
import org.gvsig.fmap.dal.DALLocator;
39
import org.gvsig.fmap.dal.DataManager;
40
import org.gvsig.fmap.dal.DataServerExplorer;
41
import org.gvsig.fmap.dal.DataStore;
42
import org.gvsig.fmap.dal.DataStoreNotification;
43
import org.gvsig.fmap.dal.FileHelper;
44
import org.gvsig.fmap.dal.exception.CloseException;
45
import org.gvsig.fmap.dal.exception.DataException;
46
import org.gvsig.fmap.dal.exception.InitializeException;
47
import org.gvsig.fmap.dal.exception.OpenException;
48
import org.gvsig.fmap.dal.exception.ReadException;
49
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
50
import org.gvsig.fmap.dal.raster.api.BandAttributeDescriptor;
51
import org.gvsig.fmap.dal.raster.api.BandDescriptor;
52
import org.gvsig.fmap.dal.raster.api.RasterQuery;
53
import org.gvsig.fmap.dal.raster.spi.AbstractRasterStoreProvider;
54
import org.gvsig.fmap.dal.resource.ResourceAction;
55
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
56
import org.gvsig.fmap.dal.resource.file.FileResource;
57
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
58
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
59
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
60
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
61
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
62
import org.gvsig.fmap.geom.Geometry;
63
import org.gvsig.fmap.geom.GeometryLocator;
64
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
65
import org.gvsig.fmap.geom.primitive.Envelope;
66
import org.gvsig.metadata.MetadataLocator;
67
import org.gvsig.metadata.MetadataManager;
68
import org.gvsig.metadata.exceptions.MetadataException;
69
import org.gvsig.raster.lib.buffer.api.BandInfo;
70
import org.gvsig.raster.lib.buffer.api.Buffer;
71
import org.gvsig.raster.lib.buffer.api.BufferLocator;
72
import org.gvsig.raster.lib.buffer.api.BufferManager;
73
import org.gvsig.raster.lib.buffer.api.NoData;
74
import org.gvsig.raster.lib.buffer.api.PageManager;
75
import org.gvsig.raster.lib.buffer.api.exceptions.BufferException;
76
import org.gvsig.tools.ToolsLocator;
77
import org.gvsig.tools.dynobject.DynObject;
78
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
79
import org.gvsig.tools.exception.BaseException;
80
import org.gvsig.tools.locator.LocatorException;
81
import org.gvsig.tools.task.SimpleTaskStatus;
82
import org.gvsig.tools.task.TaskStatusManager;
83
import org.slf4j.Logger;
84
import org.slf4j.LoggerFactory;
85

    
86

    
87
/**
88
 * Provider for Raster GDAL files
89
 * @author dmartinezizquierdo
90
 *
91
 */
92
public class RasterGdalStoreProvider extends AbstractRasterStoreProvider implements
93
ResourceConsumer{
94

    
95
    private static final Logger logger =
96
        LoggerFactory.getLogger(RasterGdalStoreProvider.class);
97

    
98
    public static String NAME = "RasterGdal";
99
    public static String DESCRIPTION = "Raster GDAL file";
100
    public static final String METADATA_DEFINITION_NAME = NAME;
101

    
102
    private ResourceProvider resource;
103
    private final SimpleTaskStatus taskStatus;
104

    
105
    private Envelope envelope = null;
106
    private IProjection projection= null;
107
    private Dataset gdalDataSet;
108

    
109

    
110
    public Dataset getGdalDataSet() {
111
        return gdalDataSet;
112
    }
113

    
114
    protected static void registerMetadataDefinition()
115
        throws MetadataException {
116
        MetadataManager manager = MetadataLocator.getMetadataManager();
117
        if (manager.getDefinition(METADATA_DEFINITION_NAME) == null) {
118
            manager.addDefinition(METADATA_DEFINITION_NAME,
119
                RasterGdalStoreProviderParameters.class
120
                    .getResourceAsStream("RasterGdalMetadata.xml"),
121
                RasterGdalStoreProviderParameters.class.getClassLoader());
122
        }
123
    }
124

    
125
    public RasterGdalStoreProvider(RasterGdalStoreProviderParameters params,
126
        DataStoreProviderServices storeServices)
127
        throws InitializeException {
128
        super(
129
                params,
130
                storeServices,
131
                FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
132
        );
133
        TaskStatusManager manager = ToolsLocator.getTaskStatusManager();
134
        this.taskStatus = manager.createDefaultSimpleTaskStatus("RasterGdal");
135
        this.init(params, storeServices);
136
    }
137

    
138
    protected RasterGdalStoreProvider(RasterGdalStoreProviderParameters params,
139
            DataStoreProviderServices storeServices, DynObject metadata)
140
            throws InitializeException {
141
        super(params, storeServices, metadata);
142
        TaskStatusManager manager = ToolsLocator.getTaskStatusManager();
143
        this.taskStatus = manager.createDefaultSimpleTaskStatus("RasterGdal");
144
        this.init(params, storeServices);
145
    }
146

    
147
    protected void init(RasterGdalStoreProviderParameters params,
148
        DataStoreProviderServices storeServices) throws InitializeException {
149
        if (params == null) {
150
            throw new InitializeException(
151
                new NullPointerException("params is null"));
152
        }
153
        File file = getRasterGdalParameters().getFile();
154
        if (file == null) {
155
            throw new InitializeException(
156
                new NullPointerException("Raster GDAL file is null"));
157
        }
158

    
159
        this.projection=params.getCRS();
160

    
161
        resource = this.createResource(
162
            FileResource.NAME,
163
            new Object[] { file.getAbsolutePath() }
164
        );
165

    
166
        resource.addConsumer(this);
167

    
168
    }
169

    
170
    private RasterGdalStoreProviderParameters getRasterGdalParameters() {
171
        return (RasterGdalStoreProviderParameters) this.getParameters();
172
    }
173

    
174
    @Override
175
    public Buffer createBuffer(RasterQuery rasterQuery) throws BufferException {
176
        int bandCount=gdalDataSet.getRasterCount();
177
        BufferManager bufferManager=BufferLocator.getBufferManager();
178
        int[] bandDataTypes=new int[bandCount];
179
        NoData[] bandNoData=new NoData[bandCount];
180
        List<PageManager> pageManagers=new ArrayList<PageManager>();
181

    
182
        for (int i=0;i<bandCount;i++){
183
            //Gdal bands begin count in 1
184
            int gdalBandNumber=i+1;
185
            Band gdalBand=gdalDataSet.GetRasterBand(gdalBandNumber);
186
            bandDataTypes[i]=getRasterBufTypeFromGdalType(gdalBand.getDataType());
187
            Double noData=getNoData(gdalBand);
188
            if (noData!=null){
189
                bandNoData[i]=bufferManager.createNoData(noData, noData);
190
            }else{
191
                bandNoData[i]=null;
192
            }
193
            pageManagers.add(new RasterGdalBandPageManager(gdalDataSet, gdalBandNumber));
194
        }
195

    
196
        Buffer buffer =
197
            bufferManager.createBuffer(gdalDataSet.getRasterYSize(), gdalDataSet.getRasterXSize(),
198
                bandDataTypes, bandNoData, projection, envelope, pageManagers);
199

    
200
        return buffer;
201
    }
202
    
203
    @Override
204
    public BandInfo getBandInfo(int band) {
205
        RasterGdalBandPageManager gdalBandPageManager =
206
            new RasterGdalBandPageManager(gdalDataSet, band + 1); // Gdal bands start at 1
207
        return gdalBandPageManager.getBandInfo();
208
    }
209

    
210
    @Override
211
    public BandDescriptor getBandDescriptor(int band) {
212
        // Returns an empty band descriptor
213
        return getStoreServices().createBandDescriptor(band,
214
            new ArrayList<BandAttributeDescriptor>(0));
215
    }
216

    
217
    @Override
218
    public int getBands() {
219
        return gdalDataSet.getRasterCount();
220
    }
221

    
222
    private Double getNoData(Band gdalBand){
223
        Double[] noDataValueResult=new Double[1];
224
        gdalBand.GetNoDataValue(noDataValueResult);
225
        Double noData=noDataValueResult[0];
226
        return noData;
227
    }
228

    
229
    @Override
230
    public DataServerExplorer getExplorer()
231
        throws ReadException, ValidateDataParametersException {
232
        DataManager manager = DALLocator.getDataManager();
233
        FilesystemServerExplorerParameters params;
234
        try {
235
            params = (FilesystemServerExplorerParameters) manager
236
            .createServerExplorerParameters(FilesystemServerExplorer.NAME);
237
            params.setRoot(this.getRasterGdalParameters().getFile().getParent());
238
            return manager.openServerExplorer(FilesystemServerExplorer.NAME,params);
239
        } catch (DataException e) {
240
            throw new ReadException(this.getProviderName(), e);
241
        } catch (ValidateDataParametersException e) {
242
            throw new ReadException(this.getProviderName(), e);
243
        }
244

    
245
    }
246

    
247
    public void open() throws OpenException {
248
        if (this.gdalDataSet != null) {
249
            return;
250
        }
251
        openEver();
252
    }
253

    
254
    private void openEver() throws OpenException {
255
        try {
256
            getResource().execute(new ResourceAction() {
257

    
258
                public Object run() throws Exception {
259

    
260
                    gdalDataSet = gdal.Open(
261
                        getRasterGdalParameters().getFile().getAbsolutePath(),
262
                        gdalconstConstants.GA_ReadOnly);
263

    
264
                    resource.notifyOpen();
265

    
266
                    envelope = createEnvelope(getGeoTransform());
267

    
268
                    if (envelope == null) {
269
                        // If couldn't be possible to create an envelope,
270
                        // this is created at 0,0 coordinates.
271
                        envelope = GeometryLocator.getGeometryManager()
272
                            .createEnvelope(0, 0, gdalDataSet.getRasterXSize(),
273
                                gdalDataSet.getRasterYSize(),
274
                                Geometry.SUBTYPES.GEOM2D);
275
                    }
276

    
277
                    resource.notifyClose();
278

    
279
                    resource.setData(gdalDataSet);
280

    
281
                    return null;
282
                }
283

    
284
            });
285
        } catch (Exception e) {
286
            this.gdalDataSet = null;
287
            try {
288
                throw new OpenException(resource.getName(), e);
289
            } catch (AccessResourceException e1) {
290
                throw new OpenException(getProviderName(), e);
291
            }
292
        } finally {
293
            this.taskStatus.remove();
294
        }
295
    }
296

    
297
    private double[] getGeoTransform(){
298
        double[] geotransform = null;
299
        double[] defaultGeotransform =
300
            { 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 };
301
        // Try to create an Envelope through geolocalization
302
        // methods
303
        if (getRasterGdalParameters().getWldParams() != null) {
304

    
305
            // Try to get a geotransform from wld file
306
            List<String> wldParams =
307
                getRasterGdalParameters().getWldParams();
308
            double pixelSizeX =
309
                Double.valueOf(wldParams.get(0));
310
            double rotationAxisY =
311
                Double.valueOf(wldParams.get(1));
312
            double rotationAxisX =
313
                Double.valueOf(wldParams.get(2));
314
            double pixelSizeY =
315
                -Double.valueOf(wldParams.get(3));
316
            double upperLeftPixelCenterCoordX =
317
                Double.valueOf(wldParams.get(4));
318
            double upperLeftPixelCenterCoordY =
319
                Double.valueOf(wldParams.get(5));
320

    
321
            geotransform = new double[6];
322
            // Info found at:
323
            // http://www.gdal.org/gdal_8h.html#adae2ed5807e4ec288812b54c6fccda1e
324
            // and http://www.gdal.org/gdal_tutorial.html
325
            // GDALReadWorldFile
326
            geotransform[0] = upperLeftPixelCenterCoordX
327
                - (pixelSizeX * 0.5) - (rotationAxisX * 0.5);
328
            geotransform[1] = pixelSizeX;
329
            geotransform[2] = rotationAxisX;
330
            geotransform[3] = upperLeftPixelCenterCoordY
331
                - (pixelSizeY * 0.5) - (rotationAxisY * 0.5);
332
            geotransform[4] = pixelSizeY;
333
            geotransform[5] = rotationAxisY;
334

    
335
        } else if (geotransform == null) {
336
            // Try to get a geotransform from the file
337
            geotransform = gdalDataSet.GetGeoTransform();
338

    
339
        }
340

    
341
        // Try to get a geotransform from GCPs in the file
342
        if (Arrays.equals(defaultGeotransform, geotransform)) {
343
            Vector vectorGCPs = gdalDataSet.GetGCPs();
344
            GCP[] gcps = new GCP[gdalDataSet.GetGCPCount()];
345
            for (int i = 0; i < gdalDataSet
346
                .GetGCPCount(); i++) {
347
                gcps[i] = (GCP) vectorGCPs.get(i);
348
            }
349
            double[] gcpsGeotransform = new double[6];
350
            int isOK =
351
                gdal.GCPsToGeoTransform(gcps, gcpsGeotransform);
352
            if (isOK != 0) {
353
                geotransform = gcpsGeotransform;
354
            }
355
        }
356

    
357
        return geotransform;
358
    }
359

    
360
    private Envelope createEnvelope(double[] geotransform){
361

    
362
        double leftMostX        = geotransform[0];/* top left x */
363
        double pixelSizeX       = geotransform[1];/* w-e pixel resolution */
364
        double rotationAxisX    = geotransform[2];/* 0 */
365
        double upperMostY       = geotransform[3];/* top left y */
366
        double rotationAxisY    = geotransform[4];/* 0 */
367
        double pixelSizeY       = geotransform[5];/* n-s pixel resolution (negative value) */
368

    
369
        if (0.0 != rotationAxisX || 0.0 != rotationAxisY) {
370
            logger.warn(
371
                "Rotation in wld file not implemented yet. It will be ignored");
372
        }
373

    
374
        double width =gdalDataSet.getRasterXSize()*pixelSizeX;
375
        double height=gdalDataSet.getRasterYSize()*pixelSizeY;
376

    
377
        // double minX, double minY, double maxX, double maxY, int subType
378
        try {
379
            envelope = GeometryLocator.getGeometryManager().createEnvelope(
380
                Math.min(leftMostX,leftMostX + width),
381
                Math.min(upperMostY,upperMostY + height),
382
                Math.max(leftMostX,leftMostX + width),
383
                Math.max(upperMostY,upperMostY + height),
384
                Geometry.SUBTYPES.GEOM2D);
385
        } catch (LocatorException | CreateEnvelopeException e) {
386
            logger.warn(
387
                "Failed to create envelope from wld file with coords: minx:"+leftMostX+
388
                ", miny:"+upperMostY+", maxX: "+leftMostX + width+", maxY: "+upperMostY + height);
389
            e.printStackTrace();
390
        }
391

    
392
        return envelope;
393
    }
394

    
395
    @Override
396
    public Object getDynValue(String name) throws DynFieldNotFoundException {
397
        if( DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name) ) {
398
            return this.envelope;
399
        } else if( DataStore.METADATA_CRS.equalsIgnoreCase(name) ) {
400
            IProjection pro = this.getRasterGdalParameters().getCRS();
401
            if (pro != null) {
402
                return pro;
403
            }
404
        }
405
        return super.getDynValue(name);
406
    }
407

    
408
    @Override
409
    public void close() throws CloseException {
410
        this.gdalDataSet = null;
411
    }
412

    
413
    @Override
414
    public ResourceProvider getResource() {
415
        return this.resource;
416
    }
417

    
418

    
419
    @Override
420
    public Object getSourceId() {
421
        return this.getRasterGdalParameters().getFile();
422
    }
423

    
424
    @Override
425
    public String getProviderName() {
426
        return NAME;
427
    }
428

    
429
    @Override
430
    public String getName() {
431
        String name = this.getRasterGdalParameters().getFile().getName();
432
        return FilenameUtils.getBaseName(name);
433
    }
434

    
435
    @Override
436
    public String getFullName() {
437
        return this.getRasterGdalParameters().getFile().getAbsolutePath();
438
    }
439

    
440
    @Override
441
    public boolean closeResourceRequested(ResourceProvider resource) {
442
        return true;
443
    }
444

    
445
    @Override
446
    /*
447
     * (non-Javadoc)
448
     *
449
     * @see
450
     * org.gvsig.fmap.dal.resource.spi.ResourceConsumer#resourceChanged(org.
451
     * gvsig.fmap.dal.resource.spi.ResourceProvider)
452
     */
453
    public void resourceChanged(ResourceProvider resource) {
454
        this.getStoreServices().notifyChange(
455
            DataStoreNotification.RESOURCE_CHANGED,
456
            resource);
457
    }
458

    
459
    @Override
460
    /* (non-Javadoc)
461
     * @see org.gvsig.fmap.dal.feature.spi.memory.AbstractMemoryStoreProvider#doDispose()
462
     */
463
    protected void doDispose() throws BaseException {
464
        super.doDispose();
465
        resource.removeConsumer(this);
466
    }
467

    
468
    /**
469
     * Conversi?n de los tipos de datos de gdal a los tipos de datos de RasterBuf
470
     * @param gdalType Tipo de dato de gdal
471
     * @return Tipo de dato de RasterBuf
472
     */
473
    protected static int getRasterBufTypeFromGdalType(int gdalType) {
474
        switch (gdalType) {
475
            case 1:// Eight bit unsigned integer GDT_Byte = 1
476
                return BufferManager.TYPE_BYTE;
477

    
478
            case 3:// Sixteen bit signed integer GDT_Int16 = 3,
479
                return BufferManager.TYPE_SHORT;
480

    
481
            case 2:// Sixteen bit unsigned integer GDT_UInt16 = 2
482
                //return RasterBuffer.TYPE_USHORT;
483
                return BufferManager.TYPE_SHORT; //Apa?o para usar los tipos de datos que soportamos
484

    
485
            case 5:// Thirty two bit signed integer GDT_Int32 = 5
486
                return BufferManager.TYPE_INT;
487

    
488
            case 6:// Thirty two bit floating point GDT_Float32 = 6
489
                return BufferManager.TYPE_FLOAT;
490

    
491
            case 7:// Sixty four bit floating point GDT_Float64 = 7
492
                return BufferManager.TYPE_DOUBLE;
493

    
494
                // TODO:Estos tipos de datos no podemos gestionarlos. Habria que definir
495
                // el tipo complejo y usar el tipo long que de momento no se gasta.
496
            case 4:// Thirty two bit unsigned integer GDT_UInt32 = 4,
497
                return BufferManager.TYPE_INT;
498
                //return RasterBuffer.TYPE_UNDEFINED; // Deberia devolver un Long
499

    
500
            case 8:// Complex Int16 GDT_CInt16 = 8
501
            case 9:// Complex Int32 GDT_CInt32 = 9
502
            case 10:// Complex Float32 GDT_CFloat32 = 10
503
            case 11:// Complex Float64 GDT_CFloat64 = 11
504
                return BufferManager.TYPE_UNDEFINED;
505
        }
506
        return BufferManager.TYPE_UNDEFINED;
507
    }
508
}