从 GeoServer(Google 地图)获取图层要素信息

问题描述 投票:0回答:2

我正在使用 Android Studio(使用 Java)编写 Android 应用程序。该应用程序使用 Google 地图,并有一个包含从地理服务器获取的字段所有权信息的图层。设置此功能的代码如下,并且运行良好。

public class App1Step1 extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_app1_step1);
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);

        TileProvider tileProvider = TileProviderFactory.getTileProvider();
        mMap.addTileOverlay(new TileOverlayOptions().tileProvider(tileProvider));
    }
}

class TileProviderFactory {
    private static final String GEOSERVER_FORMAT =
            "http://xxxxxxxx.at/geoserver/wms" +
                    "?service=WMS" +
                    "&version=1.1.1" +
                    "&request=GetMap" +
                    "&layers=satgrass:INSPIRE_SCHLAEGE_2020_POLYGON" +
                    "&bbox=%f,%f,%f,%f" +
                    "&width=256" +
                    "&height=256" +
                    "&srs=EPSG:900913" +
                    "&format=image/png" +
                    "&transparent=true";

    static TileProvider getTileProvider() {
        TileProvider tileProvider = new WMSTileProvider(256,256) {

            @Override
            public synchronized URL getTileUrl(int x, int y, int zoom) {
                double[] bbox = getBoundingBox(x, y, zoom);
                String s = String.format(Locale.US, GEOSERVER_FORMAT, bbox[MINX], bbox[MINY], bbox[MAXX], bbox[MAXY]);
                
                URL url = null;
                
                try {
                    url = new URL(s);
                } catch (MalformedURLException e) {
                    throw new AssertionError(e);
                }
                
                return url;
            }
        };

        return tileProvider;
    }
}

abstract class WMSTileProvider extends UrlTileProvider {
    // Web Mercator n/w corner of the map.
    private static final double[] TILE_ORIGIN = {-20037508.34789244, 20037508.34789244};
    //array indexes for that data
    private static final int ORIG_X = 0;
    private static final int ORIG_Y = 1; // "

    // Size of square world map in meters, using WebMerc projection.
    private static final double MAP_SIZE = 20037508.34789244 * 2;

    // array indexes for array to hold bounding boxes.
    protected static final int MINX = 0;
    protected static final int MAXX = 1;
    protected static final int MINY = 2;
    protected static final int MAXY = 3;
    
    // Construct with tile size in pixels, normally 256, see parent class.
    public WMSTileProvider(int x, int y) {
        super(x, y);
    }

    // Return a web Mercator bounding box given tile x/y indexes and a zoom
    // level.
    protected double[] getBoundingBox(int x, int y, int zoom) {
        double tileSize = MAP_SIZE / Math.pow(2, zoom);
        double minx = TILE_ORIGIN[ORIG_X] + x * tileSize;
        double maxx = TILE_ORIGIN[ORIG_X] + (x+1) * tileSize;
        double miny = TILE_ORIGIN[ORIG_Y] - (y+1) * tileSize;
        double maxy = TILE_ORIGIN[ORIG_Y] - y * tileSize;

        double[] bbox = new double[4];
        bbox[MINX] = minx;
        bbox[MINY] = miny;
        bbox[MAXX] = maxx;
        bbox[MAXY] = maxy;

        return bbox;
    }
}

上面的代码将在 Google 地图上生成以下叠加层。在地理服务器上,图层保存为 EPSG:31287 (Austria Lambert)。

我现在想做的是当我单击其中一个字段时获取功能信息。我尝试了很多,但无法弄清楚如何计算必要的值(宽度、高度、x、y、bbox)以从我单击的纬度和经度获取特征信息。具体来说,这些是我缺少的查询中的值。

