2009-07-03 10 views
14

tengo el creado la tabla de abajover si las caídas de latitud/longitud dentro de un polígono usando MySQL

CREATE TABLE geom (g GEOMETRY); 

y se han insertado muchas filas, el ejemplo a continuación:

INSERT INTO geom (g) 
VALUES(PolygonFromText('POLYGON((
9.190586853 45.464518970, 
9.190602686 45.463993916, 
9.191572471 45.464001929, 
9.191613325 45.463884676, 
9.192136130 45.463880767, 
9.192111509 45.464095594, 
9.192427961 45.464117804, 
9.192417811 45.464112862, 
9.192509035 45.464225851, 
9.192493139 45.464371079, 
9.192448471 45.464439002, 
9.192387444 45.464477861, 
9.192051402 45.464483037, 
9.192012814 45.464643592, 
9.191640825 45.464647090, 
9.191622331 45.464506215, 
9.190586853 45.464518970))') 
); 

Ahora quiero para buscar todas las los datos y devuelven las entradas donde una latitud/longitud I cae dentro de cualquiera de los polígonos.

¿Cómo se puede hacer esto usando mysql? ¿o alguien está al tanto de algún enlace que me señale en la dirección correcta?

Respuesta

17

MySQL a partir de v5.1 solo admite operaciones en el minimum bounding rectangles (MBR). Si bien existe una "Contains" función que haría lo que necesita, no se aplique plenamente y cae de nuevo a usar MBRContains

Desde el relevant manual page

Actualmente, MySQL no implementa estas funciones según la especificación . Los que están implementados en devuelven el mismo resultado que las funciones correspondientes basadas en MBR. Esto incluye funciones en la siguiente lista que no sea Distancia() y Related().

Estas funciones pueden ser implementadas en futuras versiones con soporte completo para análisis espacial, no sólo MBR-basada apoyo.

Lo que podría hacer es dejar que MySQL le proporcione un resultado aproximado basado en el MBR, y luego procesarlo para realizar una prueba más precisa. Alternativamente, cambie a PostGIS!

(Actualización mayo 2012 - gracias Mike Toews)

MySQL 5.6.1+ ofrece functions which use object shapes en lugar de MBR

MySQL implementó originalmente estas funciones tales que utilizaron rectángulos delimitadores objeto y devueltos el mismo resultado que las funciones basadas en MBR correspondientes. A partir de MySQL 5.6.1, las versiones correspondientes están disponibles que usan formas de objeto precisas. Estas versiones se nombran con un prefijo ST_. Por ejemplo, Contains() usa el objeto rectángulos delimitadores, mientras que ST_Contains() usa formas de objetos.

+2

