javascript cantidad - Verificar si un punto es tierra o agua en Google Maps




la mundo (15)

..y luego Google-maps "divide las aguas de las aguas"

Bueno, no en el sentido bíblico pero ...

Me gustaría saber qué opciones tengo para verificar si un punto de [Lat, Lon] es tierra o agua.

Google Maps obviamente tiene estos datos (los cuerpos de agua son azules), pero ¿hay algo en la API que pueda usar para eso? Y si no, ¿no lo están sirviendo porque nunca lo pensaron? ¿O porque es demasiado complicado?

No he encontrado ninguna información sobre el asunto, excepto algunas preguntas similares aquí (como encontrar el tipo de terreno o elevación) pero no es exactamente lo que necesito).

¿Hay una capa separada para eso? ¿Una opción? ¿Mando? ¿O debería ir a hacer eso manualmente?

La única forma en que puedo pensar en cómo abordar esto (si tengo que hacerlo manualmente) es verificar cada ficha servida para el punto exacto, y luego verificar el valor RGB para ese matiz del mapa de Google. Esto es solo por teoría, porque en la práctica, no tengo idea de cómo lograr eso, el primer obstáculo es que no sé cómo puedo convertir una ubicación de píxeles en un mosaico en un punto [LatLon], por ejemplo.

Una solución preparada sería mucho más fácil.

Tenga en cuenta que no necesito TODA el agua del mundo (por ejemplo, no me importan los arroyos, los estanques pequeños, la mayoría de los ríos o la piscina de su vecino. Necesito los puntos donde una persona puede aventurarse sin la ayuda de un vehículo flotante )

EDITAR I

Después de leer los comentarios: El método de elevación no es confiable, hay demasiados lugares ABAJO nivel del mar (puede ver una lista de los 10 más "profundos" aquí http://geology.com/below-sea-level/ ) y allí hay demasiados cuerpos de agua sin mar ABASTECES al nivel del mar (lagos). El método de geolocalización inversa no es confiable porque devolverá una entidad geopolítica, como ciudad o estado, o CERO muchas veces. Ya examiné esas pseudo soluciones antes de hacer la pregunta, pero ninguna de ellas respondió la pregunta; esos métodos son malos para "adivinar" en el mejor de los casos.


Answers

Además de la geocodificación inversa, como ha señalado el Dr.Molle , puede devolver ZERO_RESULTS, puede usar el servicio Elevation. Si obtiene cero resultados por geocodificación inversa, obtenga la elevación de la ubicación. En general, el mar obtiene un número negativo ya que el fondo está por debajo del nivel del mar. Hay un ejemplo completo del servicio de elevación en http://www.daftlogic.com/sandbox-google-maps-find-altitude.htm .

Tenga en cuenta que, como Google no pone a disposición esta información, cualquier otro método es solo una suposición y las suposiciones son inherentemente inexactas. Sin embargo, usar el type devuelto por geocodificación inversa, o la elevación si el type no está disponible, cubrirá la mayoría de las eventualidades.


Lamentablemente, esta respuesta no está dentro de la API de Google Maps y el recurso al que se hace referencia no es gratuito, pero hay un servicio web proporcionado por DynamicGeometry que expone una operación GetWaterOrLand que acepta un par de latitud / longitud (aquí puede ver una demostración ).

Mi comprensión de cómo esto se implementa es mediante el uso de archivos de forma de cuerpo de agua. Cómo se usan exactamente estos archivos de formas con la API de Google Maps, pero es posible que pueda obtener alguna información de la demostración vinculada.

Espero que eso ayude de algún modo.


Si todo lo demás falla, siempre puedes intentar verificar la elevación en el punto y por un poco de distancia, no muchas otras cosas aparte del agua tienden a ser completamente planas.


Esto es lo que uso y no está funcionando mal ... puedes mejorar la prueba si tienes más CPU que perder agregando píxeles.

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

Este método es totalmente no confiable. De hecho, los datos devueltos dependerán totalmente de la parte del mundo con la que esté trabajando. Por ejemplo, estoy trabajando en Francia. Si hago clic en el mar en la costa de Francia, Google devolverá la ubicación LAND más cercana que pueda "adivinar". Cuando solicité información de Google para esta misma pregunta, respondieron que no pueden devolver con precisión el punto solicitado en una masa de agua.

No es una respuesta muy satisfactoria, lo sé. Esto es bastante frustrante, especialmente para aquellos de nosotros que brindamos al usuario la capacidad de hacer clic en el mapa para definir una posición de marcador.


Pensé que era más interesante hacer esta consulta localmente, así que puedo ser más autosuficiente: digamos que quiero generar 25000 coordenadas de terreno aleatorias a la vez, prefiero evitar llamadas a API externas posiblemente costosas. Aquí está mi oportunidad de esto en Python, usando el ejemplo de pitón mencionado por TomSchober. Básicamente busca las coordenadas en un archivo de 350MB prefabricado que contiene todas las coordenadas del terreno, y si las coordenadas existen allí, las imprime.

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)

