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

时间:2012-02-01 23:21:21

标签: java gis geocoding

关于如何生成地球上的地方的随机坐标(纬度/经度)的任何聪明的想法?纬度/经度。精确到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个坐标。由于延迟,成本和一些其他因素,去外部服务提供商可能不是最佳选择。

16 个答案:

答案 0 :(得分:14)

处理水体问题将主要是一个数据问题,例如:你想错过海洋吗?或者你也想错过小溪。您需要使用具有所需数据质量的服务,或者您需要自己获取数据并在本地运行。从你的编辑,听起来你想要去本地数据路线,所以我将专注于一种方法来做到这一点。

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

要开始使用,您可能会获得一些低分辨率数据here,然后获得更高分辨率数据here,以便在海岸线或湖泊/河流/等处获得更好的答案。你提到你希望你的点精度达到5位小数,这个位置略超过1米。请注意,如果您获得的数据与该精度相匹配,您将拥有一个巨大的数据集。而且,如果您想要非常好的数据,请准备为此付费。

获得形状数据后,您需要一些工具来帮助您确定随机点的交集。 Geotools是一个很好的起点,可能会满足您的需求。您最终还会查看opengis代码(geotools网站下的文档 - 不确定它们是否消耗它们或者是什么)以及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. 第一部分打开shapefile - 没有什么有趣的
  3. 您必须获取给定文件的几何属性名称
  4. 坐标系的东西 - 你在帖子中指定了lat / long但是GIS可能会复杂得多。一般来说,我指出的数据是geographic, wgs84,这就是我在这里设置的。但是,如果您不是这种情况,那么您需要确保在正确的坐标系中处理数据。如果这听起来像是胡言乱语,请浏览一下GIS /坐标系/基准/椭圆体的教程。
  5. 生成坐标几何和过滤器非常明显。由此产生的一组特征将为空,这意味着如果您的数据是土地覆盖,则坐标在水中,或者不是空的,这意味着相反。
  6. 注意:如果你用一组非常随机的点来做这件事,你会经常打水,这可能需要一段时间才能达到25k点。您可能希望尝试更好地确定您的点生成范围,而不是真正随机(例如移除大西洋/太平洋/印度洋的大块)。

    此外,您可能会发现您的交叉点查询太慢。如果是这样,您可能希望使用GDAL之类的工具来创建四叉树索引(qix)。我不记得geotools支持哪些索引类型。

答案 1 :(得分:4)

  1. 下载一卡车的KML文件,其中包含仅限土地的位置。
  2. 从中提取所有坐标this might help here
  3. 随意挑选。

答案 2 :(得分:4)

这是很久以前的问题,我现在有类似的需求。我正在研究两种可能性:

<强> 1。定义随机生成器的表面范围。

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

enter image description here

每个盒子都有自己的lat lon范围。然后你首先随机获得一个随机框,然后你随机获得一个随机lat并在该框的边界内随机长。

精确度当然不是最好的......虽然它取决于:)如果你做好功课并定义了许多覆盖大多数复杂表面形状的盒子 - 你可能对精度非常好。

<强> 2。列表项

从坐标返回大陆名称的某些API或地址OR国家或地区= WATER没有的东西。 Google Maps API可以在这里提供帮助。我没有更深入地研究这个,但我认为这是可能的,尽管你必须对每个生成的坐标对运行检查并重新运行,如果它是错误的。如果随机发生器不断将你扔到海里,你就会陷入困境。

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

根据我的需要 - 我会选择“盒子”,因为我也想控制随机坐标所在的确切区域,不介意它是否落在湖泊或河流上,而不是开放海洋:)< / p>

答案 3 :(得分:3)

你肯定应该有一张地图作为资源。您可以在此处查看:http://www.naturalearthdata.com/

然后我会准备1位黑白位图资源,标记为1,标记为0x。

位图的大小取决于您所需的精度。如果你需要5度,那么你的位图将是360/5 x 180/5 = 72x36像素= 2592位。

然后我会在Java中加载这个位图,生成范围在上面的随机整数,读取位,如果它为零则重新生成。

P.S。您也可以在这里挖掘http://geotools.org/以获得一些现成的解决方案。

答案 4 :(得分:3)

还有另一种方法可以使用Google Earth Api来解​​决这个问题。我知道这是javascript,但我认为这是一种解决问题的新方法。

