在谷歌地图中验证一个点是陆地还是水域

IT技术 javascript google-maps google-maps-api-3
2021-02-02 21:17:54

..然后谷歌地图“将水域与水域分开”

好吧,不是在圣经意义上,而是..

我想知道我有哪些选项可以验证 [Lat, Lon] 的点是陆地还是水域。

谷歌地图显然有这些数据(水体是蓝色的) - 但是 API 中有什么东西可以用来做这个吗?如果没有 - 他们不提供服务是因为他们从未想过吗?还是因为太复杂了?

我没有找到关于此事的任何信息 - 除了这里的一些类似问题(例如查找地形类​​型或海拔 - 但这并不完全是我需要的)。

有分离层吗?一个选项?命令?还是我应该手动执行此操作?

我能想到如何解决这个问题的唯一方法(我是否需要手动执行此操作)是检查每个提供的图块的确切点 - 然后检查该 Google 地图色调的 RGB 值。这只是理论上 - 因为在实践中 - 我不知道如何实现这一点,第一个障碍是我不知道如何将瓷砖上的像素位置转换为 [LatLon] 点

一个现成的解决方案会容易得多。

请注意,我不需要世界上所有的水(例如 - 我不关心溪流、小池塘、大多数河流或你邻居的游泳池。我需要一个人可以在没有漂浮车辆帮助的情况下冒险的点)

编辑我

看完评论:高程方法不靠谱,海平面以下的地方太多了(你可以在这里查看“最深”10的列表http://geology.com/below-sea-level/)和那里海平面以上的内陆水体(湖泊)太多。反向地理定位方法不可靠,因为它会多次返回地缘政治实体,如城市或州 - 或零。在问这个问题之前,我已经研究过那些伪解决方案——但他们都没有真正回答过这个问题——这些方法充其量只是糟糕的“猜测”。

6个回答

这是两种不同的方法,您可以尝试:

  • 您可以使用Google 地图反向地理编码在结果集中,您可以通过检查来确定是否是水types在水域情况下,类型是natural_feature在此链接http://code.google.com/apis/maps/documentation/geocoding/#Types 中查看更多信息

    您还需要检查要素的名称,如果它们包含Sea, Lake, Ocean与水域相关的其他一些词,以提高准确性。例如沙漠也是natural_features。

    优点- 所有检测过程都将在客户端的机器上完成。无需创建自己的服务器端服务。

    缺点- 非常不准确,您在水域中“没有”的可能性非常高。

  • 您可以使用Google 静态地图按像素检测水域/陆地但为此您需要创建 http 服务。

    这些是您的服务必须执行的步骤:

    1. 接收latitude,longitudecurrent zoom来自客户端。
    2. 向 Google 静态地图服务发送http://maps.googleapis.com/maps/api/staticmap?center={纬度,经度}&zoom={当前缩放`}&size=1x1&maptype=roadmap&sensor=false 请求。
    3. 检测 1x1 静态图像的像素颜色。
    4. 响应检测信息。

    您无法在客户端检测像素的颜色。是的,您可以在客户端机器上加载静态图像并在canvas元素上绘制图像但是您不能使用getImageData画布的上下文来获取像素的颜色。这是受跨域策略限制的。

    优点- 高度准确的检测

    缺点 - 使用自己的服务器资源进行检测

至于静态地图方法,您可以使用样式开发人员.google.com/maps/documentation/ static-maps/...但也可以使用 Saurav 链接的文章。
2021-03-13 21:17:54
以提议的方式使用静态地图可能会被视为违反条款(10.1.1(h))。
2021-03-18 21:17:54
谢谢 - 我已经检查过了 - 我不知道这些类型正在变成 Sea Lake Ocean 之类的,就像你在编辑中指出的那样 - natural_feature 也将是一座山、一座岛屿和一片沙漠......你能不能指向文档?还有 - 如何对没有地址的地方进行反向地理编码?那么作为地缘政治实体一部分的湖泊呢?就像城市或自治市范围内的湖泊(例如日内瓦),或者只是城市港口内的一个点。在我的试验中,我没有这样做。
2021-03-31 21:17:54
@Tomas - 不是说我想对其他“堆叠者”不屑一顾或不尊重 - 但也许它没有被投票,因为它不是有效/准确的方法?
2021-04-02 21:17:54
对于世界上大部分水域,反向地理编码将返回“零结果”,请查看地理编码工具:gmaps-samples-v3.googlecode.com/svn/trunk/geocoder/...并单击海洋中的某处。
2021-04-07 21:17:54

任何当前的 Google 服务似乎都不可能。

但是还有其他服务,例如Koordinates Vector JSON Query 服务您只需查询 URL 中的数据,即可返回 JSON/XML 响应

示例请求:http : //api.koordinates.com/api/vectorQuery.json?key=YOUR_GEODATA_KEY&layer=1298&x=-159.9609375&y=13.239945499286312&max_results=3&radius=10000&geometry=names&with_field

您必须注册并提供您的密钥和选定的层号。您可以搜索所有可用层存储库大多数图层只是区域性的,但您也可以找到全球性的,例如World Coastline

在此处输入图片说明

当您选择一个层时,您单击“服务”选项卡,您将获得示例请求 URL。我相信您只需要注册就可以了!

现在最好的:

您可以上传您的图层!

它不是立即可用的,嘿必须以某种方式处理它,但它应该可以工作!层存储库实际上看起来像人们根据需要上传它们。

嘿,你为我节省了一周的自定义编码!这很值得!
2021-03-15 21:17:54
嘿,托马斯,我不知道你是否真的得到了赏金(因为我离线了一个星期)但这太棒了!感谢您的帮助,我将无法使我的应用程序工作。谢谢!(如果你没有得到赏金,我会重新奖励,只是 PM 我)
2021-03-18 21:17:54
这看起来几乎完美,但是我没有看到任何不是大洋洲的本地地图。有美国层吗?
2021-03-28 21:17:54
@HaloWebMaster 我提到的层是全局的。您还可以按地区搜索图层。
2021-04-03 21:17:54
@HaloWebMaster 我刚刚注意到您可以上传自己的图层!看我的更新。
2021-04-06 21:17:54

有一个免费的 Web API 可以解决这个问题,叫做onwater.io它不是谷歌地图内置的东西,但给定纬度和经度,它会通过 get 请求准确地返回 true 或 false。

水示例:https : //api.onwater.io/api/v1/results/23.92323,-66.3

{
  lat: 23.92323,
  lon: -66.3,
  water: true
}

陆地示例:https : //api.onwater.io/api/v1/results/42.35,-71.1

{
  lat: 42.35,
  lon: -71.1,
  water: false
}

完全披露我在Dockwa.com工作,该公司是 onwater 背后的公司。我们建在水上是为了自己解决这个问题并帮助社区。它是免费使用的(支付大量费用),我们想分享 :)