String url = "http://xxxxxxxxxxx.at/geoserver/wms" +
                "?service=WMS" +
                "&version=1.1.1" +
                "&request=GetFeatureInfo" +
                "&layers=satgrass:INSPIRE_SCHLAEGE_2020_POLYGON" +
                "&query_layers=satgrass:INSPIRE_SCHLAEGE_2020_POLYGON" +
                "&exceptions=application/vnd.ogc.se_inimage" +
                "&x=" +                             // ????????
                "&y=" +                             // ????????
                "&bbox=" +                          // ????????
                "&width=" +                         // ????????
                "&height=" +                        // ????????
                "&srs=EPSG:900913" +                // EPSG:900913 or EPSG:31287 ?
                "&format=image/png" +
                "&info_format=application/json" +
                "&transparent=true" +
                "&feature_count=50";

到目前为止我所做的(我认为)是根据纬度、经度和缩放级别计算我点击的 x 和 y 位置。

private void getFeatureInfo(LatLng latLng) {
    // get current zoom
    int zoom = (int)mMap.getCameraPosition().zoom;

    // get "click" point coordinates in pixels
    long pointNorthWestX = lonToX(latLng.longitude, zoom);
    long pointNorthWestY = latToY(latLng.latitude, zoom);
}

public static long lonToX(double lon, int zoom) {
    int offset = 256 << (zoom - 1);
    return (int)Math.floor(offset + (offset * lon / 180));
}

public static long latToY(double lat, int zoom) {
    int offset = 256 << (zoom - 1);
    return (int)Math.floor(offset - offset / Math.PI * Math.log((1 + Math.sin(Math.toRadians(lat))) / (1 - Math.sin(Math.toRadians(lat)))) / 2);
}

不幸的是,与我在地理服务器上的图层预览中单击相同位置时获得的值相比,这些值似乎相差很大。

有谁知道从纬度、经度和缩放级别获取我点击位置的要素信息需要哪些计算步骤?我非常感谢您对此提供的任何帮助。

java android android-studio geoserver getfeatureinfo
2个回答
0
投票

A

getFeatureRequest
本质上是用于获取您正在查询的地图并添加了一些参数的
getMap
请求。您必须添加
QUERY_LAYERS
(您想要了解其信息的图层的名称)以及
X
Y
(或版本 1.3.0 中的
I
J
),它们是您想要的像素的位置有关(因此您单击的位置)的信息。或者,您可以添加
info_format
来控制返回的格式。

有关更多详细信息,我建议您阅读标准文档


0
投票

我已经找到了解决方案,而且比我想象的要容易得多。地理服务器已经支持从我通过单击地图获得的 LatLon 值到

getFeatureInfo()
请求所需的 XY 坐标的投影转换。

我已将代码更改为以下内容。

private void getFeatureInfo(LatLng latLng) {
    String url = "http://xxxxxxxxxx.at/geoserver/wms" +
            "?service=WMS" +
            "&version=1.1.1" +
            "&request=GetFeatureInfo" +
            "&layers=satgrass:INSPIRE_SCHLAEGE_2020_POLYGON" +
            "&query_layers=satgrass:INSPIRE_SCHLAEGE_2020_POLYGON" +
            "&exceptions=application/vnd.ogc.se_inimage" +
            "&x=128" +
            "&y=128" +
            "&bbox=" + (latLng.longitude - 0.0000000001) + "," + (latLng.latitude - 0.0000000001) + "," + (latLng.longitude + 0.0000000001) + "," + (latLng.latitude + 0.0000000001) +
            "&width=256" +
            "&height=256" +
            "&srs=EPSG:4326" +
            "&format=image/png" +
            "&info_format=application/json" +
            "&transparent=true" +
            "&feature_count=50";
}

width
height
都是
256
,我最初是在TileProvider中设置的。
x
y
值都是
128
,这将是每个图块的中心。

我现在基本上需要做的是创建一个边界框,地理服务器将在其中寻找特征。我将其设置得尽可能小(应在厘米或毫米范围内),因此仅返回 1 个特征。为此,我将

0.0000000001
minX
minY
值中分散出来,并将
0.0000000001
添加到
maxX
maxY
值中。

重要的部分是使用

EPSG:4326
来完成此请求。然后,地理服务器将自动计算
EPSG:31287
图层的投影并返回该点的要素信息。

© www.soinside.com 2019 - 2024. All rights reserved.