I'm trying to optimize (for speed) the following code snippet, which
prepares over a million small polygons for rendering. Before you start
asking (what?!), yes there are over a million individual data points
that 1.) have unique properties 2.) can change on the fly. Thus the
DrawPolygon function below is called repeatedly with new datasets.
Yes, using the Polygon API is fairly slow and I'm exploring OpenGL to
remove that lantency. Still, the actual determining of the vertex
placements on the screen is the purpose of the following function.
I'm running a new, pretty high end PC, and am seeing this function
take around .45 seconds to complete in the IDE and around .13 seconds
compiled (with optimizations selected).
This still seems quite slow for a 2.4 GHz Core 2 Duo, considering the
basic math involved. I was hoping that someone might see something
obvious that may help bring this down. The outer loop with the trig
functions actually runs quite fast (taking less than 1ms to complete
for all iterations), so there has to be something with the inner loop
that's causing the problem. My guess is that (at least partially) it's
the Long assigment to the POINTAPI array (as required for the Polygon
API) from the Single variables.
Thanks in advance!
wxforecaster
'REQUIREMENTS: Create a form with a listbox (list1)
'and a timer (timer1) whose interval is set to 10 to spawn this
function frequently.
'Timer APIs
Private Declare Function timeGetTime Lib "winmm.dll" () As Long
Private Declare Function timeBeginPeriod Lib "winmm.dll" (ByVal
uPeriod As Long) As Long
Private Declare Function timeEndPeriod Lib "winmm.dll" (ByVal uPeriod
As Long) As Long
Private Type POINTAPI
x As Long
y As Long
End Type
Dim bUnload As Boolean
Const Pi180 As Single = 0.0174533
Public Sub DrawPolygons()
Dim Start As Long
Dim i As Long, j As Long
Dim radarPoly(0 To 3) As POINTAPI
Dim jj As Single, cosaz As Single, sinaz As Single
Dim cosazplus As Single, sinazplus As Single
'Throw in some random approximate values that would be passed to this
function.
'Because these change, we cannot simply store the resultant polygons
in a
'permanant array. Hence the need to optimize the speed here as this
function will be called repeatedly.
Dim HalfWidth As Single: HalfWidth = 300.25
Dim HalfHeight As Single: HalfHeight = 301.13
Dim zoomscl As Single: zoomscl = 2#
Dim zoomwidth As Single: zoomwidth = 0.806667 * zoomscl
Dim zoomheight As Single: zoomheight = 0.8061111 * zoomscl
Dim vlft As Single: vlft = 89.90001 * zoomscl
Dim vtop As Single: vtop = 82.26666 * zoomscl
Dim sf As Single: sf = 0.25
Dim azang As Single, delang As Single
Dim oldx1 As Long, oldx2 As Long, oldy1 As Long, oldy2 As Long
'Create Lookup Table with bin distances
Dim bin_dist() As Single
ReDim bin_dist(1800)
For j = 0 To UBound(bin_dist)
bin_dist(j) = 8 + j * sf
Next j
'Total Loop iterations = 720 (i) * 1800 (j) = 1296000
DoEvents
Start = timeGetTime
'Run outer loop over 720 degrees and calculate some angular based
variables
For i = 1 To 720
azang = i / 2
delang = azang + 0.49
cosaz = Cos((450# - azang) * Pi180)
sinaz = Sin((450# - azang) * Pi180)
cosazplus = Cos((450# - (delang)) * Pi180)
sinazplus = Sin((450# - (delang)) * Pi180)
'Calculate Initial X,Y vertices before entering inner loop
oldx1 = ((HalfWidth + (bin_dist(0) * cosaz)) * zoomwidth)
- vlft
oldy1 = ((HalfHeight - (bin_dist(0) * sinaz)) *
zoomheight) - vtop
oldx2 = ((HalfWidth + (bin_dist(0) * cosazplus)) *
zoomwidth) - vlft
oldy2 = ((HalfHeight - (bin_dist(0) * sinazplus)) *
zoomheight) - vtop
'Run inner loop and calculate vertices for remaining
points
'Since all of our polygons are adjacent within the inner
loop, we only
'need to calculate two new points each iteration and then
save them to
'an variable to avoid the excess math calculations
For j = 1 To 1800
'get zoom/scale adjusted j from lookup table above
jj = bin_dist(j)
'Back left vertex
radarPoly(0).x = oldx1
radarPoly(0).y = oldy1
'Back right vertex
radarPoly(3).x = oldx2
radarPoly(3).y = oldy2
'Front left vertex then assign to Back left
radarPoly(1).x = ((HalfWidth + (jj * cosaz)) *
zoomwidth) - vlft
oldx1 = radarPoly(1).x
radarPoly(1).y = ((HalfHeight - (jj * sinaz)) *
zoomheight) - vtop
oldy1 = radarPoly(1).y
'Front right vertex then assign to Back right
radarPoly(2).x = ((HalfWidth + (jj * cosazplus)) *
zoomwidth) - vlft
oldx2 = radarPoly(2).x
radarPoly(2).y = ((HalfHeight - (jj * sinazplus)) *
zoomheight) - vtop
oldy2 = radarPoly(2).y
'We would then draw our polygon here, passing the
radarPoly() array to
'Polygon API (or eventually OpenGL QUAD_STRIPS)
Next j
Next i
'Place a list box on the form to monitor how long it takes this
function to complete
Call List1.AddItem((timeGetTime - Start) / 1000, 0)
If List1.ListCount >= 100 Then List1.RemoveItem 99
'Calculate running average of the speed to account for fluctuations
Dim sum As Single
For i = 0 To List1.ListCount - 1
sum = sum + CSng(List1.List(i))
Next i
Me.Caption = sum / List1.ListCount
End Sub
Private Sub Form_Load()
'use API to set timer accuracy to 1 ms.
timeBeginPeriod 1
Me.Show
Me.Refresh
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
bUnload = True
End Sub
Private Sub Form_Unload(Cancel As Integer)
'use API to end timer accuracy of 1 ms.
timeEndPeriod 1
Timer1.Interval = 2000
Timer1.Enabled = False
Set Form1 = Nothing
End Sub
Private Sub Timer1_Timer()
If bUnload = True Then Timer1.Enabled = False
DrawPolygons
End Sub