it-swarm.com.ru

Проверьте, является ли точка Землей или Водой в Картах Google

..и тогда гугл-карты "делят воду от воды"

Ну, не в библейском смысле, но ..

Я хотел бы знать, какие у меня есть варианты, чтобы проверить, является ли точка [Lat, Lon] Землей или Водой.

Google Maps, очевидно, имеет эти данные (водоемы синие) - но есть ли в API что-то, что я могу использовать для этого? А если нет - разве они не служат ему, потому что никогда не думали об этом? Или потому что это слишком сложно?

Я не нашел никакой информации по этому вопросу - за исключением некоторых подобных вопросов здесь (например, поиск типа местности или возвышения - но это не совсем то, что мне нужно).

Есть ли отдельный слой для этого? Опция? Команда? Или я должен пойти сделать это вручную?

Единственный способ, которым я могу придумать, как подойти к этому (должен ли я сделать это вручную), это проверить каждую обслуживаемую плитку на предмет точной точки, а затем проверить значение RGB для этого оттенка карты Google. Это только по теории - потому что на практике - я понятия не имею, как этого добиться, первое препятствие, которое я не знаю, как я могу преобразовать местоположение пикселя на плитке в точку [LatLon], например

Готовое решение будет намного проще.

Обратите внимание, что мне не нужна ВСЕ вода в мире (например, мне нет дела до ручьев, небольших прудов, большинства рек или бассейна вашего соседа. Мне нужны точки, где человек может рисковать без помощи плавучего транспортного средства. )

РЕДАКТИРОВАТЬ I

После прочтения комментариев: метод повышения не является надежным, слишком много мест ниже уровня моря (вы можете увидеть список "самых глубоких" 10 здесь http://geology.com/below-sea-level / ) и слишком много не имеющих выхода к морю водоемов НАД уровня моря (озер). Метод обратной геолокации ненадежен, потому что он будет возвращать геополитическую единицу, такую ​​как город, или штат, или НОЛЬ много раз. Я уже изучил эти псевдо-решения, прежде чем задавать вопрос - но на самом деле никто из них не ответил на этот вопрос - эти методы в лучшем случае плохо "угадывают".

98
Obmerk Kronen

Это 2 разных способа, вы можете попробовать:

  • Вы можете использовать Google Maps Reverse Geocoding . В наборе результатов вы можете определить, является ли это водой, проверив types. В случае воды тип natural_feature. Подробнее читайте по этой ссылке http://code.google.com/apis/maps/documentation/geocoding/#Types .

    Также вам нужно проверить названия объектов, если они содержат Sea, Lake, Ocean и некоторые другие слова, связанные с водами, для большей точности. Например, пустыни также являются natural_features.

    Prons - Весь процесс обнаружения будет выполняться на компьютере клиента. Нет необходимости создавать собственную службу на стороне сервера.

    Минусы - Очень неточно, и шансы, что вы получите "ничего" в водах, очень высоки.

  • Вы можете обнаружить воды/земли по пикселям, используя Google Static Maps . Но для этого вам нужно создать http сервис.

    Вот шаги, которые должен выполнить ваш сервис:

    1. Получите latitude, longitude и current zoom от клиента.
    2. Отправьте http://maps.googleapis.com/maps/api/staticmap?center={latitude,longitude}&zoom={current zoom`} & size = 1x1 & maptype = roadmap & sensor = false в сервис Google Static Map.
    3. Определить цвет пикселя статического изображения 1x1.
    4. Ответьте информацию об обнаружении.

    Вы не можете обнаружить цвет пикселя на стороне клиента. Да, вы можете загрузить статическое изображение на компьютер клиента и нарисовать изображение на элементе canvas. Но вы не можете использовать getImageData контекста canvas для получения цвета пикселя. Это ограничено междоменной политикой.

    Prons - Высокая точность обнаружения

    Минусы - Использование собственных ресурсов сервера для обнаружения

54
Engineer

Это кажется невозможным с любой текущей службой Google.

Но есть и другие сервисы, например Служба запросов JSON векторов координат! Вы просто запрашиваете данные в 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=true&with_field_names=t==

Вы должны зарегистрироваться и предоставить свой ключ и выбранный номер слоя. Вы можете искать все их хранилище доступных слоев . Большинство слоев являются только региональными, но вы также можете найти глобальные, такие как World Coastline :

enter image description here

Когда вы выбираете слой, вы нажимаете на вкладку "Услуги", вы получаете пример запроса URL. Я считаю, что вам просто нужно зарегистрироваться и все!

А теперь самое лучшее:

Вы можете загрузить свой слой!

Это не доступно сразу, эй, надо как-то обработать, но оно должно работать! Хранилище слоев на самом деле выглядит так, как будто люди загружали их так, как им нужно.

19
TMS

Это то, что я использую, и это работает не так уж плохо ... вы можете улучшить тест, если у вас есть больше процессорного времени, добавляя пиксели.

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;
}
8
rebe100x

