如何在 PostGIS 数据库中存储值网格,以便 GeoServer 可以绘制轮廓?

How to store a grid of values in a PostGIS database such that it can be contoured by GeoServer?

我计划将 GeoServer 与 PostGIS 数据库结合使用,以通过 Web 地图服务提供等高线。

我有一个简单的经纬度值网格,我想将其存储在数据库中并绘制轮廓。虽然 GeoServer 用户手册暗示在此示例中是可能的...

https://docs.geoserver.org/stable/en/user/styling/sld/extensions/rendering-transform.html#contour-extraction

...它没有讨论数据应该采用什么格式。请有人建议我可以使用的合适的 PostGIS 数据库模式,GeoServer 可以理解并能够绘制轮廓?最好是可以与上面 link 中的 GeoServer 示例一起使用的一个。

感谢您的帮助。

由于您的数据已经在 Java 程序中,我将深入研究 GeoTools which is the underlying library that GeoServer 用于完成实际工作。

查看 ContourProcess what you actually need is a GridCoverage2D,这是对二维渲染图像支持的网格数据值的基本访问。图像中的每个波段都表示为样本维度。

所以你想要获取数据数组并执行如下操作:

WritableRaster raster2 = RasterFactory.createBandedRaster(java.awt.image.DataBuffer.TYPE_INT, w,
    h, 1, null);
for (int i = 0; i < w; i++) {//width...
     for (int j = 0; j < h; j++) {
         raster2.setSample(i, j, 0, myData[i*w+j]);
     }
}
GridCoverageFactory gcf = new GridCoverageFactory();
// Here I'm using OSGB as I live in the UK you would be using something else
CoordinateReferenceSystem crs = CRS.decode("EPSG:27700");
// Position of Lower Left Corner of grid
int llx = 500000;
int lly = 105000;
// Pixel size in projection units
int resolution = 10;
ReferencedEnvelope referencedEnvelope = new ReferencedEnvelope(llx, llx + (w * resolution), lly, lly + (h * resolution),
    crs);
GridCoverage2D gc = gcf.create("name", raster2, referencedEnvelope);

然后您可以将其写成 GeoTiff 或将以上所有内容包装到 a new Process 中 returns 等高线。

所以我玩了一把,可以确认@IanTurton 的代码很有魅力。这是我的最终代码,基于他的代码,主要区别在于我使用的是 lat/long 坐标参考系统,并且我包含了一些代码以将栅格写为 GeoTIFF...

import java.awt.image.WritableRaster;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;

import java.io.File;
import java.io.IOException;

import javax.media.jai.RasterFactory;

import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.geotools.gce.geotiff.GeoTiffWriter;
import org.opengis.parameter.ParameterValue;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

public class GridToGeoTiff {

    public static void main(String[] args) throws NoSuchAuthorityCodeException, FactoryException, IllegalArgumentException, IndexOutOfBoundsException, IOException {

        // Define the data grid
        double[][] myGrid = {
                { 0.0, 0.2, 0.6, 0.3 },
                { 0.1, 1.1, 0.8, 0.7 },
                { 1.1, 2.6, 3.4, 0.3 },
                { 0.3, 0.9, 0.6, 0.1 }
        };

        int w = myGrid.length;
        int h = myGrid[0].length;

        // Position of Lower Left Corner of grid
        double southBound = 51.5074; // degrees latitude
        double westBound = 0.1278; // degrees latitude
        double resolution = 0.001; // degrees lat/long

        // Convert to a Raster
        WritableRaster raster2 = RasterFactory.createBandedRaster(java.awt.image.DataBuffer.TYPE_INT, w, h, h, null);
            for (int i = 0; i < w; i++) {
                 for (int j = 0; j < h; j++) {
                      raster2.setSample(i, j, 0, myGrid[j][i]);
                 }
            }

            // Create a GeoTools 2D grid referenced in lat/long 
            GridCoverageFactory gcf = new GridCoverageFactory();
            CoordinateReferenceSystem crs = DefaultGeographicCRS.WGS84;
            ReferencedEnvelope referencedEnvelope = new ReferencedEnvelope(
                westBound, westBound + (w * resolution), southBound, southBound + (h * resolution), crs
            );
            GridCoverage2D gc = gcf.create("my-grid", raster2, referencedEnvelope);

            // Write out to a GeoTIFF file
            final File geotiff = new File("my-grid.tif");
            final ImageOutputStream imageOutStream = ImageIO.createImageOutputStream(geotiff);
            GeoTiffWriter writer = new GeoTiffWriter(imageOutStream);
            final ParameterValue<Boolean> tfw = GeoTiffFormat.WRITE_TFW.createValue();
            tfw.setValue(true);
            writer.write(gc, null);
            writer.dispose();
    }
}

我正在使用以下 Maven 依赖项...

  • org.geotools 22.2: gt-main, gt-coverage, gt-referencing, gt-geometry, gt-geotiff
  • org.opengis 2.2.0: geoapi
  • org.locationtech.jts 1.16.1: jts-核心
  • javax.media.jai 1.1.3: com.springsource.javax.media.jai.core

...来自 Boundless 和 OSGeo 存储库。

使用此代码创建 GeoTIFF 文件后,我可以使用它在 GeoServer 中设置商店,然后发布它。我在 GeoServer 的 contouring example 中调整了 SLD(实际上只是更改了名称和等高线阈值)来创建一种样式,然后我将其应用于已发布的 GeoTIFF 数据,等高线出现在地图上!

但是...我的数据不是静态的,我将生成许多不同的网格,因此这种基于文件的方法会有点笨拙。因此,我将研究 GeoServer 的 ImageMosaic plugin as a way of getting the contours straight from the database. However, it seems that this is not a popular option, and might not be production ready (according to this post),这样我最终可能会自己绘制数据轮廓并将其存储为矢量。如果有人对此有进一步的想法,我很想听听他们的意见。

感谢大家的帮助!