Jump to content
Sign in to follow this  
Langy

Atan2 in my App and possible speeding it all up.

Recommended Posts

Langy

To cut a long story short I'm trying to make an app that has to ready anything from 1 to a vast number of XML files from a website. I started out in vb.net (not used it much but can often muddle through apps) found that too complicated for what I wanted, then Excel but it hung every time after about 5 downloads of XML files.

So I've come to AutoIT as I use it for a fair bit of scripting to modify settings on our users computers.

One of the things I need to do in my app is read in around 6000 sites in one XML file, the user chooses one and then I need to calculate the distance and direction from the selected site for all the rest. Now those 6000 sites only really have to be loaded once as I will end up making a new XML file only storing the sites the users select.

Now when I try to load all 6000 sites to start with in the code below it starts off really quick as I can monitor it with GUICtrlSetData($lblStatus2,UBound($Sites,1)) reporting back to my splash screen. However as time goes on the records take longer and longer to get through. The whole process takes about 2 minutes. So any assistance on speeding that up would be great. Basically I need to load the sites into an array which I can then use to create a list view based on a users search criteria.

For $oLocations In $oXML.selectNodes("/Locations")
      $sDirRefID = $oLocations.getAttribute("id")
      For $oSite In $oLocations.selectNodes("Location")
         $Sites[UBound($Sites,1)-1][0] = $oSite.getAttribute("id")
         $Sites[UBound($Sites,1)-1][1] = $oSite.getAttribute("name")
         $Sites[UBound($Sites,1)-1][2] = $oSite.getAttribute("latitude")
         $Sites[UBound($Sites,1)-1][3] = $oSite.getAttribute("longitude")
         $Sites[UBound($Sites,1)-1][4] = $oSite.getAttribute("elevation")
         $Sites[UBound($Sites,1)-1][5] = $oSite.getAttribute("region")
         $Sites[UBound($Sites,1)-1][6] = $oSite.getAttribute("unitaryAuthArea")
         $Sites[UBound($Sites,1)-1][7] = $oSite.getAttribute("nationalPark")
         
         If Int(UBound($Sites,1)/100) = UBound($Sites,1)/100 Then
            GUICtrlSetData($lblStatus2,UBound($Sites,1))
         EndIf
                 
         ReDim $Sites[UBound($Sites,1)+1][10]

      Next
   Next

So my next dilema which I spent several hours on today was to work out the distance and direction between the sites. That took me a few hours in Excel to start with and converting the distance to AutoIT was quite easy as in the code below.

Func Distance($LatD,$LongD)

   $HomeLat = 54.9425
   $HomeLong = -2.7349

   $rad1 = _Radian(90-$HomeLat)
   $cos1 = Cos($rad1)
   $sin1 = Sin($rad1)

   $DISTANCE = ACos(Cos(_Radian(90-$HomeLat))*Cos(_Radian(90-$LatD))+Sin(_Radian(90-$HomeLat))*Sin(_Radian(90-$LatD))*Cos(_Radian($HomeLong-$LongD)))*6371

   Return $DISTANCE

EndFunc

The next thing was the direction. I got a nice script running at work using the _Atlan2 code that was in math.au3. However I've installed a newer version of AutoIT at home on my laptop and went to run the code tonight only to find the _Atlan2 has been removed. So some hunting around on actual equations and I've come up with below to replace it. Any thoughts on this from anyone most appreciated.

Func Direction($LatD,$LongD)

   $HomeLat = 54.9425
   $HomeLong = -2.7349

   $y = $HomeLat - $LatD
   $x = $HomeLong - $LongD
   $bear = ATan2($y,$x)
   $degB = 180 + _Degree($bear)

   Return $degB

EndFunc

