Distância entre dois pontos na superfície da Terra

MariaDB

Diagrama ilustrando a menor distância entre os dois pontos P e Q na superfície de uma esfera,
Diagrama ilustrando a menor distância entre os dois pontos P e Q na superfície de uma esfera, via Wikimedia Commons

O World Geodetic System (WGS) define um quadro de referência para a Terra, para uso em geodésia e navegação. Sua última revisão, o WGS 84, é baseado em um conjunto consistente de constantes e parâmetros do modelo que descreve o tamanho, forma e gravidade da Terra e seus campos geomagnéticos, sendo o padrão usado pelo Departamento de Defesa dos EUA para informações geoespaciais e pelo Sistema de Posicionamento Global (GPS). O valor adotado para o semieixo maior (a) do elipsoide do WGS 84, um parâmetro de definição, e sua estimativa de precisão de um sigma são:

a = (6378137 ±2) metros.

O semieixo menor é uma constante derivada:

b = 6356752.3142 metros.

Assim como o raio médio dos semieixos:

R1 = 6371008.7714 metros.

Os argumentos da geometria devem consistir de pontos que especificam os valores das coordenadas (longitude, latitude):

  • Longitude e latitude são a primeira e a segunda coordenadas do ponto, respectivamente;
  • As duas coordenadas estão em graus;
  • Os valores de longitude devem estar no intervalo (-180, 180]. Os valores positivos estão a leste do meridiano principal.
  • Os valores de latitude devem estar no intervalo [-90, 90]. Os valores positivos estão ao norte do equador.

Como não existe no MariaDB a função ST_Distance_Sphere do MySQL, que retorna a distância esférica mínima entre os dois argumentos, foi desenvolvida a função análoga, mostrada abaixo, usando a formula:

d = R * acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1))

DELIMITER $$
-- Função para calcular a distância entre dois pontos na superfície da Terra.
-- Recebe como parâmetro as coordenadas dos dois pontos com o tipo geométrico Point.
-- Retorna a distância dos dois pontos em quilômetros.
-- Utiliza como raio da Terra o semieixo maior.
-- d = R * acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1))
CREATE OR REPLACE FUNCTION `distancia`(`ponto1` POINT, `ponto2` POINT) RETURNS DOUBLE
BEGIN
RETURN (SELECT (6378.137 * ACOS( 
        SIN(RADIANS(ST_Y(ponto1)))
      * SIN(RADIANS(ST_Y(ponto2)))
      + COS(RADIANS(ST_Y(ponto1))) 
      * COS(RADIANS(ST_Y(ponto2))) 
      * COS(RADIANS(ST_X(ponto2)) - RADIANS(ST_X(ponto1)))
)));
END$$
DELIMITER ;

O raio da Terra em uma determinada latitude pode ser calculado pela fórmula:

R = √ [ (a² * cos(L))² + (b² * sin(L))² ] / [ (a * cos(L))² + (b * sin(L))² ]

sendo L a latitude. A função abaixo calcula o raio da Terra a partir da latitude:

DELIMITER $$
-- Função para calcular o raio da Terra a partir da latitude.
-- Recebe como parâmetro a latitude em graus decimais.
-- Retorna o raio em quilômetros.
CREATE OR REPLACE FUNCTION `raio_latitude`(`L` DOUBLE) RETURNS DOUBLE
BEGIN
DECLARE a, b DOUBLE;
SET a = 6378.137;
SET b = 6356.752;
RETURN SQRT( ( POWER((a*a * COS(RADIANS(L))),2) + POWER((b*b * SIN(RADIANS(L))),2) ) /
             ( POWER((a   * COS(RADIANS(L))),2) + POWER((b   * SIN(RADIANS(L))),2) ) );
END$$
DELIMITER ;

Juntando-se as duas funções temos:

DELIMITER $$
-- Função para calcular a distância entre dois pontos na superfície da Terra.
-- Recebe como parâmetro as coordenadas dos dois pontos com o tipo geométrico Point.
-- Retorna a distância dos dois pontos em quilômetros.
-- Calcula o raio da Terra a partir da latitude média.
-- d = R * acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1))
CREATE OR REPLACE FUNCTION `distancia_latitude`(`ponto1` POINT, `ponto2` POINT) RETURNS DOUBLE
BEGIN
DECLARE a, b, L, R DOUBLE;
SET a = 6378.137;
SET b = 6356.752;
SET L = (ST_Y(ponto1) + ST_Y(ponto2))/2.;
SET R = SQRT( ( POWER((a*a * COS(RADIANS(L))),2) + POWER((b*b * SIN(RADIANS(L))),2) ) /
              ( POWER((a   * COS(RADIANS(L))),2) + POWER((b   * SIN(RADIANS(L))),2) ) );
RETURN (SELECT (R * ACOS( 
        SIN(RADIANS(ST_Y(ponto1)))
      * SIN(RADIANS(ST_Y(ponto2)))
      + COS(RADIANS(ST_Y(ponto1))) 
      * COS(RADIANS(ST_Y(ponto2))) 
      * COS(RADIANS(ST_X(ponto2)) - RADIANS(ST_X(ponto1)))
)));
END$$
DELIMITER ;
Referências