关于如何生成地球上的地方的随机坐标(纬度/经度)的任何聪明的想法?纬度/经度。精确到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个坐标。由于延迟,成本和一些其他因素,去外部服务提供商可能不是最佳选择。
答案 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 );
快速解释:
注意:如果你用一组非常随机的点来做这件事,你会经常打水,这可能需要一段时间才能达到25k点。您可能希望尝试更好地确定您的点生成范围,而不是真正随机(例如移除大西洋/太平洋/印度洋的大块)。
此外,您可能会发现您的交叉点查询太慢。如果是这样,您可能希望使用GDAL之类的工具来创建四叉树索引(qix)。我不记得geotools支持哪些索引类型。
答案 1 :(得分:4)
答案 2 :(得分:4)
这是很久以前的问题,我现在有类似的需求。我正在研究两种可能性:
<强> 1。定义随机生成器的表面范围。
确定您的目标精确度非常重要。最简单的方法是采用非常放松和近似的方法。在这种情况下,您可以将世界地图划分为“框”:
每个盒子都有自己的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 method中GEView object的Google 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个城市。