Оформить заказ этой статьи. Он точно определяет, находится ли что-то на воде, без необходимости использования сервера. Это взлом, который опирается на функцию пользовательского стиля в Картах Google.

http://tech.bellycard.com/blog/where-d-the-water-go-google-maps-water-pixel-detection-with-canvas/

7
Saurav

Я подумал, что было бы интереснее делать этот запрос локально, поэтому я могу быть более самостоятельным: скажем, я хочу генерировать 25000 случайных координат земли одновременно, я бы предпочел избегать вызовов, возможно, дорогостоящих внешних API. Вот мой взгляд на это в python, используя пример python , упомянутый TomSchober. По сути, он ищет координаты в готовый файл размером 350 МБ , содержащий все наземные координаты, и, если эти координаты существуют, он печатает их.

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, может быть, вторая тоже работает)

7
SylvainB

Существует бесплатный веб-API, который решает именно эту проблему и называется onwater.io . Это не что-то встроенное в карты Google, но с учетом широты и долготы оно точно вернет истину или ложь через запрос на получение.

Пример по воде: https://api.onwater.io/api/v1/results/23.92323,-66.

{
  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. Мы построили на воде, чтобы решить эту проблему сами и помочь сообществу. Это бесплатно для использования (платят за большой объем), и мы хотели бы поделиться :)

6
stuyam

В дополнение к обратному геокодированию - как указал Dr Molle , он может возвращать ZERO_RESULTS - вы можете использовать службу Elevation. Если вы получите нулевой результат путем обратного геокодирования, получите высоту местоположения. Обычно море получает отрицательное число, поскольку морское дно находится ниже уровня моря. Полностью обработанный пример службы повышения прав можно получить по адресу http://www.daftlogic.com/sandbox-google-maps-find-altitude.htm .

Имейте в виду, что, поскольку Google не предоставляет эту информацию, любой другой метод является лишь предположением, а догадки по своей сути неточны. Однако использование type, возвращенного обратным геокодированием, или повышение, если type недоступно, охватит большинство возможных ситуаций.

5
Andrew Leach

Если ничего не помогает, вы всегда можете попробовать проверить высоту в точке и на некотором расстоянии - не так много вещей, кроме воды, как правило, совершенно плоские.

3
Steve Barnes

Этот метод абсолютно ненадежен. Фактически, возвращаемые данные будут полностью зависеть от того, с какой частью мира вы работаете. Например, я работаю во Франции. Если я нажму на море на побережье Франции, Google вернет ближайшее местоположение LAND, в котором оно может "угадать". Когда я запросил информацию у Google по этому же вопросу, они ответили, что не могут точно вернуть ту точку, которая была запрошена для водной массы.

Не очень удовлетворительный ответ, я знаю. Это довольно неприятно, особенно для тех из нас, кто предоставляет пользователю возможность нажимать на карту, чтобы определить положение маркера.

3
Simon

см. Ответ, который я дал на аналогичный вопрос - он использует "HIT_TEST_TERRAIN" из API Земли для достижения этой функции.

Вот рабочий пример идеи, которую я собрал здесь: http://www.msa.mmu.ac.uk/~fraser/ge/coord/

2
Fraser

К сожалению, этот ответ не входит в Google Maps API, и указанный ресурс не является бесплатным, но есть веб-сервис, предоставляемый DynamicGeometry, который предоставляет операцию GetWaterOrLand, которая принимает пару широта/долгота ( вы можете увидеть демонстрацию здесь ).

Мое понимание того, как это реализовано, заключается в использовании файлов формы водоема. Как именно эти файлы форм используются с API Карт Google, но вы можете получить некоторое представление о связанной демонстрации.

Надеюсь, это поможет каким-то образом.

2
sellmeadog

Мне удалось подойти довольно близко с помощью Google Elevation API. Вот изображение результатов:

screenshot of results

Вы видите, что шестиугольники в значительной степени остаются на земле, хотя определен прямоугольный периметр, который частично проходит над водой. В этом случае я сделал быструю проверку из Google Maps, и минимальная высота над уровнем моря была около 8-9 м, так что это был мой порог. Код в основном копируется/вставляется из документации Google и Stack Overflow, вот полный Gist:

https://Gist.github.com/dvas0004/fd541a0502528ebfb825

2
dvas0004

