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

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

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

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

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

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

  File f = new File ( "world.shp" ); ShapefileDataStore dataStore = new ShapefileDataStore ( f.toURI ().toURL () ); FeatureSource 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 features = featureSource .getFeatures ( filter ); filter = ff.intersects ( ff.property ( geomAttrName ), ff.literal ( pointWater ) ); features = featureSource.getFeatures ( filter ); 

快速解释:

  1. 假设您获得的shapefile是多边形数据。 线或点上的交叉点不会给你你想要的东西。
  2. 第一部分打开shapefile – 没有什么有趣的
  3. 您必须获取给定文件的几何属性名称
  4. 坐标系的东西 – 你在你的post中指定了lat / long但是GIS可能要复杂得多。 一般来说,我指出的数据是地理,wgs84 ,这就是我在这里设置的。 但是,如果您不是这种情况,那么您需要确保在正确的坐标系中处理数据。 如果这听起来像胡言乱语,谷歌周围的GIS /坐标系/基准/椭圆体教程。
  5. 生成坐标几何和filter是非常明显的。 由此产生的一组特征将为空,这意味着如果您的数据是土地覆盖,则坐标在水中,或者不是空的,这意味着相反。

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

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

  1. 下载一卡车的KML文件,其中包含仅限陆地的位置。
  2. 从中提取所有坐标, 这可能对此有所帮助 。
  3. 随机挑选它们。

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

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

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

在此处输入图像描述

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

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

2.列出项目

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

此外 – 一些水确实属于国家,地区……所以是的,不是很精确。

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

当然你应该有一个地图作为资源。 你可以在这里拿到它: http : //www.naturalearthdata.com/

然后我会准备1位黑白位图资源,1s标记着陆和0x标记水。

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

然后我将在Java中加载此位图,生成具有上述范围的随机整数,读取位,并且如果它为零则重新生成。

PS你也可以在http://geotools.org/挖掘一些现成的解决方案。

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

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

我使用的基本思想是在Google Earth Api中实现GEView对象的hiTest方法 。

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

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

这是我使用的实现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调用后移动地球视图。 这是使用小辅助function实现的。

 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调整到更高的altitude ,如50m解决了这个但显然它正在缩小可能选择的坐标的面积。

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

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

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

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

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

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

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

  1. 去那里http://wiki.openstreetmap.org/
  2. 尝试使用API​​: http : //wiki.openstreetmap.org/wiki/Databases_and_data_access_APIs

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

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

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

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

海拔api? 海拔或以下的http://code.google.com/apis/maps/documentation/elevation/ ? (没有荷兰点!)

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

补充bsimic关于挖掘GeoNames的Webservices的内容,这是一个捷径:
他们有一个专门的WebService来请求海洋名称

(由于请求数量的原因,我知道OP对于使用公共Web服务的限制。但是我偶然发现了同样的基本问题,并认为这有用。)

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

关于海洋区域的请求示例(波罗的海,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 } } 

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

打开你最喜欢的地图服务,在美国,俄罗斯,中国,西欧和非洲北部画一个矩形 – 确保矩形内没有大湖或里海。 取每个矩形的角坐标,然后这些矩形随机选择坐标。

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

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

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

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

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

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

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

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

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