La buena noticia es que [hay toda una serie de funciones con el prefijo 'ST_' para v5.6] (http://dev.mysql.com/doc/refman /5.6/en/functions-for-testing-spatial-relations-between-geometric-objects.html#function_st-contains) que hacen su correcta implementación, similar a PostGIS. –

6

Si no puede cambiar DBS a uno que tiene operadores espaciales correctamente implementados como extensión PostGIS de PostgreSQL http://postgis.refractions.net/, puede resolver este problema utilizando un enfoque de dos partes.

Primero deje que MySQL le proporcione un resultado de prefiltrado de cuadro delimitador basado en el cuadro delimitador (esto es lo que hace de forma predeterminada) utilizando su operador intersects (http://dev.mysql.com/doc/refman/5.1/en/functions-that-test-spatial-relationships-between-geometries.html#function_intersects). Si las consultas son lentas, primero asegúrese de tener un índice en su campo de geometría.

Entonces hidratar la geometría original que utilizó en su consulta en un objeto de geometría de la biblioteca de la geometría SIG como GEOS (http://trac.osgeo.org/geos/) (basado en C++, aunque también tiene enlaces para diferentes lenguajes como Python), bien proporcionado (http://trac.gispython.org/lab/wiki/Shapely), OGR (o el Java topología suite (JTS) http://www.vividsolutions.com/jts/jtshome.htm).

prueba cada una de las geometrías que regrese de su resultado de la consulta utilizando el operador apropiado como dentro o intersecta. Cualquiera de estas bibliotecas le dará un valor lógico resultado.

Personalmente, me gustaría ver las muestras para OGR ya que tiene una gran comunidad que está lista para ayudar.

Oh sí, y lo siento por poner los enlaces así ... supongo que ya estoy "nueva" Sólo puedo publicar un enlace (?)

1

La función dada en this post en los foros de MySQL funciona perfectamente para mi.

No es muy rápido y debe asegurarse de que el parámetro 'mp' sea del mismo tipo que la columna espacial que está usando (utilicé ogr2ogr para importar un shapefile de Ordnance Survey a MySQL, así que tuve que cambiarlo de 'MULTIPOLYGON 'a' GEOMETRÍA ')

+0

Solo para agregar, aumenté la velocidad de consulta en un orden de magnitud ejecutando el archivo de forma original a través de http://mapshaper.com/test/demo.html - Dios bendiga a Douglas-Peucker ... –

+0

@all para aquellos que están utilizando la versión de mysql por debajo de 5.6 esto debería ayudar –

0

He reescrito function que se proporcionó en la publicación anterior por @danherd, por lo que puede funcionar con multipolígonos reales que consisten en más de un polígono. Para aquellos de ustedes que siguen usando la versión anterior de MySql, deberían ayudar.

Aquí está:

DELIMITER // 

CREATE FUNCTION GISWithin(pt POINT, mp MULTIPOLYGON) RETURNS INT(1) DETERMINISTIC 

BEGIN 

DECLARE str_big, str, xy LONGTEXT; 
DECLARE x, y, p1x, p1y, p2x, p2y, m, xinters DECIMAL(16, 13) DEFAULT 0; 
DECLARE counter INT DEFAULT 0; 
DECLARE p, pb, pe, sb, se, ct DECIMAL(16, 0) DEFAULT 0; 

SELECT MBRWithin(pt, mp) INTO p; 
IF p != 1 OR ISNULL(p) THEN 
return p; 
END IF; 

SELECT X(pt), Y(pt), ASTEXT(mp) INTO x, y, str_big; 
SET str_big = REPLACE(str_big, 'MULTIPOLYGON(((',''); 
SET str_big = REPLACE(str_big, ')))', ''); 
SET str_big = REPLACE(str_big, ')),((', '|'); 
SET str_big = CONCAT(str_big, '|'); 

SET sb = 1; 
SET se = LOCATE('|', str_big); 
SET str = SUBSTRING(str_big, sb, se - sb); 

WHILE se > 0 DO 
SET ct = ct + 1; 
SET str = SUBSTRING(str_big, sb, se - sb); 

SET pb = 1; 
SET pe = LOCATE(',', str); 
SET xy = SUBSTRING(str, pb, pe - pb); 
SET p = INSTR(xy, ' '); 
SET p1x = SUBSTRING(xy, 1, p - 1); 
SET p1y = SUBSTRING(xy, p + 1); 
SET str = CONCAT(str, xy, ','); 

WHILE pe > 0 DO 
SET xy = SUBSTRING(str, pb, pe - pb); 
SET p = INSTR(xy, ' '); 
SET p2x = SUBSTRING(xy, 1, p - 1); 
SET p2y = SUBSTRING(xy, p + 1); 
IF p1y < p2y THEN SET m = p1y; ELSE SET m = p2y; END IF; 
IF y > m THEN 
IF p1y > p2y THEN SET m = p1y; ELSE SET m = p2y; END IF; 
IF y <= m THEN 
IF p1x > p2x THEN SET m = p1x; ELSE SET m = p2x; END IF; 
IF x <= m THEN 
IF p1y != p2y THEN 
SET xinters = (y - p1y) * (p2x - p1x)/(p2y - p1y) + p1x; 
END IF; 
IF p1x = p2x OR x <= xinters THEN 
SET counter = counter + 1; 
END IF; 
END IF; 
END IF; 
END IF; 
SET p1x = p2x; 
SET p1y = p2y; 
SET pb = pe + 1; 
SET pe = LOCATE(',', str, pb); 
END WHILE; 

SET sb = se + 1; 
SET se = LOCATE('|', str_big, sb); 

END WHILE; 

RETURN counter % 2; 

END 

DELIMITER ; 
Cuestiones relacionadas