2012-10-02 23 views
8

Estoy usando MySQL Spatial Extensions para almacenar datos sobre carreteras y hoteles. Guardo los datos del hotel como un Punto mientras almaceno los datos del camino como LineString. Las tablas se ven asíEncontrar N LineString más cercano desde un punto usando MySQL Spatial Extensions

CREATE TABLE IF NOT EXISTS `Hotels` (
    `id` int unsigned NOT NULL AUTO_INCREMENT, 
    `name` text, 
    `coordinate` point NOT NULL, 
    PRIMARY KEY (`id`), 
    SPATIAL KEY `coordinate` (`coordinate`), 
) 

CREATE TABLE IF NOT EXISTS `Roads` (
    `id` int unsigned NOT NULL AUTO_INCREMENT, 
    `name` text, 
    `route` linestring NOT NULL, 
    PRIMARY KEY (`id`), 
    SPATIAL KEY `coordinate` (`route`), 
) 

La visualización de una instancia sería así.

http://i.stack.imgur.com/8IVVA.png

Mi problema se da un número N y un punto P, ¿cuál es la consulta SQL para encontrar caminos más cercanos N desde el punto P? La distancia se define por la distancia perpendicular más pequeña entre un segmento en el camino al punto como se muestra arriba. (aunque en la realidad, la distancia más cercana debe estar entre la puerta de la autopista y un hotel, pero en este caso, podemos ingresar a la carretera desde cualquier punto: P)

Si no hay una sola solución de declaración SQL para esto problema, una consulta SQL intermedia y un post-procesamiento son aceptables para mí. Pero, ¿qué sería una consulta SQL eficiente y cómo post-procesar los datos?

+0

¿Ya has recibido tu respuesta? :) – bonCodigo

+0

Asegúrate de utilizar MySQL 5.5; de lo contrario, la funcionalidad espacial no se implementa lo suficiente como para responder a tu pregunta – TheSteve0

Respuesta

2

Se pueden crear dos funciones en la base de datos:

  1. Distancia: Esto le dará la distancia entre dos puntos
  2. DistanceFromLine: Aquí distancia se calcula a partir de cada punto de la línea, y le dará la la distancia más corta.

Compara la distancia entre tus puntos y líneas y elige la más corta.

Aquí es la función Distancia


delimiter // 

CREATE FUNCTION distance (latA double, lonA double, latB double, LonB double) 
RETURNS double DETERMINISTIC 
    BEGIN 
     SET @RlatA = radians(latA); 
     SET @RlonA = radians(lonA); 
     SET @RlatB = radians(latB); 
     SET @RlonB = radians(LonB); 
     SET @deltaLat = @RlatA - @RlatB; 
     SET @deltaLon = @RlonA - @RlonB; 
     SET @d = SIN(@deltaLat/2) * SIN(@deltaLat/2) + 
     COS(@RlatA) * COS(@RlatB) * SIN(@deltaLon/2)*SIN(@deltaLon/2); 
     RETURN 2 * ASIN(SQRT(@d)) * 637101; 
    END// 

Aquí es función DistanceFromLine:


DROP function IF EXISTS `DistanceFromLine`; 
delimiter // 
    CREATE FUNCTION `DistanceFromLine`(
    route LINESTRING, point1 POINT 
    ) RETURNS INT DETERMINISTIC 
     BEGIN 
     DECLARE a INT Default 0 ; 
     DECLARE minDistance INT Default 0; 
     DECLARE currentDistance INT Default 0; 
     DECLARE currentpoint point ; 
     DECLARE size INT Default 0 ; 
     SET size = NumPoints(route); 
       simple_loop: LOOP 
     SET a = a+1; 
     SET currentpoint = PointN(route,a); 
     SET currentDistance = Distance(X(point1), Y(point1),  
       X(currentpoint),Y(currentpoint)); 

     IF a = 1 THEN 
     SET minDistance = currentDistance; 
      END IF; 

     IF currentDistance < minDistance THEN 
     SET minDistance = currentDistance; 
     END IF; 
     IF a=size THEN 
       LEAVE simple_loop; 
     END IF; 
      END LOOP simple_loop; 
    RETURN (minDistance); 
END// 

0

Esta fue una muy útil una Swer para mí, pero estoy usando MySQL 5.7.18, que tiene funciones de consulta geo más avanzadas o simplemente diferentes. La función de distancia publicada ya no es necesaria; use ST_Distance_Sphere. Así que aquí hay una actualización del mismo código para hacer DistanceFromLine compatible con moderna (5.7.6+) MySQL ...

DROP function IF EXISTS `DistanceFromLine`; 
delimiter // 
    CREATE FUNCTION `DistanceFromLine`(
    route LINESTRING, point1 POINT 
    ) RETURNS INT DETERMINISTIC 
     BEGIN 
     DECLARE a INT Default 0 ; 
     DECLARE minDistance INT Default 0; 
     DECLARE currentDistance INT Default 0; 
     DECLARE currentpoint point ; 
     DECLARE size INT Default 0 ; 
     SET size = ST_NumPoints(route); 
       simple_loop: LOOP 
     SET a = a+1; 
     SET currentpoint = ST_PointN(route,a); 
     SET currentDistance = ST_Distance_Sphere(point1,currentpoint); 

     IF a = 1 THEN 
     SET minDistance = currentDistance; 
      END IF; 

     IF currentDistance < minDistance THEN 
     SET minDistance = currentDistance; 
     END IF; 
     IF a=size THEN 
       LEAVE simple_loop; 
     END IF; 
      END LOOP simple_loop; 
    RETURN (minDistance); 
END// 
0

También he estado trabajando en este tema, pero por desgracia, la búsqueda de la carretera más cercana de Hoteles es una solución desfavorable. He descubierto que la entrada en la carretera es la respuesta definitiva. En otras palabras, la dirección. Esto significa tener una tabla de direcciones y puntos coincidentes con dirección de la carretera más cercana.

Cuestiones relacionadas