Func ATan2($x, $y)
   Local Const $PI = 3.14159265358979
   If $x > 0 Then
      Return ATan($y / $x)
   ElseIf $x < 0 Then
      Return ATan($y / $x) - _Radian(180)
   ElseIf $x = 0 Then
      If $y > 0 Then
         Return 90
      ElseIf $y < 0 Then
         Return -90
      ElseIf $y=0 Then
         Return 0
      EndIf
   Else
      MsgBox( 16, "Error - Division by zero", "Domain Error in Function: ATan2()" & @LF & "$x and $y cannot both equal zero" )
      SetError( 1 )
   EndIf
 EndFunc

I'm not a newbie, but can get most basic programming done in vb, vba, asp, asp.net and AutoIT to name a few. I may not set the procedures out like hardcore programmers, but it works and always willing to learn. I find that you learn more when faced with problems like this where you have to find an answer.

Thanks in advance for any assistance.

Share this post


Link to post
Share on other sites
Bowmore

This should solve your first problem, the slow load. ReDim is a slow function so it's best to not use it every time you add a new record. Add new array space in big blocks and remove any unused rows when you have finished loading.  

Local $iSite = 0
   Local $Sites[5000][10] ;Make the array big enough to hold the estimated number of rows
   $iSitesMaxIdx = UBound($Sites,1)-1 ; save the size of array so you don't have to call UBound all the time
   
   For $oLocations In $oXML.selectNodes("/Locations")
      $sDirRefID = $oLocations.getAttribute("id")
      For $oSite In $oLocations.selectNodes("Location")
         $Sites[$iSite][0] = $oSite.getAttribute("id")
         $Sites[$iSite][1] = $oSite.getAttribute("name")
         $Sites[$iSite][2] = $oSite.getAttribute("latitude")
         $Sites[$iSite][3] = $oSite.getAttribute("longitude")
         $Sites[$iSite][4] = $oSite.getAttribute("elevation")
         $Sites[$iSite][5] = $oSite.getAttribute("region")
         $Sites[$iSite][6] = $oSite.getAttribute("unitaryAuthArea")
         $Sites[$iSite][7] = $oSite.getAttribute("nationalPark")
             
         If Int($iSite/100) = $iSite/100 Then
            GUICtrlSetData($lblStatus2,$iSite)
         EndIf
        if $iSitesMax = $iSitesMaxIdx Then
            ;if array is full 
            ;add another 1000 rows
            $iSitesMaxIdx += 1000
            ReDim $Sites[$iSitesMaxIdx][10]
        EndIf
        ;ncrement array index
        $iSite += 1
      Next
  Next
 
 ;remove unused rows
  ReDim $Sites[$iSite][10]

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to build bigger and better idiots. So far, the universe is winning."- Rick Cook

Share this post


Link to post
Share on other sites
czardas

Here's the old _ATan2() code by Nutster, in case you don't have it. I don't know why it would have been removed.

<REMOVED>

;

Edited by czardas

Share this post


Link to post
Share on other sites
Langy

 

This should solve your first problem, the slow load. ReDim is a slow function so it's best to not use it every time you add a new record. Add new array space in big blocks and remove any unused rows when you have finished loading.  

 

Thanks that helped enormously, now the whole 6000 sites loads in a couple of seconds. I do start off now with an array at 6000 and if that fills up add 100 at a time, just in case it should ever increase. Then I finally just cut it back to size when the whole xml file is loaded.

czardas, yes I could have copied the code from my machine at work, but I think that there is an issue with it as to why it was removed. I did have to modify my code a little as it could return a negative direction. I've based my code on some proper equations I found online which should cut out any errors, plus I've tested quite a few results as to that which I have in an Excel file.

Func GeoDir($LatStart,$LongStart,$LatEnd,$LongEnd)

   $y = $LatStart - $LatEnd
   $x = $LongStart - $LongEnd
   $bear = ATan2($y,$x)
   $degB = 180 + _Degree($bear)
   If $degb < 0 Then
      $degb = 360 + $degb
   EndIf

   Return $degB

EndFunc

Share this post


Link to post
Share on other sites
czardas

Ah, I remember reading something about this now. :)

Edited by czardas

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×