View Full Version : Distance between 2 locations 2D array
cwassmuth
05-06-2018, 03:20 PM
I have a unique identifier (column A) with its respective set of coordinates  (DD units, ex. 59, -110) for 500+ locations  and would like to write a macro that creates a 2D array (500+ X 500+) and automatically populates each cell within the array with the distance between all of the other coordinates in the data set. 
                          For example:
__Lat Long
                          A   59   -110
                          B   34   -90
                          C   78    -80
                          Hopefully I can create an array that looks like this:
__A   B   C
                          A    0    X    Y
                          B    X    0    Z
                          C    Y    Z    0
                          The formula to calculate the distance between the two coordinates is:
                          =ACOS( SIN(lat1*PI()/180)*SIN(lat2*PI()/180) + COS(lat1*PI()/180)*COS(lat2*PI()/180)*COS(long2*PI()/180-long1*PI()/180) ) * 6371000
                          In addition to this, if possible I would like to add a row onto the end of the array that gives the lowest distance calculated that is not zero.
                          It does not have to be a macro either, I just thought this may be the fastest most efficient way to accomplish this
                          Any help with this would be greatly appreciated
                          Thanks in advance
All this is off the top of my head with no help from Excel VBA, so there will be errors.
Next time, Copy a block of cells from the Sheet and paste them into your post, so we can just C&P them into a worksheet. I certainly won't look up a mess of location's Lats and Longs to make my own test data. They don't pay me.
This formula should be the same
Const R2D As Double = (Pi/190) 
Constant MagicNumber as long = 637100 'Convert to... Feet? Miles? Centimeters? *Furlongs?
ACOS(SIN(lat1)*SIN(lat2)*PIRN^2) +  COS(lat1)*COS(lat2)*COS(long2)*PIRN^3 _
-long1*PIRN)*MagicNumber
Const R2D As Double = (Pi/180) 'Declared here for speed
Const MagicNumber as long = 637100   'Don't want to declare them 2500 times
Sub MakeMatrix()
Dim Originals As Variant
Dim Distances As Variant
Dim Results As Double
Dim i as long, j as Long, k As long, l As long
Dim Rws As Long
Const Lat as Long = 1
Const Lon As Long = 2
Const MinDistance = 0.01 '*Furlongs ' Adjust as desired
'How many Rows
Rws = Cells(Rows,Count, "A").End(xlUp)).Row - 1 '-1 for header Row
'Set up the arrays
Originals = Application.Transpose(Range(Cells(2, "B"), Cells(Rws, "C"))).Value
Redim Distances(1 to Rws1, 1 to Rws)
'Step thru Originals one Row at a time.Twice
For i = LBound(Originals) to Ubound(Originals)
   For j = LBound(Originals) to Ubound(Originals)
       Results = GetDistance(Lat1:=Originals(i, Lat), _
                                     Lat2 =Originals(j, Lat), _
                                     Long1:=Originals(i, Lon), _
                                     Long1:=Originals(j, Lon))
       'Step thru Distances by columns then by rows
       If Results > MinDistance Then Distances(i, j) = Results 'No zeros, so you can find the min()
              'YOu might have to add 1 to i & j for the Distances array indices
Next j: Next i
'TBD: add Headers and Row Lables to Matrix
'You need to Assign Top left cell of Range for Matrix
Range("??").Resize(Rws, Rws) = Distances
End Sub
Private Function GetDistances(Lat1 As Double, Lat2 As Double, Long1 As Double, Long2 As Double) As Double
GetDistances = ACOS(SIN(lat1)*SIN(lat2)*R2D^2) +  COS(lat1)*COS(lat2)*COS(long2)*R2D^3 _
-long1*R2D)*MagicNumber
End Function
cwassmuth
05-07-2018, 06:22 AM
Thanks for the quick reply!
Here is a few of the values, sorry didn't post them before
22188
Paul_Hossler
05-07-2018, 11:40 AM
There are efficiencies that can be added, but at the expense of increasing the complexity 
Option Explicit
Sub MakeMatrix()
    
    Dim rIn As Range
    Dim wsOut As Worksheet
    Dim i As Long, j As Long
    Dim Lat1 As Double, Lat2 As Double, Long1 As Double, Long2 As Double
    
    Set rIn = Worksheets("Sheet1").Cells(1, 1).CurrentRegion
    
    On Error Resume Next
    Application.DisplayAlerts = False
    Worksheets("Matrix").Delete
    Application.DisplayAlerts = True
    On Error GoTo 0
    
    Worksheets.Add.Name = "Matrix"
    Set wsOut = Worksheets("Matrix")
    
    
    For i = 2 To rIn.Rows.Count
        wsOut.Cells(i, 1).Value = rIn.Cells(i, 1).Value
        wsOut.Cells(1, i).Value = rIn.Cells(i, 1).Value
    Next i
    
    
    For i = 2 To rIn.Rows.Count
        For j = 2 To rIn.Rows.Count
            
            Lat1 = rIn.Cells(i, 2).Value
            Long1 = rIn.Cells(i, 3).Value
            Lat2 = rIn.Cells(j, 2).Value
            Long2 = rIn.Cells(j, 3).Value
            
            If i = j Then
                wsOut.Cells(i, j).Value = 0#
            Else
                With Application.WorksheetFunction
                    wsOut.Cells(i, j).Value = _
                        .Acos(Sin(Lat1 * .Pi / 180) * Sin(Lat2 * .Pi / 180) + Cos(Lat1 * .Pi / 180) * Cos(Lat2 * .Pi / 180) * Cos(Long2 * .Pi / 180 - Long1 * .Pi / 180)) * 6371000
                End With
            End If
        Next j
    Next i
End Sub
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.