2021-03-20 21:17:54
它不再是免费的(对于更高的容量),但如果它可以完成工作,它仍然非常实惠!
2021-03-20 21:17:54
onwater.io 是否适用于湖泊和河流?如果是这样,我是否会得到类型的指示?
2021-03-20 21:17:54
文档页面给出了一个错误。我想检查是否有任何覆盖特定数据?我的意思是你覆盖哪些国家?
2021-03-22 21:17:54
大声笑根本与代码无关,但我想将我的全部道具扩展给你们来构建它。这是如此(双关语意)我完全无法想象将它变成 $/call 的想法是如何出现的。编辑:我认为dockwa.com 与容器有关。这些人实际上从事船舶业务。哈哈
2021-03-30 21:17:54

我认为在本地执行此查询更有趣,因此我可以更加自力更生:假设我想一次生成 25000 个随机陆地坐标,我宁愿避免调用可能昂贵的外部 API。这是我在 python 中使用TomSchober 提到python 示例的镜头。基本上,它会在包含所有陆地坐标预制 350MB 文件中查找坐标,如果坐标存在于其中,则将其打印出来。

import ogr
from IPython import embed
import sys

drv = ogr.GetDriverByName('ESRI Shapefile') #We will load a shape file
ds_in = drv.Open("land_polygons.shp")    #Get the contents of the shape file
lyr_in = ds_in.GetLayer(0)    #Get the shape file's first layer

