随机地理坐标(陆地上,避开海洋)
关于如何生成地球上地点的随机坐标(纬度/经度)有什么聪明的想法吗?纬度/经度。精度为 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 个坐标。由于延迟、成本和其他一些因素,寻求外部服务提供商可能不是最佳选择。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
处理水体问题在很大程度上将是一个数据问题,例如,您是否只想错过海洋,还是还需要错过小溪流。您要么需要使用具有所需数据质量的服务,要么需要自己获取数据并在本地运行。从您的编辑看来,您似乎想要采用本地数据路线,因此我将重点介绍一种实现此目的的方法。
一种方法是获取陆地区域或水域的形状文件。然后,您可以生成一个随机点并确定它是否与陆地区域相交(或者不与水域相交)。
首先,您可能会获得一些低分辨率数据 此处,然后获取更高分辨率的数据 这里适用于当您想在海岸线或湖泊/河流/等方面获得更好的答案时。您提到您希望点的精度达到小数点后 5 位,即 1m 多一点。请注意,如果您获得的数据符合该精度,您将拥有一个巨大的数据集。而且,如果您想要真正好的数据,请准备好为此付费。
获得形状数据后,您需要一些工具来帮助您确定随机点的交点。 Geotools 是一个很好的起点,可能会满足您的需求。您最终还将查看 opengis 代码(geotools 网站下的文档 - 不确定他们是否使用了它们或什么)和 JTS 用于几何处理。使用它,您可以快速打开形状文件并开始执行一些交集查询。
快速解释:
注意:如果您使用一组非常随机的点来执行此操作,您会经常遇到水,并且可能需要一段时间才能达到 25k 点。您可能想尝试比真正随机更好地确定点生成范围(例如删除大西洋/太平洋/印度洋的大块区域)。
此外,您可能会发现交叉点查询太慢。如果是这样,您可能需要考虑使用 GDAL 等工具创建四叉树索引 (qix)。不过,我不记得 geotools 支持哪些索引类型。
To deal with the body of water problem is going to be largely a data issue, e.g. do you just want to miss the oceans or do you need to also miss small streams. Either you need to use a service with the quality of data that you need, or, you need to obtain the data yourself and run it locally. From your edit, it sounds like you want to go the local data route, so I'll focus on a way to do that.
One method is to obtain a shapefile for either land areas or water areas. You can then generate a random point and determine if it intersects a land area (or alternatively, does not intersect a water area).
To get started, you might get some low resolution data here and then get higher resolution data here for when you want to get better answers on coast lines or with lakes/rivers/etc. You mentioned that you want precision in your points to 5 decimal places, which is a little over 1m. Do be aware that if you get data to match that precision, you will have one giant data set. And, if you want really good data, be prepared to pay for it.
Once you have your shape data, you need some tools to help you determine the intersection of your random points. Geotools is a great place to start and probably will work for your needs. You will also end up looking at opengis code (docs under geotools site - not sure if they consumed them or what) and JTS for the geometry handling. Using this you can quickly open the shapefile and start doing some intersection queries.
Quick explanations:
Note: if you do this with a really random set of points, you are going to hit water pretty often and it could take you a while to get to 25k points. You may want to try to scope your point generation better than truly random (like remove big chunks of the Atlantic/Pacific/Indian oceans).
Also, you may find that your intersection queries are too slow. If so, you may want to look into creating a quadtree index (qix) with a tool like GDAL. I don't recall which index types are supported by geotools, though.
这个问题很久以前就有人问过,我现在也有类似的需求。我正在研究两种可能性:
1。定义随机生成器的表面范围。
这里重要的是确定您想要的精度级别。最简单的方法是采用一种非常轻松且近似的方法。在这种情况下,您可以将世界地图划分为“框”:
每个框都有自己的经纬度范围。然后,您首先随机化以获得一个随机框,然后您随机化以获得该框边界内的随机纬度和随机长。
当然,精度在这里根本不是最好的......尽管这取决于:)如果你做好功课并定义了很多覆盖最复杂表面形状的盒子 - 你可能对精度相当满意。
2.列表项
一些API从坐标返回大陆名称或地址或国家或地区= WATER 没有的东西。 Google 地图 API 可以在这方面提供帮助。我没有对此进行更深入的研究,但我认为这是可能的,尽管您必须对每个生成的坐标对运行检查,如果错误则重新运行。因此,如果随机生成器不断将你扔进海里,你可能会陷入困境。
另外 - 有些水确实属于国家、地区......所以是的,不是很精确。
出于我的需要 - 我将使用“盒子”,因为我还想控制从中获取随机坐标的确切区域,并且不介意它是否落在湖泊或河流上,而不是公海:)
This has being asked a long time ago and I now have the similar need. There are two possibilities I am looking into:
1. Define the surface ranges for the random generator.
Here it's important to identify the level of precision you are going for. The easiest way would be to have a very relaxed and approximate approach. In this case you can divide the world map into "boxes":
Each box has it's own range of lat lon. Then you first randomise to get a random box, then you randomise to get a random lat and random long within the boundaries of that box.
Precisions is of course not the best at all here... Though it depends:) If you do your homework well and define a lot of boxes covering most complex surface shapes - you might be quite ok with the precision.
2. List item
Some API to return continent name from coordinates OR address OR country OR district = something that WATER doesn't have. Google Maps API's can help here. I didn't research this one deeper, but I think it's possible, though you will have to run the check on each generated pair of coordinates and rerun IF it's wrong. So you can get a bit stuck if random generator keeps throwing you in the ocean.
Also - some water does belong to countries, districts...so yeah, not very precise.
For my needs - I am going with "boxes" because I also want to control exact areas from which the random coordinates are taken and don't mind if it lands on a lake or river, just not open ocean:)
为了在纬度和经度上获得良好的均匀分布,您应该执行以下操作以获得正确的角度:
至于避免水体,您有水所在位置的数据吗?好吧,只需重新采样,直到获得成功!如果您还没有这些数据,那么似乎其他人有一些比我更好的建议......
希望这有帮助,干杯。
To get a nice even distribution over latitudes and longitudes you should do something like this to get the right angles:
As for avoiding bodies of water, do you have the data for where water is already? Well, just resample until you get a hit! If you don't have this data already then it seems some other people have some better suggestions than I would for that...
Hope this helps, cheers.
当然,您应该有一张地图作为资源。你可以在这里: http://www.naturalearthdata.com/
然后我会准备1bit黑白位图资源,1s 标记陆地,0x 标记水。
位图的大小取决于您所需的精度。如果您需要 5 度,那么您的位图将为 360/5 x 180/5 = 72x36 像素 = 2592 位。
然后我会在 Java 中加载这个位图,生成上述范围内的随机整数,读取位,如果为零则重新生成。
PS 此外,您还可以在这里挖掘 http://geotools.org/ 以获得一些现成的解决方案。
Definitely you should have a map as a resource. You can take it here: http://www.naturalearthdata.com/
Then I would prepare 1bit black and white bitmap resource with 1s marking land and 0x marking water.
The size of bitmap depends on your required precision. If you need 5 degrees then your bitmap will be 360/5 x 180/5 = 72x36 pixels = 2592 bits.
Then I would load this bitmap in Java, generate random integer withing range above, read bit, and regenerate if it was zero.
P.S. Also you can dig here http://geotools.org/ for some ready made solutions.
还有另一种方法可以使用 Google Earth Api 来解决此问题。我知道它是 javascript,但我认为这是解决问题的一种新颖方法。
无论如何,我在这里整理了一个完整的工作解决方案 - 请注意它也适用于河流: http://www.msa.mmu.ac.uk/~fraser/ge/coord/
我使用的基本想法是实现 hiTest 方法。 com/earth/documentation/reference/interface_g_e_view" rel="nofollow">GEView Google 地球 Api 中的对象。
看看以下来自 Google 的热门示例。
http://earth-api-samples.googlecode.com/svn /trunk/examples/hittest.html
hitTest 方法提供了屏幕上的一个随机点(像素坐标),它返回一个 GEHitTestResult 对象,该对象包含有关与该点对应的地理位置的信息。如果使用 GEPlugin.HIT_TEST_TERRAIN 模式和方法,只要我们将结果筛选到海拔 > 1 的点,就可以将结果限制为仅陆地(地形)。 1m
这是我用来实现 hitTest 的函数:
显然,您还希望获得来自地球上任何地方的随机结果(不仅仅是从单个视点可见的随机点)。为此,我在每次成功调用
hitTestTerrain
后移动地球视图。这是使用一个小的辅助函数来实现的。最后,这是调用这两个方法的主代码块的精简版本。
因此,地球随机移动到一个位置。
其中的其他函数只是帮助程序生成随机 x,y 和随机 lat,lng 数字,输出结果以及切换控件等。
我已经对代码进行了相当多的测试位,结果并不是 100% 完美,将
海拔
调整到更高的值,比如 50m 可以解决这个问题,但显然它会减少可能选定坐标的区域。显然,您可以调整这个想法以满足您的需要。也许多次运行代码来填充数据库或其他东西。
There is another way to approach this using the Google Earth Api. I know it is javascript, but I thought it was a novel way to solve the problem.
Anyhow, I have put together a full working solution here - notice it works for rivers too: http://www.msa.mmu.ac.uk/~fraser/ge/coord/
The basic idea I have used is implement the hiTest method of the GEView object in the Google Earth Api.
Take a look at the following example of the hitest from Google.
http://earth-api-samples.googlecode.com/svn/trunk/examples/hittest.html
The hitTest method is supplied a random point on the screen in (pixel coordinates) for which it returns a GEHitTestResult object that contains information about the geographic location corresponding to the point. If one uses the GEPlugin.HIT_TEST_TERRAIN mode with the method one can limit results only to land (terrain) as long as we screen the results to points with an altitude > 1m
This is the function I use that implements the hitTest:
Obviously you also want to have random results from anywhere on the globe (not just random points visible from a single viewpoint). To do this I move the earth view after each successful
hitTestTerrain
call. This is achieved using a small helper function.Finally here is a stripped down version of the main code block that calls these two methods.
So, the earth moves randomly to a postition
The other functions in there are just helpers to generate the random x,y and random lat,lng numbers, to output the results and also to toggle the controls etc.
I have tested the code quite a bit and the results are not 100% perfect, tweaking the
altitude
to something higher, like 50m solves this but obviously it is diminishing the area of possible selected coordinates.Obviously you could adapt the idea to suit you needs. Maybe running the code multiple times to populate a database or something.
作为备用计划,也许您可以随机选择一个国家/地区,然后在该国家/地区内选择一个随机坐标。为了公平起见,在选择国家/地区时,您可以使用其面积作为权重。
As a plan B, maybe you can pick a random country and then pick a random coordinate inside of this country. To be fair when picking a country, you can use its area as weight.
这里有一个库,您可以使用它.random() 方法获取随机坐标。然后您可以使用 GeoNames WebServices 来确定是否在陆地上。他们有一份网络服务列表,您只需使用正确的服务即可。 GeoNames 是免费且可靠的。
There is a library here and you can use its .random() method to get a random coordinate. Then you can use GeoNames WebServices to determine whether it is on land or not. They have a list of webservices and you'll just have to use the right one. GeoNames is free and reliable.
正如公认的答案所指出的那样 - 实施的质量取决于所使用的地理数据的质量。
如果有人需要更精确和最新的方法来检查坐标是否在陆地或水域(包括河流、溪流、池塘等),您可以考虑 REST API IsItWater.com - 增强现实游戏 Randonauts 使用该服务来解决同样的问题。当您使用他们的“避免水”功能时,它会根据 IsItWater api 检查生成的兴趣点。
响应如下所示:
As the accepted answer points out - the quality of the implementation depends on the quality of the geographic data in use.
If someone need a more precise and current way to check if a coordinate is on land or water (including rivers, streams, ponds, etc), you could consider the REST API IsItWater.com - the service is used by the augmented reality game Randonauts to solve this very same issue. When you use their "avoid water" feature it checks generated points of interest against the IsItWater api.
A response looks like:
我想您可以使用世界地图,在其上定义几个点来界定大多数水体,如您所说,并使用 Polygon.contains 方法来验证坐标。
更快的算法是使用这张地图,随机取一些点并检查下面的颜色,如果是蓝色,则为水......当您获得坐标时,将它们转换为纬度/经度。
I guess you could use a world map, define a few points on it to delimit most of water bodies as you say and use a polygon.contains method to validate the coordinates.
A faster algorithm would be to use this map, take some random point and check the color beneath, if it's blue, then water... when you have the coordinates, you convert them to lat/long.
您也可以执行蓝绿色操作,然后存储所有绿色点以供以后查找。这样做的好处是可以“逐步”精炼。当您找到更好的方法来制作点列表时,您可以将随机抓取器指向越来越准确的点组。
也许服务提供商已经对您的问题有了答案:例如 https://www.google.com/enterprise/marketplace/viewListing?productListingId=3030+17310026046429031496&pli=1
海拔 api? http://code.google.com/apis/maps/documentation/elevation/ 高于海平面还是低于海平面? (没有荷兰积分给你!)
You might also do the blue green thing , and then store all the green points for later look up. This has the benifit of being "step wise" refinable. As you figure out a better way to make your list of points you can just point your random graber at a more and more acurate group of points.
Maybe a service provider has an answer to your question already: e.g. https://www.google.com/enterprise/marketplace/viewListing?productListingId=3030+17310026046429031496&pli=1
Elevation api? http://code.google.com/apis/maps/documentation/elevation/ above sea level or below? (no dutch points for you!)
发电很容易,问题是它们不应该在水上。我将在这里导入“开放街道地图”http://ftp.ecki-netz.de/osm / 并将其导入数据库(非常简单的数据结构)。我建议使用 PostgreSQL,它带有一些地理函数 http://www.postgresql.org/docs/8.2/static/functions-geometry.html" rel="nofollow">http://www.postgresql.org postgresql.org/docs/8.2/static/functions-geometry.html 。为此,您必须将点保存在“多边形”列中,然后您可以使用“&&”进行检查运算符(如果它位于水多边形中)。对于 OpenStreetmap Way-Entry 的属性,您应该查看 http://wiki。 openstreetmap.org/wiki/Category:En:Keys
Generating is easy, the Problem is that they should not be on water. I would import the "Open Streetmap" for example here http://ftp.ecki-netz.de/osm/ and import it to an Database (verry easy data Structure). I would suggest PostgreSQL, it comes with some geo functions http://www.postgresql.org/docs/8.2/static/functions-geometry.html . For that you have to save the points in a "polygon"-column, then you can check with the "&&" operator if it is in an Water polygon. For the attributes of an OpenStreetmap Way-Entry you should have a look at http://wiki.openstreetmap.org/wiki/Category:En:Keys
作为对 bsimic 所说的有关深入 GeoNames 的 Web 服务的补充,这里有一个快捷方式:
他们有一个用于请求海洋名称的专用 Web 服务。
(我知道 OP 由于请求数量而限制不使用公共网络服务。尽管如此,我还是偶然发现了这一点,并提出了相同的基本问题,并认为这很有帮助。)
转到 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
结果
有关 陆地上的坐标结果为
Supplementary to what bsimic said about digging into GeoNames' Webservices, here is a shortcut:
they have a dedicated WebService for requesting an ocean name.
(I am aware the of OP's constraint to not using public web services due to the amount of requests. Nevertheless I stumbled upon this with the same basic question and consider this helpful.)
Go to http://www.geonames.org/export/web-services.html#astergdem and have a look at "Ocean / reverse geocoding". It is available as XML and JSON. Create a free user account to prevent daily limits on the demo account.
Request example on ocean area (Baltic Sea, JSON-URL):
http://api.geonames.org/oceanJSON?lat=54.049889&lng=10.851388&username=demo
results in
while some coordinates on land result in
随机点必须均匀分布在世界各地吗?如果您可以满足表面上的均匀分布,您可以这样做:
打开您最喜欢的地图服务,在美国、俄罗斯、中国、西欧以及非洲北部绘制一个矩形 -确保矩形内没有大湖泊或里海。获取每个矩形的角坐标,然后在这些矩形内随机选择坐标。
向您保证这些点都不会位于任何海洋或湖泊上。您可能偶尔会发现一条河流,但我不确定有多少地理服务对此足够准确。
Do the random points have to be uniformly distributed all over the world? If you could settle for a seemingly uniform distribution, you can do this:
Open your favorite map service, draw a rectangle inside the United States, Russia, China, Western Europe and definitely the northern part of Africa - making sure there are no big lakes or Caspian seas inside the rectangles. Take the corner coordinates of each rectangle, and then select coordinates at random inside those rectangles.
You are guaranteed non of these points will be on any sea or lake. You might find an occasional river, but I'm not sure how many geoservices are going to be accurate enough for that anyway.
从理论和实践的角度来看,这是一个非常有趣的问题。最合适的解决方案很大程度上取决于您的具体要求。您需要考虑所有水域,还是只考虑主要的海洋?准确性和正确性有多重要;将海洋识别为陆地或反之亦然会是灾难性的失败吗?
我认为机器学习技术将是解决这个问题的一个很好的解决方案,只要你不介意一个水点被错误地分类为陆地的概率(希望很小)。如果这不是问题,那么与其他技术相比,这种方法应该具有许多优势。
使用位图是一个很好的解决方案,简单而优雅。它可以按照指定的精度生成,并且保证分类是正确的(或者至少与您制作位图一样正确)。但其实用性取决于您需要解决方案的准确性。您提到您希望坐标精度达到小数点后 5 位(这相当于将地球的整个表面映射到最接近的米)。每个元素使用 1 位,位图的重量约为 73.6 TB!
不过,我们不需要存储所有这些数据;我们只需要知道海岸线在哪里。只要知道一个点相对于海岸的位置,我们就可以确定它是在陆地上还是在海上。根据中央情报局世界概况的粗略估计,地球上的海岸线有 22498 公里。如果我们要存储每米海岸线的坐标,并为每个纬度和经度使用 32 位字,则存储所需的空间将少于 1.35GB。如果这对于一个简单的应用程序来说仍然很多,但比使用位图少几个数量级。如果不需要如此高的准确度,这些数字将会大幅下降。将映射减少到最近的公里将使位图只有约 75GB,并且世界海岸线的坐标可以放在软盘上。
我的建议是使用聚类算法来确定一个点是否在陆地上。我们首先需要大量已知的陆地或海上坐标。现有的 GIS 数据库适合于此。然后我们可以分析这些点以确定陆地和海洋的聚类。簇之间的决策边界应该落在海岸线上,并且所有不确定决策边界的点都可以被删除。可以迭代该过程以给出逐渐更准确的边界。
仅需要存储确定决策边界/海岸线的点,并且通过使用简单的距离度量,我们可以快速轻松地确定一组坐标是在陆地上还是在海上。训练系统需要大量资源,但一旦完成,分类器将只需要很少的空间或时间。
This is an extremely interesting question, from both a theoretical and practical perspective. The most suitable solution will largely depend on your exact requirements. Do you need to account for every body of water, or just the major seas and oceans? How critical are accuracy and correctness; Will identifying sea as land or vice-versa be a catastrophic failure?
I think machine learning techniques would be an excellent solution to this problem, provided that you don't mind the (hopefully small) probability that a point of water is incorrectly classified as land. If that's not an issue, then this approach should have a number of advantages against other techniques.
Using a bitmap is a nice solution, simple and elegant. It can be produced to a specified accuracy and the classification is guaranteed to be correct (Or a least as correct as you made the bitmap). But its practicality is dependent on how accurate you need the solution to be. You mention that you want the coordinate accuracy to 5 decimal places (which would be equivalent to mapping the whole surface of the planet to about the nearest metre). Using 1 bit per element, the bitmap would weigh in at ~73.6 terabytes!
We don't need to store all of this data though; We only need to know where the coastlines are. Just by knowing where a point is in relation to the coast, we can determine whether it is on land or sea. As a rough estimate, the CIA world factbook reports that there are 22498km of coastline on Earth. If we were to store coordiates for every metre of coastline, using a 32 bit word for each latitude and longitude, this would take less than 1.35GB to store. It's still a lot if this is for a trivial application, but a few orders of magnitude less than using a bitmap. If having such a high degree of accuracy isn't neccessary though, these numbers would drop considerably. Reducing the mapping to only the nearest kilometre would make the bitmap just ~75GB and the coordinates for the world's coastline could fit on a floppy disk.
What I propose is to use a clustering algorithm to decide whether a point is on land or not. We would first need a suitably large number of coordinates that we already know to be on either land or sea. Existing GIS databases would be suitable for this. Then we can analyse the points to determine clusters of land and sea. The decision boundary between the clusters should fall on the coastlines, and all points not determining the decision boundary can be removed. This process can be iterated to give a progressively more accurate boundary.
Only the points determining the decision boundary/the coastline need to be stored, and by using a simple distance metric we can quickly and easily decide if a set of coordinates are on land or sea. A large amount of resources would be required to train the system, but once complete the classifier would require very little space or time.
假设亚特兰蒂斯不在数据库中,您可以随机选择城市。如果您打算模仿人类活动,这还提供了更真实的点分布:
https://simplemaps.com/data/world-cities
免费的城市只有 7,300 个版本。
Assuming Atlantis isn't in the database, you could randomly select cities. This also provides a more realistic distribution of points if you intend to mimic human activity:
https://simplemaps.com/data/world-cities
There's only 7,300 cities in the free version.