Verify if a point is Land or Water in Google Maps

后端 未结 18 1677
不知归路
不知归路 2020-11-22 17:16

..and then Google-maps \"divide the waters from the waters\"

Well, not in the biblical sense but..

I would like to know what options I have in order to verif

相关标签:
18条回答
  • 2020-11-22 17:52

    As a complete novice to Python I couldn't get SylvainB's solution to work with the python script that checks if coordinates are on land. I managed to figure it out however, by downloading OSGeo4W (https://trac.osgeo.org/osgeo4w/) and then installed everything I needed pip, Ipython, and checked that all the imports specified were there. I saved the following code as a .py file.

    Code to check if coordinates are on land

    ###make sure you check these are there and working separately before using the .py file 
    
    import ogr
    from IPython import embed
    from osgeo import osr
    import osgeo
    
    import random
    #####generate a 1000 random coordinates
    ran1= [random.uniform(-180,180) for x in range(1,1001)]
    ran2= [random.uniform(-180,180) for x in range(1,1001)]
    
    
    drv = ogr.GetDriverByName('ESRI Shapefile') #We will load a shape file
    ds_in = drv.Open("D:\Downloads\land-polygons-complete-4326\land-polygons-complete-4326\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=osgeo.osr.SpatialReference()
    point_ref.ImportFromEPSG(4326)
    ctran=osgeo.osr.CoordinateTransformation(point_ref,geo_ref)
    ###check if the random coordinates are on land
    def check(runs):
        lon=ran1[runs]
        lat=ran2[runs]
        #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:
            return(lon, lat)
    
    ###give it a try
    result = [check(x) for x in range(1,11)] ###checks first 10 coordinates
    

    I tried to get it to work in R but I had a nightmare trying to get all the packages you need to install so stuck to python.

    0 讨论(0)
  • 2020-11-22 17:53

    Here is a simple solution

    Because Google does not provide reliable results with regards to coordinates that lay on either ocean or inland bodies of water you need to use another backup service, such as Yandex, to help provide that critical information when it is missing. You most likely would not want to use Yandex as your primary geocoder because Google is far superior in the reliability and completeness of the worlds data, however Yandex can be very useful for the purpose of retrieving data when it relates to coordinates over bodies of water, so use both.


    Yandex Documentation: https://api.yandex.com.tr/maps/doc/geocoder/desc/concepts/input_params.xml


    The steps to retrieve Ocean name:

    1.) Use Google first to reverse geocode the coordinate.

    2.) If Google returns zero results, it is 99% likely the coordinate lies over an ocean. Now make a secondary reverse geocoding request with the same coordinates to Yandex. Yandex will return a JSON response with for the exact coordinates, within this response will be two "key":"value" pairs of importance

    ["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"]
    
    and
    
    ["GeoObject"]["name"]
    

    Check the kind key, if it == "hydro" you know you are over a body of water, and because Google returned zero results it is 99.99% likely this body of water is an ocean. The name of the ocean will be the above "name" key.

    Here is an example of how I use this strategy written in Ruby

    if result.data["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"] == "hydro"
         ocean = result.data["GeoObject"]["name"] 
    end
    

    The steps to retrieve an Inland Body of Water name:

    For this example assume our coordinate lies in a lake somewhere:

    1.) Use Google first to reverse geocode the coordinate.

    2.) Google will most likely return a result that is a prominent default address on land nearby. In this result it supplies the coordinates of the address it returned, this coordinate will not match the one you provided. Measure the distance between the coordinate you supplied and the one returned with the result, if it is significantly different (for example 100 yards) then perform a secondary backup request with Yandex and check to see the value of the "kind" key, if it is "hydro" then you know the coordinate lies on water. Because Google returned a result as opposed to the example above, it is 99.99% likely this is an inland body of water so now you can get the name. If "kind" does not == "hydro" then use the Google geocoded object.

    ["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"]
    
    and
    
    ["GeoObject"]["name"]
    

    Here is the same code written in Ruby to get inland_body_of_water

    if result.data["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"] == "hydro"
         inland_body_of_water = result.data["GeoObject"]["name"] 
    end
    

    A note about Licensing: As far as I know Google does not allow you to use their data to display on any other maps other than those Google offers. Yandex however has very flexible licensing, and you can use their data to be displayed on Google maps.

    Also Yandex has a a high rate limit of 50,000 request / day free of charge, and with no required API key.

    0 讨论(0)
  • 2020-11-22 17:54

    There is a free web API that solves exactly this problem called onwater.io. It isn't something built into Google maps, but given a latitude and longitude it will accurately return true or false via a get request.

    Example on water: https://api.onwater.io/api/v1/results/23.92323,-66.3

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

    Example on land: https://api.onwater.io/api/v1/results/42.35,-71.1

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

    Full disclosure I work at Dockwa.com, the company behind onwater. We built onwater to solve this problem ourselves and help the community. It is free to use (paid for high volume) and we wanted to share :)

    0 讨论(0)
  • 2020-11-22 17:54

    I would recommend rolling your own here. You can use tools like GDAL to query the contents under a point in a shapefile. You can get shapefiles for US geography from many sources including the US Census Bureau.

    This can be done via GDAL binaries, the source C, or via swig in Java, Python, and more.

    Census Maps

    GDAL Information

    Point Query Example in Python

    0 讨论(0)
  • 2020-11-22 17:57

    Here's another example in pure JavaScript: http://jsfiddle.net/eUwMf/

    As you can see, the ideia is basically the same as rebe100x, getting the image from Google static map API, and read the first pixel:

    $("#xGps, #yGps").change(function() {
        var img = document.getElementById('mapImg');
    
        // Bypass the security issue : drawing a canvas from an external URL.
        img.crossOrigin='anonymous';
    
        var xGps = $("#xGps").val();
        var yGps = $("#yGps").val();
    
        var mapUrl = "http://maps.googleapis.com/maps/api/staticmap?center=" + xGps + "," + yGps +
            "&zoom=14&size=20x20&maptype=roadmap&sensor=false";
    
        // mapUrl += "&key=" + key;
    
        $(img).attr("src", mapUrl);
    
        var canvas = $('<canvas/>')[0];
        canvas.width = img.width;
        canvas.height = img.height;
        canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
    
        var pixelData = canvas.getContext('2d').getImageData(1, 1, 1, 1).data;
    
        if (pixelData[0] == 164 &&
            pixelData[1] == 190 &&
            pixelData[2] == 220) {
            $("#result").html("Water");
        } else {
            $("#result").html("Not water");
        }
    });
    
    0 讨论(0)
  • 2020-11-22 17:58

    It doesn't seem possible with any current Google service.

    But there are other services, like Koordinates Vector JSON Query service! You simply query the data in the URL, and you get back a JSON/XML response.

    Example request: 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=true&with_field_names=true

    You have to register and supply your key and selected layer number. You can search all their repository of available layers. Most of the layers are only regional, but you can find global also, like the World Coastline:

    enter image description here

    When you select a layer, you click on the "Services" tab, you get the example request URL. I believe you just need to register and that's it!

    And now the best:

    You can upload your layer!

    It is not available right away, hey have to process it somehow, but it should work! The layer repository actually looks like people uploaded them as they needed.

    0 讨论(0)
提交回复
热议问题