2012-10-02 12 views
8

Używam MySQL Spatial Extensions do przechowywania danych o drogach i hotelach. Przechowuję dane hotelu jako punkt, gdy przechowuję dane drogowe jako LineString. Tabele wyglądają tak, jakby wizualizacja instancji wyglądała następująco: wizualizacja instancji.Znajdź N najbliższego LineString z punktu przy użyciu rozszerzeń przestrzennych MySQL

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

Mój problem jest podana liczba N i punkt P, co jest kwerenda SQL, aby znaleźć najbliższe N ​​dróg z punktu P? Odległość jest określona przez najmniejszą prostopadłą odległość między segmentem na drodze do punktu pokazanego powyżej. (chociaż w rzeczywistości najbliższa odległość powinna znajdować się między bramą autostrady a hotelem, ale w tym przypadku możemy wprowadzić autostradę z dowolnego punktu: P)

Jeśli nie ma jednego rozwiązania instrukcji SQL dla tego problem, pośrednie zapytanie SQL i przetwarzanie końcowe są dla mnie akceptowalne. Ale jaka byłaby wydajna kwerenda SQL i jak postprocesować dane?

+0

Masz już swoją odpowiedź? :) – bonCodigo

+0

Upewnij się, że używasz MySQL 5.5 inaczej funkcja przestrzenna nie jest zaimplementowana na tyle, aby odpowiedzieć na twoje pytanie – TheSteve0

Odpowiedz

2

Można utworzyć dwie funkcje w bazie:

  1. Odległość: To daje odległość między dwoma punktami
  2. DistanceFromLine: Tutaj odległość będzie obliczana z każdego punktu w linii, i daje najkrótsza odległość.

Porównaj odległość między punktem i liniami i wybierz najkrótszy.

Oto funkcja Odległość


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

Oto DistanceFromLine funkcja:


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

To był bardzo pożyteczny dla mnie, ale używam MySQL 5.7.18, który ma bardziej zaawansowane lub po prostu inne funkcje zapytań geo. Opublikowana funkcja odległości nie jest już potrzebna - użyj ST_Distance_Sphere. Więc tutaj jest zmiana tego samego kodu, aby uczynić DistanceFromLine zgodny z nowoczesnym (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

I zostały również prace nad tym problemem, ale niestety znalezienie najbliższej drogi dla hoteli jest niekorzystne rozwiązanie. Przekonałem się, że wejście na drogę jest ostateczną odpowiedzią. Innymi słowy adres. Oznacza to posiadanie tabeli adresowej i pasujących punktów do najbliższego adresu drogowego.

Powiązane problemy