#Put the title of the field you are interested in here
idx_reg = lyr_in.GetLayerDefn().GetFieldIndex("P_Loc_Nm")

#If the latitude/longitude we're going to use is not in the projection
#of the shapefile, then we will get erroneous results.
#The following assumes that the latitude longitude is in WGS84
#This is identified by the number "4236", as in "EPSG:4326"
#We will create a transformation between this and the shapefile's
#project, whatever it may be
geo_ref = lyr_in.GetSpatialRef()
point_ref=ogr.osr.SpatialReference()
point_ref.ImportFromEPSG(4326)
ctran=ogr.osr.CoordinateTransformation(point_ref,geo_ref)

def check(lon, lat):
    #Transform incoming longitude/latitude to the shapefile's projection
    [lon,lat,z]=ctran.TransformPoint(lon,lat)

    #Create a point
    pt = ogr.Geometry(ogr.wkbPoint)
    pt.SetPoint_2D(0, lon, lat)

    #Set up a spatial filter such that the only features we see when we
    #loop through "lyr_in" are those which overlap the point defined above
    lyr_in.SetSpatialFilter(pt)

    #Loop through the overlapped features and display the field of interest
    for feat_in in lyr_in:
        # success!
        print lon, lat

check(-95,47)

我尝试了十几个坐标,效果很好。“land_polygons.shp”文件可以在这里下载,是 OpenStreetMaps 的补充。(我自己使用了第一个 WGS84 下载链接,也许第二个也可以)

湖泊呢?它是否将湖泊上的点视为海洋或陆地?
2021-04-03 21:17:54
好问题!我在页面上查看了答案链接的 OpenStreetMaps 数据,它说土地文件的值基于标签natural=coastline快速使用谷歌搜索可以使用此页面,其中明确指出海岸线标签实际上不适用于其命名法中的湖泊。所以,我要说的是,没有,我的方法并不能确定湖泊水,因为我使用的数据集没有。但是你自己试试吧!
2021-04-06 21:17:54

这就是我使用的,而且效果还不错……如果您有更多的 CPU 可以通过添加像素来浪费,您可以改进测试。

function isItWatter($lat,$lng) {

    $GMAPStaticUrl = "https://maps.googleapis.com/maps/api/staticmap?center=".$lat.",".$lng."&size=40x40&maptype=roadmap&sensor=false&zoom=12&key=YOURAPIKEY";  
    //echo $GMAPStaticUrl;
    $chuid = curl_init();
    curl_setopt($chuid, CURLOPT_URL, $GMAPStaticUrl);   
    curl_setopt($chuid, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($chuid, CURLOPT_SSL_VERIFYPEER, FALSE);
    $data = trim(curl_exec($chuid));
    curl_close($chuid);
    $image = imagecreatefromstring($data);

    // this is for debug to print the image
    ob_start();
    imagepng($image);
    $contents =  ob_get_contents();
    ob_end_clean();
    echo "<img src='data:image/png;base64,".base64_encode($contents)."' />";

    // here is the test : I only test 3 pixels ( enough to avoid rivers ... )
    $hexaColor = imagecolorat($image,0,0);
    $color_tran = imagecolorsforindex($image, $hexaColor);

    $hexaColor2 = imagecolorat($image,0,1);
    $color_tran2 = imagecolorsforindex($image, $hexaColor2);

    $hexaColor3 = imagecolorat($image,0,2);
    $color_tran3 = imagecolorsforindex($image, $hexaColor3);

    $red = $color_tran['red'] + $color_tran2['red'] + $color_tran3['red'];
    $green = $color_tran['green'] + $color_tran2['green'] + $color_tran3['green'];
    $blue = $color_tran['blue'] + $color_tran2['blue'] + $color_tran3['blue'];

    imagedestroy($image);
    var_dump($red,$green,$blue);
    //int(492) int(570) int(660) 
    if($red == 492 && $green == 570 && $blue == 660)
        return 1;
    else
        return 0;
}
代码在新版本上不起作用。新版本应该是这样 if($red == 537 && $green == 627 && $blue == 765)
2021-03-27 21:17:54