无论如何,我已经在这里整理了一个完整的解决方案 - 注意它也适用于河流:http://www.msa.mmu.ac.uk/~fraser/ge/coord/

我使用的基本思想是实现hiTest methodGEView objectGoogle Earth Api

查看以下来自Google的hitest示例。 http://earth-api-samples.googlecode.com/svn/trunk/examples/hittest.html

在屏幕上(像素坐标)中为hitTest方法提供一个随机点,它返回一个GEHitTestResult对象,该对象包含有关该点对应的地理位置的信息。如果使用GEPlugin.HIT_TEST_TERRAIN模式和方法,只要我们将结果筛选到海拔高度> gt的点,就可以将结果限制为只有陆地(地形)。 1米

这是我使用的实现hitTest的函数:

var hitTestTerrain = function()
{
    var x = getRandomInt(0, 200); // same pixel size as the map3d div height
    var y = getRandomInt(0, 200); // ditto for width
    var result = ge.getView().hitTest(x, ge.UNITS_PIXELS, y, ge.UNITS_PIXELS, ge.HIT_TEST_TERRAIN);
    var success = result && (result.getAltitude() > 1);
    return { success: success, result: result };
};

显然,您还希望从地球上的任何位置获得随机结果(而不仅仅是从单个视点可见的随机点)。为此,我会在每次成功hitTestTerrain电话后移动地球视图。这是通过使用小辅助函数实现的。

var flyTo = function(lat, lng, rng)
{
    lookAt.setLatitude(lat);
    lookAt.setLongitude(lng);
    lookAt.setRange(rng);
    ge.getView().setAbstractView(lookAt);
};

最后,这是一个主要代码块的精简版本,它调用这两种方法。

var getRandomLandCoordinates = function()
{
    var test = hitTestTerrain();
    if (test.success)
    {
        coords[coords.length] = { lat: test.result.getLatitude(), lng: test.result.getLongitude() };
    }

    if (coords.length <= number)
    {
       getRandomLandCoordinates();
    }
    else
    {
       displayResults();
    }
};

所以,地球随机移动到一个帖子

其他函数只是帮助生成随机x,y和随机lat,lng数字,输出结果以及切换控件等。

我已经对代码进行了相当多的测试,并且结果并非100%完美,将altitude调整到更高的值,就像50米解决了这个问题,但显然它正在缩小可能选定坐标的面积。

显然,你可以根据自己的需要调整这个想法。也许多次运行代码来填充数据库或其他东西。

答案 5 :(得分:2)

要在纬度和经度上获得均匀分布,你应该做这样的事情来获得正确的角度:

double longitude = Math.random() * Math.PI * 2;
double latitude = Math.acos(Math.random() * 2 - 1);

至于避开水体,你有水已经存在的数据吗?好吧,只需重新采样,直到你受到欢迎!如果您还没有这些数据,那么其他人似乎有一些比我更好的建议......

希望这会有所帮助,欢呼。

答案 6 :(得分:2)

作为计划B,也许您可​​以选择一个随机国家/地区,然后选择该国家/地区内的随机坐标。为了公平地选择一个国家,你可以使用它的面积作为重量。

答案 7 :(得分:1)

有一个库here,您可以使用其.random()方法获取随机坐标。然后,您可以使用GeoNames WebServices来确定它是否在陆地上。他们有一个web服务列表,你只需要使用正确的服务。 GeoNames是免费且可靠的。

答案 8 :(得分:1)

答案 9 :(得分:0)

我想你可以使用世界地图,在它上面定义几个点来划分大多数水体,并按照你说的方式使用polygon.contains方法验证坐标。

更快的算法是使用这个地图,取一些随机点并检查下面的颜色,如果它是蓝色,然后是水......当你有坐标时,你将它们转换为纬度/经度。

答案 10 :(得分:0)

你也可以做蓝绿色的东西,然后存储所有的绿点以便以后查找。这具有“逐步”可精炼的益处。当你想出一个更好的方法来制作你的积分列表时,你可以将你的随机记者指向越来越精确的一组积分。

也许服务提供商已经回答了您的问题:例如https://www.google.com/enterprise/marketplace/viewListing?productListingId=3030+17310026046429031496&pli=1

海拔高度? http://code.google.com/apis/maps/documentation/elevation/海拔以下? (没有荷兰分!)

答案 11 :(得分:0)

