随机地理坐标(在陆地上,避开海洋)

2022-09-01 08:59:29

关于如何生成地球上地方的随机坐标(纬度/经度)的任何聪明想法?纬度/经度。精确到5点,避免水体。

    double minLat = -90.00;
    double maxLat = 90.00;      
    double latitude = minLat + (double)(Math.random() * ((maxLat - minLat) + 1));
    double minLon = 0.00;
    double maxLon = 180.00;     
    double longitude = minLon + (double)(Math.random() * ((maxLon - minLon) + 1));
    DecimalFormat df = new DecimalFormat("#.#####");        
    log.info("latitude:longitude --> " + df.format(latitude) + "," + df.format(longitude));

也许我生活在一个梦想的世界里,水的话题是不可避免的......但希望有一种更好,更干净,更有效的方法可以做到这一点?

编辑

一些奇妙的答案/想法 - 但是,在规模上,假设我需要生成25,000个坐标。由于延迟,成本和其他一些因素,去外部服务提供商可能不是最佳选择。


答案 1

处理水体问题在很大程度上将是一个数据问题,例如,您只是想错过海洋还是还需要错过小溪流。您需要使用具有所需数据质量的服务,或者需要自己获取数据并在本地运行。从您的编辑中,听起来您想走本地数据路线,因此我将重点介绍一种方法。

一种方法是获取陆地区域或水域的 shapefile。然后,您可以生成一个随机点,并确定它是否与陆地区域相交(或者不与水域区域相交)。

首先,您可能会在此处获得一些低分辨率数据,然后在此处获取更高分辨率的数据,以便在海岸线或湖泊/河流等获得更好的答案时。您提到您希望点的精度达到小数点后5位,这略高于1m。请注意,如果您获取的数据与该精度相匹配,则将拥有一个巨大的数据集。而且,如果您想要真正好的数据,请准备好为此付费。

获得形状数据后,您需要一些工具来帮助您确定随机点的交集。Geotools是一个很好的起点,可能会满足您的需求。您最终还将查看opengis代码(geotools site下的文档 - 不确定他们是否使用了它们或什么)和JTS用于几何处理。使用此功能,您可以快速打开 shapefile 并开始执行一些交集查询。

    File f = new File ( "world.shp" );
    ShapefileDataStore dataStore = new ShapefileDataStore ( f.toURI ().toURL () );
    FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = 
        dataStore.getFeatureSource ();
    String geomAttrName = featureSource.getSchema ()
        .getGeometryDescriptor ().getLocalName ();

    ResourceInfo resourceInfo = featureSource.getInfo ();
    CoordinateReferenceSystem crs = resourceInfo.getCRS ();
    Hints hints = GeoTools.getDefaultHints ();
    hints.put ( Hints.JTS_SRID, 4326 );
    hints.put ( Hints.CRS, crs );

    FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2 ( hints );
    GeometryFactory gf = JTSFactoryFinder.getGeometryFactory ( hints );

    Coordinate land = new Coordinate ( -122.0087, 47.54650 );
    Point pointLand = gf.createPoint ( land );
    Coordinate water = new Coordinate ( 0, 0 );
    Point pointWater = gf.createPoint ( water );

    Intersects filter = ff.intersects ( ff.property ( geomAttrName ), 
        ff.literal ( pointLand ) );
    FeatureCollection<SimpleFeatureType, SimpleFeature> features = featureSource
            .getFeatures ( filter );

    filter = ff.intersects ( ff.property ( geomAttrName ), 
        ff.literal ( pointWater ) );
    features = featureSource.getFeatures ( filter );

快速解释:

  1. 这假设您获得的 shapefile 是多边形数据。线或点上的交叉点不会给你你想要的东西。
  2. 第一部分打开形状文件 - 没什么有趣的
  3. 您必须获取给定文件的几何属性名称
  4. 坐标系的东西 - 你在帖子中指定了纬度/经度,但GIS可能要复杂得多。通常,我指向您的数据是地理的,wgs84,这就是我在这里设置的数据。但是,如果您不是这种情况,则需要确保在正确的坐标系中处理数据。如果这听起来像是胡言乱语,请谷歌搜索有关GIS/坐标系/基准面/椭圆体的教程。
  5. 生成坐标几何和过滤器是不言自明的。生成的要素集将为空(如果数据为土地覆被),则表示坐标在水中,或者不为空(表示相反)。

注意:如果你用一组非常随机的点来做到这一点,你将经常打水,你可能需要一段时间才能达到25k点。您可能希望尝试确定点生成的范围,而不是真正随机的(例如删除大西洋/太平洋/印度洋的大块)。

此外,您可能会发现交叉查询速度太慢。如果是这样,您可能需要考虑使用 GDAL 等工具创建四端树索引 (qix)。但是,我不记得geotools支持哪些索引类型。


答案 2

这在很久以前就有人问过了,我现在也有类似的需求。我正在研究两种可能性:

1. 定义随机生成器的表面范围。

在这里,重要的是要确定您要追求的精度水平。最简单的方法是采用非常轻松和近似的方法。在这种情况下,您可以将世界地图划分为“框”:

enter image description here

每个盒子都有自己的纬度范围。然后,您首先随机化以获得一个随机框,然后随机化以在该框的边界内获得随机纬度和随机长整型。

精度当然不是最好的...虽然视情况而定:)如果你做好了功课,并定义了很多覆盖最复杂表面形状的盒子 - 你可能对精度很满意。

2. 列表项

一些 API 用于从坐标或地址或国家/地区或地区返回大陆名称 = 水没有的东西。Google Maps API可以在这里提供帮助。我没有更深入地研究这个,但我认为这是可能的,尽管你必须对每个生成的坐标对运行检查,如果错误,请重新运行。所以你可能会有点卡住,如果随机生成器继续把你扔进海里。

另外 - 有些水确实属于国家,地区...所以是的,不是很精确。

为了我的需求 - 我使用“盒子”,因为我也想控制随机坐标的确切区域,并且不介意它是否落在湖泊或河流上,只是不是开阔的海洋:)


推荐