Probé una docena de coordenadas, funciona maravillosamente. El archivo "land_polygons.shp" se puede descargar aquí , cortesía de OpenStreetMaps. (Utilicé el primer enlace de descarga WGS84, tal vez el segundo funciona también)


Aquí hay una solución simple

Debido a que Google no proporciona resultados confiables con respecto a las coordenadas que se encuentran en el océano o cuerpos de agua continentales, necesita usar otro servicio de respaldo, como Yandex, para ayudar a proporcionar esa información crítica cuando falta. Lo más probable es que no desee utilizar Yandex como su principal geocodificador porque Google es muy superior en la fiabilidad y completitud de los datos del mundo, sin embargo, Yandex puede ser muy útil para recuperar datos cuando se trata de coordenadas sobre masas de agua, entonces usa ambos.

Documentación de Yandex: https://api.yandex.com.tr/maps/doc/geocoder/desc/concepts/input_params.xml

Los pasos para recuperar Ocean name:

1.) Use Google primero para revertir el geocodificación de la coordenada.

2.) Si Google devuelve cero resultados, es 99% probable que la coordenada se encuentre sobre un océano. Ahora haga una solicitud secundaria de geocodificación inversa con las mismas coordenadas a Yandex. Yandex devolverá una respuesta JSON con las coordenadas exactas, dentro de esta respuesta habrá dos pares de "clave": "valor" de importancia

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

and

["GeoObject"]["name"]

Compruebe la clave de tipo, si == "hidro" sabe que está sobre un cuerpo de agua, y como Google arrojó cero resultados, es 99.99% probable que este cuerpo de agua sea un océano. El nombre del océano será la clave de "nombre" anterior.

Aquí hay un ejemplo de cómo uso esta estrategia escrita en Ruby

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

Los pasos para recuperar un nombre de Cuerpo de agua interior:

Para este ejemplo, supongamos que nuestra coordenada se encuentra en un lago en alguna parte:

1.) Use Google primero para revertir el geocodificación de la coordenada.

2.) Google probablemente devolverá un resultado que es una dirección predeterminada prominente en un terreno cercano. En este resultado, proporciona las coordenadas de la dirección que devolvió, esta coordenada no coincidirá con la que proporcionó. Mida la distancia entre la coordenada que suministró y la que arrojó con el resultado, si es significativamente diferente (por ejemplo, 100 yardas) luego realice una solicitud de respaldo secundaria con Yandex y verifique el valor de la tecla "amable", si es "hidro", entonces sabes que la coordenada se encuentra en el agua. Debido a que Google arrojó un resultado en comparación con el ejemplo anterior, es 99.99% probable que se trate de un cuerpo de agua interior, por lo que ahora puede obtener el nombre. Si "kind" no == "hydro" usa el objeto Google geocoded.

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