Я бы порекомендовал прокатить свой здесь. Вы можете использовать такие инструменты, как GDAL , чтобы запросить содержимое под точкой в ​​шейп-файле. Вы можете получить шейп-файлы для географии США из многих источников, включая Бюро переписей США .

Это можно сделать через двоичные файлы GDAL, исходный код C или через swig в Java, Python и т.д.

Карты переписи

Информация GDAL

Пример запроса точки в Python

2
TomSchober

Вот еще один пример в чистом JavaScript: http://jsfiddle.net/eUwMf/

Как вы можете видеть, идея в основном совпадает с rebe100x, получая изображение из API статической карты Google и читая первый пиксель:

$("#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");
    }
});
2
IcanDivideBy0

Если адрес List<Address> возвращает 0, вы можете принять это местоположение как океан или Природные ресурсы. Просто добавьте ниже код в свой метод ответа Google Places API Response.

Инициализировать список ниже, как упоминалось

List<Address> addresses = geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1);

if (addresses.size()==0) { Toast.MakeText(getApplicationContext,"Ocean or Natural Resources selected",Toast.LENGTH_SHORT).show(); }else{ }

1
Kumar PG

Вот простое решение

Поскольку Google не предоставляет надежных результатов в отношении координат, которые лежат на океанских или внутренних водоемах, вам необходимо использовать другую службу резервного копирования, например Яндекс, чтобы предоставить эту важную информацию, когда она отсутствует. Скорее всего, вы не захотите использовать Яндекс в качестве основного геокодера, поскольку Google значительно превосходит по надежности и полноте данных о мире, однако Яндекс может быть очень полезен для получения данных, когда они связаны с координатами над водоемами, так что используйте оба.


Документация Яндекса: https://api.yandex.com.tr/maps/doc/geocoder/desc/concepts/input_params.xml


Шаги, чтобы получить имя океана:

1.) Сначала воспользуйтесь Google, чтобы изменить геокодирование координат.

2.) Если Google возвращает ноль результатов, вероятность того, что координата лежит над океаном, составляет 99%. Теперь сделайте вторичный обратный запрос геокодирования с теми же координатами к яндексу. Яндекс вернет ответ JSON с точными координатами, в этом ответе будут две важные пары "ключ": "значение"

["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"]

and

["GeoObject"]["name"]

Проверьте добрый ключ, если он == "гидро", вы знаете, что находитесь над водоемом, и, поскольку Google вернул нулевые результаты, вероятность того, что этот водоем является океаном, составляет 99,99%. Название океана будет указанным выше ключом "имя".

Вот пример того, как я использую эту стратегию, написанную на Ruby

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

Шаги, чтобы получить имя Внутреннего водного пространства:

Для этого примера предположим, что наша координата лежит где-то в озере:

1.) Сначала воспользуйтесь Google, чтобы изменить геокодирование координат.

2.) Google, скорее всего, вернет результат, который является известным адресом по умолчанию на соседней земле. В результате он предоставляет координаты адреса, который он возвратил, эта координата не будет соответствовать той, которую вы указали. Измерьте расстояние между введенной вами координатой и координатой, возвращенной с результатом, если оно существенно отличается (например, 100 ярдов), затем выполните дополнительный запрос резервного копирования с помощью Яндекса и проверьте, чтобы увидеть значение ключа "kind", если оно является "гидро", то вы знаете, координата лежит на воде. Поскольку Google возвратил результат, в отличие от приведенного выше примера, вероятность того, что это внутренний водоем, составляет 99,99%, теперь вы можете получить название. Если "kind" не == "hydro", используйте геокодированный объект Google.

["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"]

and

["GeoObject"]["name"]

Вот тот же код, написанный на Ruby для получения inland_body_of_water

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

Примечание о лицензировании. Насколько я знаю, Google не позволяет вам использовать их данные для отображения на любых других картах, кроме тех, которые предлагает Google. У Яндекса, однако, очень гибкое лицензирование, и вы можете использовать их данные для отображения на картах Google.

Также у Яндекса есть высокий лимит скорости 50 000 запросов/день бесплатно и без обязательного ключа API.

1
heading_to_tahiti

Как полный новичок в Python, я не мог заставить решение SylvainB работать со сценарием python, который проверяет, находятся ли координаты на земле. Мне удалось выяснить это, однако, загрузив OSGeo4W ( https://trac.osgeo.org/osgeo4w/ ), а затем установил все, что мне было нужно, pip, Ipython и проверил, что все указанные импорты были там. Я сохранил следующий код в виде файла .py.

Код для проверки координат на земле

###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

Я пытался заставить его работать в R, но мне приснился кошмар, пытающийся получить все пакеты, которые нужно установить, так что он застрял на python.

0
Alec Christie