view geo-backend/src/main/java/de/intevation/gnv/geobackend/sde/datasources/RasterObject.java @ 548:ccd976fc0f7b

Implemented bilinear interpolation on raster tiles. geo-backend/trunk@520 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Sat, 09 Jan 2010 16:12:10 +0000
parents 23d5cc37dd5b
children 0dcf068fb552
line wrap: on
line source
/**
 *
 */
package de.intevation.gnv.geobackend.sde.datasources;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;

import java.io.Serializable;


import org.apache.log4j.Logger;

/**
 * @author Tim Englich (tim.englich@intevation.de)
 * @author Sascha L. Teichmann (sascha.teichmann@intevation.de)
 */
public class RasterObject 
implements   Serializable
{
    private static Logger log = Logger.getLogger(RasterObject.class);

    public static final int NEAREST_NEIGHBOR = 0;
    public static final int BILINEAR         = 1;

    private double mx;
    private double bx;
    private double my;
    private double by;

    private int columnIndex;
    private int rowIndex;

    private int tileWidth;
    private int tileHeight;

    private double [] rasterData;

    public RasterObject() {
    }

    public RasterObject(
        double mx, double bx,
        double my, double by,
        int       columnIndex, 
        int       rowIndex,
        double [] rasterData,
        int       tileWidth,
        int       tileHeight
    ){
        this.mx          = mx;
        this.bx          = bx;
        this.my          = my;
        this.by          = by;
        this.columnIndex = columnIndex;
        this.rowIndex    = rowIndex;
        this.rasterData  = rasterData;
        this.tileWidth   = tileWidth;
        this.tileHeight  = tileHeight;
    }

    public boolean contains(Coordinate coordinate) {
        double px = mx*coordinate.x + bx;
        double py = my*coordinate.y + by;
        return px >= 0d && py >= 0d && px < tileWidth && py < tileHeight;
    }

    public final double get(int posX, int posY) {
        return rasterData[posY*tileWidth + posX];
    }

    public int getTileWidth() {
        return tileWidth;
    }

    public int getTileHeight() {
        return tileWidth;
    }

    public int getColumnIndex() {
        return columnIndex;
    }

    public int getRowIndex() {
        return rowIndex;
    }
    
    public double getValue(Coordinate coordinate) {
        return getValue(coordinate, NEAREST_NEIGHBOR);
    }

    public final double interpolateBilinear(double px, double py) {

        if (px < 0.5d) { // left border
            if (py < 0.5d) { // upper left edge
                return rasterData[0];
            }
            if (py > tileHeight-0.5d) { // lower left edge
                return rasterData[rasterData.length-tileWidth];
            }
            // center left
            int    i = (int)(py -= 0.5d);
            double t = py - i;
            i *= tileWidth;
            return (1d-t)*rasterData[i] + t*rasterData[i+tileWidth];
        }

        if (px > tileWidth-0.5d) { // right border
            if (py < 0.5d) { // upper right edge
                return rasterData[tileWidth-1];
            }
            if (py > tileHeight-0.5d) { // lower right edge
                return rasterData[rasterData.length-1];
            }
            // center right
            int    i = (int)(py -= 0.5d);
            double t = py - i;
            i = i*tileWidth + tileWidth-1;
            return (1d-t)*rasterData[i] + t*rasterData[i+tileWidth];
        }

        if (py < 0.5d) { // top border
            int    i = (int)(px -= 0.5d);
            double t = px - i;
            return (1d-t)*rasterData[i] + t*rasterData[i+1];
        }

        if (py > tileHeight-0.5d) { // bottom border
            int    i = (int)(px -= 0.5d);
            double t = px - i;
            i += rasterData.length-tileWidth;
            return (1d-t)*rasterData[i] + t*rasterData[i+1];
        }

        // center
        int    i  = (int)(py -= 0.5d);
        int    j  = (int)(px -= 0.5d);
        double ti = py - i;
        double tj = px - j;

        int idx = i*tileWidth + j;

        double v1j1 = rasterData[idx];
        double v2j1 = rasterData[idx+1];

        idx += tileWidth;

        double v1j2 = rasterData[idx];
        double v2j2 = rasterData[idx+1];

        double v1 = (1d-tj)*v1j1 + tj*v2j1;
        double v2 = (1d-tj)*v1j2 + tj*v2j2;

        return (1d-ti)*v1 + ti*v2;
    }

    public double getValue(Coordinate coordinate, int interpolationType) {

        double px = mx*coordinate.x + bx;
        double py = my*coordinate.y + by;

        if (px < 0d || py < 0d || px >= tileWidth || py >= tileHeight) {
            return Double.NaN;
        }

        if (interpolationType == BILINEAR) {
            return interpolateBilinear(px, py);
        }

        int posX = Math.min(tileWidth-1,  (int)Math.round(px));
        int posY = Math.min(tileHeight-1, (int)Math.round(py));

        return get(posX, posY);
    }
}

http://dive4elements.wald.intevation.org