and

["GeoObject"]["name"]

Aquí está el mismo código escrito en Ruby para obtener inland_body_of_water

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

Una nota sobre Licencias: por lo que sé, Google no le permite usar sus datos para mostrar en otros mapas que no sean las ofertas de Google. Yandex, sin embargo, tiene licencias muy flexibles, y puede usar sus datos para mostrarlos en Google Maps.

Además, Yandex tiene un límite de tarifa alta de 50,000 solicitudes / día sin cargo y sin la clave API requerida.


Tengo una solución diferente aquí. En la implementación actual del mapa de Google, no calcula la dirección / distancia desde una ubicación de agua hasta la ubicación de la tierra y viceversa. ¿Por qué no usamos esta lógica para determinar si el punto es tierra o agua?

Por ejemplo, tomemos este ejemplo

si queremos determinar, si un punto x es tierra o agua, entonces

veamos la dirección entre el punto x un punto conocido y que es tierra. Si determina la dirección / distancia, entonces el punto x es tierra o bien es agua.


Estas son 2 formas diferentes, puede intentar:

  • Puede usar la geocodificación inversa de Google Maps . En el conjunto de resultados, puede determinar si es agua al verificar los types . En el caso de las aguas, el tipo es natural_feature . Consulte más en este enlace http://code.google.com/apis/maps/documentation/geocoding/#Types .

    También necesita verificar los nombres de las características, si contienen Sea, Lake, Ocean y algunas otras palabras relacionadas con las aguas para una mayor precisión. Por ejemplo, los desiertos también son de natural_feature .

    Prons : todo el proceso de detección se realizará en la máquina del cliente. No es necesario crear un servicio propio del lado del servidor.

    Contras : muy impreciso y las posibilidades de que obtengas "ninguno" en las aguas son muy altas.

  • Puedes detectar las aguas / tierras por píxeles, usando Google Static Maps . Pero para este propósito, necesitas crear un servicio http.

    Estos son los pasos que su servicio debe realizar:

    1. Recibe latitude , longitude y current zoom del cliente.
    2. Envíe http://maps.googleapis.com/maps/api/staticmap?center={ latitude , longitude }&zoom={ current zoom`} & size = 1x1 & maptype = roadmap & sensor = solicitud falsa al servicio de Google Static Map.
    3. Detecta el color del píxel de la imagen estática de 1x1.
    4. Responda una información sobre la detección.

    No puede detectar el color del píxel en el lado del cliente. Sí, puede cargar imágenes estáticas en la máquina del cliente y dibujar imágenes en elementos de canvas . Pero no puede usar getImageData del contexto de canvas para obtener el color del píxel. Esto está restringido por la política de dominio cruzado.

    Prons : detección de alta precisión

    Contras : uso de recursos de servidor propios para la detección



Hay una API web gratuita que resuelve exactamente este problema llamado onwater.io . No es algo integrado en los mapas de Google, pero dada la latitud y la longitud, devolverá verdadero o falso con una solicitud de obtención.

Ejemplo de agua: https://api.onwater.io/23.92323,-66.3

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

Ejemplo en tierra: https://api.onwater.io/42.35,-71.1

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

Divulgación completa Trabajo en Dockwa.com , la compañía detrás de onwater. Construimos en el agua para resolver este problema y ayudar a la comunidad. Siempre es gratis y queríamos compartir :)


Si la dirección de la List<Address> devuelve 0, puede asumir esta ubicación como océano o recursos naturales. Simplemente agregue debajo del código en su método de respuesta de la respuesta de la API de Google Places.

Inicializar debajo de la lista como se menciona

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{ }




Acabo de intentar esto con kmlLayer.setMap (nulo) y funcionó. No estoy seguro de si eso funcionaría con marcadores regulares pero parece funcionar correctamente.







javascript google-maps google-maps-api-3