Search code examples
javageotools

Geotools: Total area where GridCoverage has value x


I'm working in Geotools with Java. So far, I have a GridCoverage2D and a List of Geometries. The GridCoverage2D is a digital elevation model, originating from a geotiff. Everything works fine till here.

Now I want to get the area for each polygon where the elevation has a certain value. For example for this Geometry, I want to know the total area where the elevation is 27 m. How can I achieve this?

I have no clue how to start :(

Two options I have in mind:

  • Splitting the geometries in small parts (How do I do this), for each point get the center point (I can do this) and then evaluate this GridCoverage2D. That way I have a list with very small geometries, and an elevation corresponding to each geometry. Some array magic is all that's needed further. Is this a good plan, and how do I quickly split the geometry in small parts?
  • Using a filter/query. Yet I don't know how that works and the tutorial isn't helping. Is it even possible to achieve what I want with a filter?

Solution

  • This turned out to be harder than I expected, which probably means I've missed something obvious. You can solve the question by creating a histogram of the coverage and then selecting the bin which contains your value. The all you need to do is multiply the total number of cells by the area of a cell.

    So assuming you've read in or created a coverage:

     private double selectCells(GridCoverage2D cov, int value) {
        GridGeometry2D geom = cov.getGridGeometry();
        // cov.show();
        final OperationJAI op = new OperationJAI("Histogram");
        ParameterValueGroup params = op.getParameters();
        GridCoverage2D coverage;
        params.parameter("Source").setValue(cov);
        coverage = (GridCoverage2D) op.doOperation(params, null);
        javax.media.jai.Histogram hist = (Histogram) coverage
                .getProperty("histogram");
    
        int total = hist.getSubTotal(0, value, value);
        double area = calcAreaOfCell(geom);
        Unit<?> unit = cov.getCoordinateReferenceSystem().getCoordinateSystem()
                .getAxis(0).getUnit();
        System.out.println("which gives " + (area * total) + " " + unit
                + "^2 area with value " + value);
        return area * total;
    }
    
    private double calcAreaOfCell(GridGeometry2D geom) {
        GridEnvelope gridRange = geom.getGridRange();
        int width = gridRange.getHigh(0) - gridRange.getLow(0) + 1; // allow for the
        int height = gridRange.getHigh(1) - gridRange.getLow(1) + 1;// 0th row/col
        Envelope envelope = geom.getEnvelope();
        double dWidth = envelope.getMaximum(0) - envelope.getMinimum(0);
        double dHeight = envelope.getMaximum(1) - envelope.getMinimum(1);
        double cellWidth = dWidth / width;
        double cellHeight = dHeight / height;
    
        return cellWidth * cellHeight;
    }
    

    Obviously if you plan on calling it more than once you can cache the histogram and the cellsize.