javascript - que - porcentaje de agua potable en la tierra
Verificar si un punto es tierra o agua en Google Maps (17)
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.
..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.
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.
Aquí hay otro ejemplo en JavaScript puro: http://jsfiddle.net/eUwMf/
Como puede ver, la ideia es básicamente la misma que rebe100x, obteniendo la imagen de la API del mapa estático de Google y leyendo el primer píxel:
$("#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");
}
});
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 esnatural_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 denatural_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:
- Recibe
latitude
,longitude
ycurrent zoom
del cliente. - 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. - Detecta el color del píxel de la imagen estática de 1x1.
- 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 usargetImageData
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
- Recibe
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.
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;
}
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 :)
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.
Me las arreglé para acercarme bastante usando la API Google Elevation. Aquí hay una imagen de los resultados:
Usted ve que los hexágonos se quedan prácticamente en tierra a pesar de que se define un perímetro rectangular que va parcialmente sobre el agua. En este caso, hice una comprobación rápida de Google Maps y la elevación mínima en tierra fue de aproximadamente 8-9 m, por lo que ese era mi umbral. El código es principalmente copiado / pegado de la documentación de Google y , aquí está la esencia completa:
No parece posible con ningún servicio actual de Google.
¡Pero hay otros servicios, como el servicio de consultas JSON de Koordinates Vector ! Simplemente consulta los datos en la URL y obtiene una respuesta JSON / XML .
Solicitud de ejemplo: 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
Debe registrarse y proporcionar su clave y el número de capa seleccionado. Puede buscar en todo su repositorio de capas disponibles . La mayoría de las capas son solo regionales, pero también puedes encontrar global, como la línea costera mundial :
Cuando seleccionas una capa, haces clic en la pestaña "Servicios", obtienes la URL de solicitud de ejemplo. ¡Creo que solo necesitas registrarte y listo!
Y ahora lo mejor:
¡Puedes subir tu capa!
No está disponible de inmediato, ¡tiene que procesarlo de alguna manera, pero debería funcionar! El repositorio de capas realmente parece que las personas lo cargaron cuando lo necesitaron.
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)
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{ }
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.
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.
Verifique este artículo. Detecta con precisión si hay algo en el agua sin necesidad de un servidor. Es un truco que se basa en la función de diseño personalizado en Google Maps.
http://tech.bellycard.com/blog/where-d-the-water-go-google-maps-water-pixel-detection-with-canvas/
Yo recomendaría rodar el tuyo aquí. Puede usar herramientas como GDAL para consultar los contenidos bajo un punto en un shapefile. Puede obtener shapefiles para la geografía de los EE . UU . De muchas fuentes, incluida la Oficina del Censo de EE . UU .
Esto se puede hacer a través de binarios GDAL, la fuente C, o vía swig en Java, Python y más.
Vea la respuesta que di a una pregunta similar : usa "HIT_TEST_TERRAIN" de Earth Api para lograr la función.
Hay un ejemplo de trabajo de la idea que reuní aquí: http://www.msa.mmu.ac.uk/~fraser/ge/coord/