S
Scott Emick
I am using the following to compute distances between two lat/long
coordinates for a store locator - (VB .NET 2003)
it seems to take a long time to iterate through like 100-150 locations -
about 10-15 seconds...I want to make the code faster. I changed it to be
multi-threaded, and it doesn't really make it any faster. The bottleneck
seems to be with the math computations.
Any ideas like changing my data types or other ideas etc would be helpful.
Thanks,
--
Scott Emick
Web Programmer
Fox International
Remove the ham from mail address if it's not spam
Option Strict On
Imports System.Threading
Imports Infragistics.Shared
Imports Infragistics.Win
Imports Infragistics.Win.UltraWinGrid
Public Class Locator
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
[...]
#End Region
Public Q As New Queue
Public R As New Queue
Shared rwl As New ReaderWriterLock
Dim dvZip As DataView
Dim srcLat As Double
Dim srcLon As Double
Private Sub btnFind_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnFind.Click
dvZip = New DataView(DsMM1.Zip)
Dim mmrow As dsMM.Mailing_MasterRow
Dim zlat As String
Dim zlon As String
Dim deg As Double
Dim min As Double
Dim sec As Double
dvZip.RowFilter = "ZCODE='" & Microsoft.VisualBasic.Left(txtZip.Text,
5) & "'"
srcLat = CDbl(dvZip(0)("lat"))
srcLon = CDbl(dvZip(0)("lon"))
Dim currow As Integer
For Each mmrow In DsMM1.Mailing_Master
currow += 1
UltraProgressBar1.Value = CInt((currow /
DsMM1.Mailing_Master.Count) * 100)
Application.DoEvents()
Q.Enqueue(mmrow)
R.Enqueue(currow)
Dim job3 As New ThreadStart(AddressOf ComputeDistance)
Dim thread3 As New Thread(job3)
thread3.Name = "ComputeDistance"
Do Until R.Count < 20
Loop
thread3.Start()
Next
Dim dvMM01 As New DataView(DsMM1.Mailing_Master)
UltraGrid1.DataSource = dvMM01
dvMM01.Sort = "distance"
dvMM01.RowFilter = "distance<=" & txtMiles.Text
Dim band As UltraGridBand = Me.UltraGrid1.DisplayLayout.Bands(0)
band.Columns("distance").SortIndicator = SortIndicator.Ascending
band.SortedColumns.Add("distance", False, False)
End Sub
Private Sub ComputeDistance()
Dim mmr As dsMM.Mailing_MasterRow = CType(Q.Dequeue,
dsMM.Mailing_MasterRow)
Dim lat As Double
Dim lon As Double
Dim dist As Integer
Dim dvZip2 As New DataView(DsMM1.Zip)
dvZip2.RowFilter = "ZCODE='" & Mid(mmr.MMZIP, 1, 5) & "'"
If dvZip.Count > 0 Then
lat = CDbl(dvZip2(0)("lat"))
lon = CDbl(dvZip2(0)("lon"))
dist = LocatorLib.Calcs.distance(srcLat, srcLon, lat, lon, "N")
Console.WriteLine(dist)
rwl.AcquireWriterLock(60000)
mmr.Distance = dist
rwl.ReleaseWriterLock()
Else
dist = 2147483647
End If
R.Dequeue()
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Me.Show()
txtResults.Text &= "Filling location database..." & vbCrLf
Application.DoEvents()
DsMM1.EnforceConstraints = False
daMM.Fill(DsMM1)
DsMM1.WriteXml("c:\dsmm1.xml")
daZip.Fill(DsMM1)
txtResults.Text &= "Enabling Constraints." & vbCrLf
Try
DsMM1.EnforceConstraints = True
Catch ex As Exception
MessageBox.Show(ex.ToString, "Error", MessageBoxButtons.OK)
End
End Try
txtResults.Text &= DsMM1.Mailing_Master.Count.ToString & " locations
available. " & vbCrLf
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs)
Dim dvZip As New DataView(DsMM1.Zip)
Dim mmrow As dsMM.Mailing_MasterRow
Dim zlat As String
Dim zlon As String
Dim lat As Double
Dim lon As Double
Dim deg As Double
Dim min As Double
Dim sec As Double
Dim dist As Integer
Dim srcLat As Double
Dim srcLon As Double
'dvZip.RowFilter = "ZCODE='" & Microsoft.VisualBasic.Left(txtZip.Text,
5) & "'"
'zlat = CStr(dvZip(0)("zlat"))
'deg = CDec(zlat.Substring(0, 2))
'min = CDec(zlat.Substring(2, 2))
'sec = CDec(zlat.Substring(4, 2))
'srcLat = deg + (min / 60) + (sec / 3600)
'zlon = CStr(dvZip(0)("zlon"))
'deg = CDec(zlon.Substring(0, 2))
'min = CDec(zlon.Substring(2, 2))
'sec = CDec(zlon.Substring(4, 2))
'srcLon = deg + (min / 60) + (sec / 3600)
Dim currow As Integer
For Each mmrow In DsMM1.Mailing_Master
currow += 1
UltraProgressBar1.Value = CInt((currow / DsMM1.Zip.Count) * 100)
Application.DoEvents()
dvZip.RowFilter = "ZCODE='" &
Microsoft.VisualBasic.Left(mmrow.MMZIP, 5) & "'"
If dvZip.Count > 0 Then
lat = CDbl(dvZip(0)("LAT"))
mmrow.LAT = CDec(lat)
lon = CDbl(dvZip(0)("LON"))
mmrow.LON = CDec(lon)
daMM.Update(DsMM1.Mailing_Master)
'dist = LocatorLib.Calcs.distance(srcLat, srcLon, lat, lon, "N")
mmrow.Distance = dist
Else
dist = 2147483647
End If
Next
End Sub
End Class
'Below is from a class in a library project (dll)
Option Strict On
Imports System.Math
Public Class Calcs
Const pi As Double = 3.1415926535897931
Public Shared Function distance(ByVal lat1 As Double, ByVal lon1 As
Double, ByVal lat2 As Double, ByVal lon2 As Double, ByVal unit As String) As
Integer
Dim theta As Double, dist As Double
theta = lon1 - lon2
dist = Sin(CDbl(deg2rad(lat1))) * Sin(CDbl(deg2rad(lat2))) +
Cos(CDbl(deg2rad(lat1))) * Cos(CDbl(deg2rad(lat2))) *
Cos(CDbl(deg2rad(theta)))
dist = CDbl(acos(dist))
dist = CDbl(rad2deg(dist))
distance = CInt(dist * 60 * 1.1515)
Select Case UCase(unit)
Case "K"
distance = CInt(distance * 1.609344)
Case "N"
distance = CInt(distance * 0.8684)
End Select
End Function
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: this function get the arccos function from arctan function :::
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Public Shared Function acos(ByVal rad As Double) As Double
If Abs(CDec(rad)) <> 1 Then
acos = pi / 2 - Atan(rad / Sqrt(1 - rad * rad))
ElseIf rad = -1 Then
acos = pi
End If
End Function
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: this function converts decimal degrees to radians :::
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Public Shared Function deg2rad(ByVal deg As Double) As Double
deg2rad = CDbl(deg * pi / 180)
End Function
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: this function converts radians to decimal degrees :::
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Public Shared Function rad2deg(ByVal rad As Double) As Double
rad2deg = CDbl(rad * 180 / pi)
End Function
End Class
coordinates for a store locator - (VB .NET 2003)
it seems to take a long time to iterate through like 100-150 locations -
about 10-15 seconds...I want to make the code faster. I changed it to be
multi-threaded, and it doesn't really make it any faster. The bottleneck
seems to be with the math computations.
Any ideas like changing my data types or other ideas etc would be helpful.
Thanks,
--
Scott Emick
Web Programmer
Fox International
Remove the ham from mail address if it's not spam
Option Strict On
Imports System.Threading
Imports Infragistics.Shared
Imports Infragistics.Win
Imports Infragistics.Win.UltraWinGrid
Public Class Locator
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
[...]
#End Region
Public Q As New Queue
Public R As New Queue
Shared rwl As New ReaderWriterLock
Dim dvZip As DataView
Dim srcLat As Double
Dim srcLon As Double
Private Sub btnFind_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnFind.Click
dvZip = New DataView(DsMM1.Zip)
Dim mmrow As dsMM.Mailing_MasterRow
Dim zlat As String
Dim zlon As String
Dim deg As Double
Dim min As Double
Dim sec As Double
dvZip.RowFilter = "ZCODE='" & Microsoft.VisualBasic.Left(txtZip.Text,
5) & "'"
srcLat = CDbl(dvZip(0)("lat"))
srcLon = CDbl(dvZip(0)("lon"))
Dim currow As Integer
For Each mmrow In DsMM1.Mailing_Master
currow += 1
UltraProgressBar1.Value = CInt((currow /
DsMM1.Mailing_Master.Count) * 100)
Application.DoEvents()
Q.Enqueue(mmrow)
R.Enqueue(currow)
Dim job3 As New ThreadStart(AddressOf ComputeDistance)
Dim thread3 As New Thread(job3)
thread3.Name = "ComputeDistance"
Do Until R.Count < 20
Loop
thread3.Start()
Next
Dim dvMM01 As New DataView(DsMM1.Mailing_Master)
UltraGrid1.DataSource = dvMM01
dvMM01.Sort = "distance"
dvMM01.RowFilter = "distance<=" & txtMiles.Text
Dim band As UltraGridBand = Me.UltraGrid1.DisplayLayout.Bands(0)
band.Columns("distance").SortIndicator = SortIndicator.Ascending
band.SortedColumns.Add("distance", False, False)
End Sub
Private Sub ComputeDistance()
Dim mmr As dsMM.Mailing_MasterRow = CType(Q.Dequeue,
dsMM.Mailing_MasterRow)
Dim lat As Double
Dim lon As Double
Dim dist As Integer
Dim dvZip2 As New DataView(DsMM1.Zip)
dvZip2.RowFilter = "ZCODE='" & Mid(mmr.MMZIP, 1, 5) & "'"
If dvZip.Count > 0 Then
lat = CDbl(dvZip2(0)("lat"))
lon = CDbl(dvZip2(0)("lon"))
dist = LocatorLib.Calcs.distance(srcLat, srcLon, lat, lon, "N")
Console.WriteLine(dist)
rwl.AcquireWriterLock(60000)
mmr.Distance = dist
rwl.ReleaseWriterLock()
Else
dist = 2147483647
End If
R.Dequeue()
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Me.Show()
txtResults.Text &= "Filling location database..." & vbCrLf
Application.DoEvents()
DsMM1.EnforceConstraints = False
daMM.Fill(DsMM1)
DsMM1.WriteXml("c:\dsmm1.xml")
daZip.Fill(DsMM1)
txtResults.Text &= "Enabling Constraints." & vbCrLf
Try
DsMM1.EnforceConstraints = True
Catch ex As Exception
MessageBox.Show(ex.ToString, "Error", MessageBoxButtons.OK)
End
End Try
txtResults.Text &= DsMM1.Mailing_Master.Count.ToString & " locations
available. " & vbCrLf
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs)
Dim dvZip As New DataView(DsMM1.Zip)
Dim mmrow As dsMM.Mailing_MasterRow
Dim zlat As String
Dim zlon As String
Dim lat As Double
Dim lon As Double
Dim deg As Double
Dim min As Double
Dim sec As Double
Dim dist As Integer
Dim srcLat As Double
Dim srcLon As Double
'dvZip.RowFilter = "ZCODE='" & Microsoft.VisualBasic.Left(txtZip.Text,
5) & "'"
'zlat = CStr(dvZip(0)("zlat"))
'deg = CDec(zlat.Substring(0, 2))
'min = CDec(zlat.Substring(2, 2))
'sec = CDec(zlat.Substring(4, 2))
'srcLat = deg + (min / 60) + (sec / 3600)
'zlon = CStr(dvZip(0)("zlon"))
'deg = CDec(zlon.Substring(0, 2))
'min = CDec(zlon.Substring(2, 2))
'sec = CDec(zlon.Substring(4, 2))
'srcLon = deg + (min / 60) + (sec / 3600)
Dim currow As Integer
For Each mmrow In DsMM1.Mailing_Master
currow += 1
UltraProgressBar1.Value = CInt((currow / DsMM1.Zip.Count) * 100)
Application.DoEvents()
dvZip.RowFilter = "ZCODE='" &
Microsoft.VisualBasic.Left(mmrow.MMZIP, 5) & "'"
If dvZip.Count > 0 Then
lat = CDbl(dvZip(0)("LAT"))
mmrow.LAT = CDec(lat)
lon = CDbl(dvZip(0)("LON"))
mmrow.LON = CDec(lon)
daMM.Update(DsMM1.Mailing_Master)
'dist = LocatorLib.Calcs.distance(srcLat, srcLon, lat, lon, "N")
mmrow.Distance = dist
Else
dist = 2147483647
End If
Next
End Sub
End Class
'Below is from a class in a library project (dll)
Option Strict On
Imports System.Math
Public Class Calcs
Const pi As Double = 3.1415926535897931
Public Shared Function distance(ByVal lat1 As Double, ByVal lon1 As
Double, ByVal lat2 As Double, ByVal lon2 As Double, ByVal unit As String) As
Integer
Dim theta As Double, dist As Double
theta = lon1 - lon2
dist = Sin(CDbl(deg2rad(lat1))) * Sin(CDbl(deg2rad(lat2))) +
Cos(CDbl(deg2rad(lat1))) * Cos(CDbl(deg2rad(lat2))) *
Cos(CDbl(deg2rad(theta)))
dist = CDbl(acos(dist))
dist = CDbl(rad2deg(dist))
distance = CInt(dist * 60 * 1.1515)
Select Case UCase(unit)
Case "K"
distance = CInt(distance * 1.609344)
Case "N"
distance = CInt(distance * 0.8684)
End Select
End Function
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: this function get the arccos function from arctan function :::
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Public Shared Function acos(ByVal rad As Double) As Double
If Abs(CDec(rad)) <> 1 Then
acos = pi / 2 - Atan(rad / Sqrt(1 - rad * rad))
ElseIf rad = -1 Then
acos = pi
End If
End Function
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: this function converts decimal degrees to radians :::
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Public Shared Function deg2rad(ByVal deg As Double) As Double
deg2rad = CDbl(deg * pi / 180)
End Function
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: this function converts radians to decimal degrees :::
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Public Shared Function rad2deg(ByVal rad As Double) As Double
rad2deg = CDbl(rad * 180 / pi)
End Function
End Class