生成很容易,问题是他们不应该在水上。我会导入“Open Streetmap”,例如http://ftp.ecki-netz.de/osm/,然后将其导入数据库(verry easy data Structure)。我建议使用PostgreSQL,它带有一些地理函数http://www.postgresql.org/docs/8.2/static/functions-geometry.html。为此你必须将点保存在“多边形”列中,然后你可以检查“&amp;&amp;”运算符,如果它在水多边形中。有关OpenStreetmap Way-Entry的属性,您应该查看http://wiki.openstreetmap.org/wiki/Category:En:Keys

答案 12 :(得分:0)

作为bsimic关于挖掘GeoNames Web服务的说法的补充,这是一个快捷方式:
他们有一个用于请求海洋名称的专用Web服务

(由于请求量大,我知道OP限制使用使用公共Web服务。尽管如此,我还是偶然遇到了相同的基本问题,并认为这是有帮助的。)

转到http://www.geonames.org/export/web-services.html#astergdem,然后查看“ 海洋/反向地理编码”。它以XML和JSON的形式提供。创建一个免费的用户帐户以防止对模拟帐户进行每日限制。

关于海洋区域(波罗的海,JSON-URL)的请求示例:

http://api.geonames.org/oceanJSON?lat=54.049889&lng=10.851388&username=demo

产生

{
  "ocean": {
    "distance": "0",
    "name": "Baltic Sea"
  }
}

在陆地上产生一些坐标

{
  "status": {
    "message": "we are afraid we could not find an ocean for latitude and longitude :53.0,9.0",
    "value": 15
  }
}

答案 13 :(得分:-1)

随机点是否必须在全世界均匀分布?如果您能够满足看似的统一分布,那么您可以这样做:

打开您最喜爱的地图服务,在美国,俄罗斯,中国,西欧以及非洲北部绘制一个矩形 - 确保矩形内没有大湖或里海。取每个矩形的角坐标,然后选择随机里面那些矩形的坐标。

您可以保证这些点不在任何海洋或湖泊上。您可能偶尔会发现河流,但我不确定有多少地理服务准确无误。

答案 14 :(得分:-1)

从理论和实践的角度来看,这是一个非常有趣的问题。最合适的解决方案在很大程度上取决于您的确切要求。您需要考虑每一个水体,或仅仅是主要的海洋和海洋吗?准确性和正确性至关重要;将海洋确定为陆地还是反之亦然会造成灾难性的失败?

我认为机器学习技术对于这个问题是一个很好的解决方案,前提是你不介意将水点错误地归类为土地的(希望很小)概率。如果这不是问题,那么这种方法应该具有许多优于其他技术的优势。

使用位图是一个很好的解决方案,简单而优雅。它可以按照指定的精度生成,并保证分类正确(或者至少与制作位图一样正确)。但它的实用性取决于您需要解决方案的准确程度。您提到您希望坐标精度为5位小数(这相当于将行星的整个表面映射到大约最近的米)。每个元素使用1位,位图的重量为~73.6太字节!

我们不需要存储所有这些数据;我们只需要知道海岸线在哪里。只要知道一个点与海岸的关系,我们就可以确定它是在陆地还是海上。据粗略估计,中情局世界事实报告称地球上有22498公里的海岸线。如果我们要为每米海岸线存储坐标,每个纬度和经度使用32位字,这将需要不到1.35GB存储。如果这是一个简单的应用程序,它仍然很多,但比使用位图少几个数量级。如果不是必须具有如此高的准确度,那么这些数字将会大幅下降。将映射缩小到最近的公里将使位图仅为75GB,并且世界海岸线的坐标可以放在软盘上。

我建议使用聚类算法来决定一个点是否在陆上。我们首先需要一个我们已经知道在陆地或海上的适当大量的坐标。现有的GIS数据库适用于此。然后我们可以分析这些点来确定陆地和海洋的集群。群集之间的决策边界应落在海岸线上,并且可以消除不确定决策边界的所有点。可以迭代此过程以提供逐渐更准确的边界。

只需要存储确定决策边界/海岸线的点,并且通过使用简单的距离度量,我们可以快速轻松地确定一组坐标是在陆地还是海上。训练系统需要大量资源,但一旦完成,分类器将需要很少的空间或时间。

答案 15 :(得分:-1)

假设亚特兰蒂斯不在数据库中,您可以随机选择城市。如果您打算模仿人类活动,这也可以提供更真实的点分布: https://simplemaps.com/data/world-cities

免费版本中只有7,300个城市。