All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jeo.gdal.GDALDataset Maven / Gradle / Ivy

The newest version!
/* Copyright 2014 The jeo project. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.jeo.gdal;

import io.jeo.geom.Bounds;
import io.jeo.raster.Band;
import io.jeo.raster.DataBuffer;
import io.jeo.raster.DataType;
import io.jeo.raster.Raster;
import io.jeo.raster.Stats;
import io.jeo.util.Dimension;
import io.jeo.util.Key;
import io.jeo.util.Rect;
import io.jeo.util.Util;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.gdal;
import org.gdal.osr.SpatialReference;
import io.jeo.data.Driver;
import io.jeo.data.FileData;
import io.jeo.raster.RasterDataset;
import io.jeo.raster.RasterQuery;
import io.jeo.proj.Proj;
import org.osgeo.proj4j.CoordinateReferenceSystem;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static org.gdal.gdalconst.gdalconstConstants.*;

public class GDALDataset implements RasterDataset, FileData {

    Dataset dataset;
    File file;
    GDAL driver;

    public GDALDataset(File file, Dataset dataset, GDAL driver) {
        this.file = file;
        this.dataset = dataset;
        this.driver = driver;
    }

    @Override
    public File file() {
        return file;
    }

    @Override
    public String name() {
        return Util.base(file.getName());
    }

    public String description() {
        return dataset.GetDescription();
    }

    @Override
    public Driver driver() {
        return driver;
    }

    @Override
    public Map, Object> driverOptions() {
        LinkedHashMap, Object> opts = new LinkedHashMap, Object>();
        opts.put(GDAL.FILE, file);
        return opts;
    }

    @Override
    public CoordinateReferenceSystem crs() throws IOException {
        String proj = dataset.GetProjection();
        if (proj != null) {
            SpatialReference ref = new SpatialReference(proj);
            return Proj.crs(ref.ExportToProj4());
        }
        return null;
    }

    @Override
    public Bounds bounds() throws IOException {
        return bounds(dataset);
    }

    Bounds bounds(Dataset dataset) {
        Dimension size = size(dataset);
        double[] tx = dataset.GetGeoTransform();
        return new Bounds(tx[0], tx[0] + size.width() * tx[1],
                tx[3], tx[3] + size.width()*tx[4] + size.height()*tx[5]);
    }

    @Override
    public Dimension size() {
        return size(dataset);
    }

    Dimension size(Dataset dataset) {
        return new Dimension(dataset.getRasterXSize(), dataset.getRasterYSize());
    }

    public Rect rect() {
        return rect(dataset);
    }

    Rect rect(Dataset dataset) {
        Dimension size = size(dataset);
        return new Rect(0, 0, size.width(), size.height());
    }

    @Override
    public List bands() throws IOException {
        int nbands = dataset.GetRasterCount();

        List bands = new ArrayList(nbands);
        for (int i = 1; i <= nbands; i++) {
            bands.add(new GDALBand(dataset.GetRasterBand(i)));
        }

        return bands;
    }

    @Override
    public Raster read(RasterQuery query) throws IOException {
        Raster raster = new Raster();

        Dataset data = dataset;

        // reprojection
        raster.crs(crs());
        if (query.crs() != null && !Proj.equal(query.crs(), crs())) {
            String srcWkt = toWKT(crs());
            String dstWkt = toWKT(query.crs());

            //TODO: allow query to specify interpolation method
            data = gdal.AutoCreateWarpedVRT(dataset, srcWkt, dstWkt);
            raster.crs(query.crs());
        }

        // area of raster to load
        Rect r = rect(data);            // raster space
        Bounds bbox = bounds(data);   // world space
        if (query.bounds() != null) {
            // intersect bounds with query bounds
            Bounds i = bbox.intersection(query.bounds());
            r = r.map(i, bbox);
            bbox = i;
        }
        raster.bounds(bbox);

        // raster size
        Dimension s = query.size();
        if (s == null) {
            s = size(data);
        }
        raster.size(s);

        // band selection
        List queryBands = bands(query.bands());
        int[] bands = new int[queryBands.size()];
        for (int i = 0 ; i < queryBands.size(); i++) {
            GDALBand band = queryBands.get(i);
            bands[i] = band.index();
        }
        raster.bands((List)queryBands);

        // figure out the buffer type if not specified
        DataType datatype = query.datatype();
        if (datatype == null) {
            datatype = DataType.BYTE;
            for (int i = 0 ; i < queryBands.size(); i++) {
                GDALBand band = queryBands.get(i);
                DataType dt = band.datatype();
                if (dt.compareTo(datatype) > 0) {
                    datatype = dt;
                }
            }
        }

        ByteBuffer buffer = ByteBuffer.allocateDirect(s.width()*s.height()*datatype.size());
        buffer.order(ByteOrder.nativeOrder());

        if (bands.length == 1) {
            // single band, read in same units as requested buffer
            data.ReadRaster_Direct(r.left, r.top, r.width(), r.height(), s.width(), s.height(),
                toGDAL(datatype), buffer, bands, 0, 0, 0);
        }
        else {
            // multi band mode, read as byte and back into buffer
            data.ReadRaster_Direct(r.left, r.top, r.width(), r.height(), s.width(), s.height(),
                GDT_Byte, buffer, bands, datatype.size(), 0, 1);
        }

        return raster.data(DataBuffer.create(buffer, datatype));
    }

    int toGDAL(DataType datatype) {
        switch(datatype) {
            case CHAR:
                break;
            case BYTE:
                return GDT_Byte;
            case SHORT:
                return GDT_Int16;
            case INT:
                return GDT_Int32;
            case LONG:
                return GDT_UInt32;
            case FLOAT:
                return GDT_Float32;
            case DOUBLE:
                return GDT_Float64;
        }
        throw new IllegalArgumentException("unsupported data type: " + datatype);
    }

    String toWKT(CoordinateReferenceSystem crs) {
        SpatialReference ref = new SpatialReference();
        ref.ImportFromProj4(Proj.toString(crs));
        return ref.ExportToWkt();
    }

    List bands(int[] bands) throws IOException {
        List allBands = bands();

        if (bands == null || bands.length == 0) {
            return (List) allBands;
        }

        List list = new ArrayList(bands.length);
        for (int b : bands) {
            list.add((GDALBand) allBands.get(b));
        }

        return list;
    }

    @Override
    public void close() {
        if (dataset != null) {
            dataset.delete();
            dataset = null;
        }
    }

    static class GDALBand implements Band {

        org.gdal.gdal.Band band;

        GDALBand(org.gdal.gdal.Band band) {
            this.band = band;
        }

        @Override
        public String name() {
            return band.GetDescription();
        }

        int index() {
            return band.GetBand();
        }

        @Override
        public Color color() {
            int ci = band.GetColorInterpretation();
            return ci == GCI_Undefined ? Color.UNDEFINED :
                   ci == GCI_GrayIndex ? Color.GRAY :
                   ci == GCI_RedBand ? Color.RED :
                   ci == GCI_GreenBand ? Color.GREEN :
                   ci == GCI_BlueBand ? Color.BLUE : Color.GRAY;
        }

        @Override
        public DataType datatype() {
            int dt = band.GetRasterDataType();
            return dt == GDT_Byte ? DataType.BYTE :
                   dt == GDT_Int16 ? DataType.SHORT :
                   dt == GDT_UInt16 ? DataType.INT :
                   dt == GDT_Int32 ?  DataType.INT :
                   dt == GDT_UInt32 ? DataType.LONG :
                   dt == GDT_Float32 ? DataType.FLOAT :
                   dt == GDT_Float64 ? DataType.DOUBLE :
                   null;

            //TODO
            //GDT_CInt16
            //GDT_CInt32
            //GDT_CFloat32
            //GDT_CFloat64
        }

        @Override
        public Double nodata() {
            Double[] nodata = new Double[]{null};
            band.GetNoDataValue(nodata);
            return nodata[0];
        }

        @Override
        public Stats stats() throws IOException {
            Stats stats = new Stats();

            double[] arr = new double[2];
            band.ComputeRasterMinMax(arr);
            stats.min(arr[0]).max(arr[1]);

            band.ComputeBandStats(arr);
            stats.mean(arr[0]).stdev(arr[1]);

            return stats;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy