Logo_Access_global_380x114Favicon_Access_global_180x180Logo_Access_global_380x114Logo_Access_global_380x114
  • Home
  • University
    • Destellos formativos
  • Labs
  • TV
  • Secciones
    • El mundo de Access
    • Explorando VBA
      • Artículos sobre VBA
      • Un trocito de código
    • Entrevistas
      • Profesionales de Access
    • El rincón de Excel
    • Bases de datos
      • MS SQL
      • MySQL
      • postgreSQL
      • SQLite
    • Clases magistrales
    • Utilidades hechas con Access
  • Access en el mundo
  • ¿Quiénes somos?
  • Cómo colaborar
  • Eventos
✕
            No hay resultados Mostrar todos los resultados
            VBA: Google Maps API calcular la distancia entre dos coordenadas
            11/05/2022
            VBA: Google Maps API calcular la distancia entre dos coordenadas (Pitágoras)
            13/05/2022
            Mostrar todos

            VBA: Google Maps API calcular la distancia entre dos coordenadas (Vincenty)

            Publicado por Alba Salvá
            Categorías
            • Destellos formativos
            Etiquetas
            • API
            • Coordenadas
            • Google maps
            • VBA
            • Vincenty
            Option Compare Database
            Option Explicit
            
            'modVincenty
            Private Const PI = 3.14159265358979
            Private Const EPSILON As Double = 0.000000000001
            
            Public Function distVincenty(ByVal lat1 As Double, ByVal lon1 As Double, ByVal Lat2 As Double, ByVal Lon2 As Double) As Double
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Fuente             : https://access-global.net/vba-google-maps-api-calcular-la-distancia-entre-dos-coordenadas-vincenty
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Título             : distVincenty
            ' Autor original     : Alba Salvá
            ' Fecha              : 21/02/2020
            ' Propósito          : Conocer la distancia geodésica entre dos puntos especificados por latitud/longitud usando la
            '                      fórmula inversa de Vincenty para elipsoides
            ' Retorno            : devuelve la distancia en m (con una preción hasta milímetros)
            ' Argumento/s        : La sintaxis del procedimiento o función consta del siguiente argumento:
            '                      Parte            Modo           Descripción
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            '                      LatitudInicio    Obligatorio    Latitud del punto 1
            '                      LongitudInicio   Obligatorio    Longitud del punto 1
            '                      LatitudFin       Obligatorio    Latitud del punto 2
            '                      LongitudFin      Obligatorio    Longitud del punto s
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Mas información    : el código ha sido adaptado a VBA del javascript publicado en:
            '                      http://www.movable-type.co.uk/scripts/latlong-vincenty.html
            '                      fórmula inversa de Vincenty - T Vincenty, "Direct and Inverse Solutions of Geodesics on the
            '                      Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975
            'Referencia Adicional: http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            'Test                : Para adaptar este código en tu aplicación puedes basarte en este procedimiento test. Copiar el bloque siguiente al
            '                      portapapeles y pega en el editor de VBA. Descomentar la línea que nos interese y pulsar F5 para ver su funcionamiento.
            '
            'Sub distVincenty_test()
            '
            'Debug.print distVincenty(latitudorigen, longitudorigen, latituddestino, longituddestino)
            '
            'End Sub
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            
              Dim low_a As Double
              Dim low_b As Double
              Dim f As Double
              Dim L As Double
              Dim U1 As Double
              Dim U2 As Double
              Dim sinU1 As Double
              Dim sinU2 As Double
              Dim cosU1 As Double
              Dim cosU2 As Double
              Dim lambda As Double
              Dim lambdaP As Double
              Dim iterLimit As Integer
              Dim sinLambda As Double
              Dim cosLambda As Double
              Dim sinSigma As Double
              Dim cosSigma As Double
              Dim sigma As Double
              Dim sinAlpha As Double
              Dim cosSqAlpha As Double
              Dim cos2SigmaM As Double
              Dim c As Double
              Dim uSq As Double
              Dim upper_A As Double
              Dim upper_B As Double
              Dim deltaSigma As Double
              Dim s As Double ' resultado final redondeado a 3 decimales (mm).
              
              Dim P1 As Double
              Dim P2 As Double
              Dim P3 As Double
            
            'Ver http://es.wikipedia.org/wiki/World_Geodetic_System (en inglés)
            'para information sobre los parámetros de varios Elipsoides de otros estándares.
            '
            'low_a y low_b en metros
            ' === GRS-80 ===
            ' low_a = 6378137
            ' low_b = 6356752.314245
            ' f = 1 / 298.257223563
            '
            ' === Airy 1830 ===  Mayor precisión para Inglaterra y el norte de Europa
            ' low_a = 6377563.396
            ' low_b = 6356256.910
            ' f = 1 / 299.3249646
            '
            ' === Internacional 1924 ===
            ' low_a = 6378388
            ' low_b = 6356911.946
            ' f = 1 / 297
            '
            ' === Modelo Clarke 1880 ===
            ' low_a = 6378249.145
            ' low_b = 6356514.86955
            ' f = 1 / 293.465
            '
            ' === GRS-67 ===
            ' low_a = 6378160
            ' low_b = 6356774.719
            ' f = 1 / 298.247167
            
            '=== Parámetros Elipsoide WGS-84 === El más usado en todo el mundo, incluidos los sistemas GPS
              low_a = 6378137       ' +/- 2m
              low_b = 6356752.3142
              f = 1 / 298.257223563
            '====================================
              L = toRad(Lon2 - lon1)
              U1 = Atn((1 - f) * Tan(toRad(lat1)))
              U2 = Atn((1 - f) * Tan(toRad(Lat2)))
              sinU1 = Sin(U1)
              cosU1 = Cos(U1)
              sinU2 = Sin(U2)
              cosU2 = Cos(U2)
            
              lambda = L
              lambdaP = 2 * PI
              iterLimit = 100 ' se puede disminuir hasta 20 si se desea.
            
              While (Abs(lambda - lambdaP) > EPSILON) And (iterLimit > 0)
                iterLimit = iterLimit - 1
            
                sinLambda = Sin(lambda)
                cosLambda = Cos(lambda)
                sinSigma = Sqr(((cosU2 * sinLambda) ^ 2) + ((cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) ^ 2))
                If sinSigma = 0 Then
                  distVincenty = 0  'puntos coincidentes
                  Exit Function
                End If
                cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda
                sigma = Atan2(cosSigma, sinSigma)
                sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma
                cosSqAlpha = 1 - sinAlpha * sinAlpha
            
                If cosSqAlpha = 0 Then 'verificamos di es división por cero
                  cos2SigmaM = 0 '2 puntos en el ecuador
                Else
                  cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha
                End If
            
                c = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha))
                lambdaP = lambda
            
            'Los cálculos originales son muy complejos para VBA
            'por ello, se han dividido en varias partes para evitar problemas.
            'la implementación original para el cálculo de Lambda
            '  lambda = L + (1 - C) * f * sinAlpha * _
                        (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * (cos2SigmaM ^ 2))))
                  
                'calculamos porciones
                  
                P1 = -1 + 2 * (cos2SigmaM ^ 2)
                P2 = (sigma + c * sinSigma * (cos2SigmaM + c * cosSigma * P1))
                
                'completo el cálculo
                lambda = L + (1 - c) * f * sinAlpha * P2
            
              Wend
            
              If iterLimit < 1 Then
                MsgBox "Se ha alcanzado el límite de iteraciones," & vbCrLf & _
                       "algo no ha idocomo se esperaba.", vbExclamation, "Cálculo por método Vincenty"
                Exit Function
              End If
            
              uSq = cosSqAlpha * (low_a ^ 2 - low_b ^ 2) / (low_b ^ 2)
            
              'Los cálculos originales son muy complejos para VBA
              'por ello, se han dividido en varias partes para evitar problemas.
              '
              'la implementación original para el cálculo de upper_A
              'upper_A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)))
              
              'calculo una parte de la ecuación
              P1 = (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)))
              'completo el cálculo
              upper_A = 1 + uSq / 16384 * P1
            
              'por extraño que parezca, upper_B calcula sin ningún problema
              upper_B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)))
            
              'Los cálculos originales son muy complejos para VBA
              'por ello, se han dividido en varias partes para evitar problemas.
              '
              'la implementación original para el cálculo de deltaSigma
              'deltaSigma = upper_B * sinSigma * (cos2SigmaM + upper_B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM ^ 2) _
                            - upper_B / 6 * cos2SigmaM * (-3 + 4 * sinSigma ^ 2) * (-3 + 4 * cos2SigmaM ^ 2)))
              
              'el cálculo de la fórmula de deltaSigma se divide en 3 partes
              'para prevenir el error de overflow que puede ocurrir
              
              P1 = (-3 + 4 * sinSigma ^ 2) * (-3 + 4 * cos2SigmaM ^ 2)
              P2 = upper_B * sinSigma
              P3 = (cos2SigmaM + upper_B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM ^ 2) - upper_B / 6 * cos2SigmaM * P1))
              
              'completo el cálculo de deltaSigma
              deltaSigma = P2 * P3
            
              'calculo la distancia
              s = low_b * upper_A * (sigma - deltaSigma)
              
              'redondeo la distancia a milímetros
              distVincenty = Round(s, 3)
            
            End Function
            
            Function Convert_Degree(Decimal_Deg) As Variant
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Fuente            : http://support.microsoft.com/kb/213449
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Título            : Convert_Degree
            ' Propósito         : converts a decimal degree representation to deg min sec
            '                     as 10.46 returns 10° 27' 36"
            ' Retorno           : el valor en grados del valor que le pasamos
            ' Argumento/s       : La sintaxis del procedimiento o función consta del siguiente argumento:
            '                     Parte            Modo           Descripción
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            '                     decimal_Deg     Obligatorio    Valor decimal obtenido
            '-----------------------------------------------------------------------------------------------------------------------------------------------
              Dim degrees As Variant
              Dim minutes As Variant
              Dim seconds As Variant
              
              With Application
                 'Set degree to Integer of Argument Passed
                 degrees = Int(Decimal_Deg)
                 'Set minutes to 60 times the number to the right
                 'of the decimal for the variable Decimal_Deg
                 minutes = (Decimal_Deg - degrees) * 60
                 'Set seconds to 60 times the number to the right of the
                 'decimal for the variable Minute
                 seconds = Format(((minutes - Int(minutes)) * 60), "0")
                 'Returns the Result of degree conversion
                '(for example, 10.46 = 10º 27' 36")
                 Convert_Degree = " " & degrees & "º " & Int(minutes) & "' " _
                     & seconds + Chr(34)
              
              End With
            
            End Function
            
            Function Convert_Decimal(Degree_Deg As String) As Double
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Fuente            : http://support.microsoft.com/kb/213449
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Título            : Convert_Decimal
            ' Propósito         : Converts text angular entry to decimal equivalent, as:
            '                     10° 27' 36" returns 10.46
            '                     alternative to "°" is permitted: Use "~" instead, as:
            '                     10~ 27' 36" also returns 10.46
            ' Retorno           : el valor en grados del valor que le pasamos
            ' Argumento/s       : La sintaxis del procedimiento o función consta del siguiente argumento:
            '                     Parte            Modo           Descripción
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            '                     decimal_Deg     Obligatorio    Valor decimal obtenido
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Importante        : Declare the variables to be double precision floating-point.
            '-----------------------------------------------------------------------------------------------------------------------------------------------
               Dim degrees As Double
               Dim minutes As Double
               Dim seconds As Double
               '
               
               '-----------------------------------------------------------------
               'modificación por JLatham
               'permite usar el símolo "~" symbol en vez de "°" para indicar grados
               'dado que "~" está disponible en teclados no espaañoles y "°" se tiene
               'que introducir por [Alt] [0] [1] [7] [6].
               Degree_Deg = Replace(Degree_Deg, "~", "°")
               '-----------------------------------------------------------------
            
               ' Set degree to value before "º" of Argument Passed.
               degrees = Val(Left(Degree_Deg, InStr(1, Degree_Deg, "º") - 1))
               
               ' Set minutes to the value between the "º" and the "'"
               ' of the text string for the variable Degree_Deg divided by
               ' 60. The Val function converts the text string to a number.
               minutes = Val(Mid(Degree_Deg, InStr(1, Degree_Deg, "º") + 2, _
                         InStr(1, Degree_Deg, "'") - InStr(1, Degree_Deg, "º") - 2)) / 60
               
               ' Set seconds to the number to the right of "'" that is
               ' converted to a value and then divided by 3600.
               seconds = Val(Mid(Degree_Deg, InStr(1, Degree_Deg, "'") + _
                       2, Len(Degree_Deg) - InStr(1, Degree_Deg, "'") - 2)) / 3600
               
               Convert_Decimal = degrees + minutes + seconds
            
            End Function
            
            Private Function toRad(ByVal degrees As Double) As Double
                
                toRad = degrees * (PI / 180)
            
            End Function
            
            Private Function Atan2(ByVal X As Double, ByVal Y As Double) As Double
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Fuente            : http://en.wikibooks.org/wiki/Programming:Visual_Basic_Classic/Simple_Arithmetic#Trigonometrical_Functions
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Título            : Atan2
            ' Propósito         : Converts text angular entry to decimal equivalent, as:
            '                     10° 27' 36" returns 10.46
            '                     alternative to "°" is permitted: Use "~" instead, as:
            '                     10~ 27' 36" also returns 10.46
            ' Retorno           : la arcotangente de las coordenadas que le pasamos a la función
            ' Argumento/s       : La sintaxis del procedimiento o función consta del siguiente argumento:
            '                     Parte            Modo           Descripción
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            '                     decimal_Deg     Obligatorio    Valor decimal obtenido
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            ' Importante        : Si reutilizas este código, ten en cuenta que X e Y se han invertido respecto al uso tópico
            '-----------------------------------------------------------------------------------------------------------------------------------------------
            
                If Y > 0 Then
                    If X >= Y Then
                        Atan2 = Atn(Y / X)
                    ElseIf X <= -Y Then
                        Atan2 = Atn(Y / X) + PI
                    Else
                    Atan2 = PI / 2 - Atn(X / Y)
                End If
                    Else
                        If X >= -Y Then
                        Atan2 = Atn(Y / X)
                    ElseIf X <= Y Then
                        Atan2 = Atn(Y / X) - PI
                    Else
                        Atan2 = -Atn(X / Y) - PI / 2
                    End If
                End If
            
            End Function
            
            
            ¡Ver en el repositorio!
            Compartir
            18
            Alba Salvá
            Alba Salvá

            Entradas relacionadas

            21/03/2023

            ¿Mis procedimientos tienen tratamiento de errores?


            Leer más
            20/03/2023

            Moda, mediana y algo más


            Leer más
            17/03/2023

            Funciones de dominio de Alba


            Leer más

            Deja una respuesta Cancelar la respuesta

            Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

            ETIQUETAS

            Access API BD Botones ComboBox Consultas CountOfLines CStr Diseño DoCmd Excel Exportar Fecha FileSystemObject Filtros For Each...Next Formulario Formularios Funciones Funciones de dominio GetFolder GetWindowRect Google maps Informes InStr Jose Bengoechea Kill Left Listbox Mid Módulos Node ProcCountLines Procedimientos ProcOfLine References Ribbon RunCommand Seguridad Split SysCmd Tablas TreeView VBA VBIDE

            ÚLTIMAS ENTRADAS

            • 0
              ¿Mis procedimientos tienen tratamiento de errores?
              21/03/2023
            • 0
              Moda, mediana y algo más
              20/03/2023

            ¿QUIERES PUBLICITAR TU EMPRESA AQUÍ?

            SUSCRÍBETE A NUESTRO
            NEWSLETTER

            Recibirás información puntual sobre el mundo de Access y VBA

            ¡Próximamente!

            Promovemos el uso de Access y de la programación en VBA en todo el mundo

            Centro de conocimiento


            Toda la sabiduría de los mejores programadores de Access y VBA a tu alcance.

            Legal

            Política de privacidad

            Condiciones de uso

            Condiciones del redactor

            ®Access Global 2021 | All right reserved
                      No hay resultados Mostrar todos los resultados