Question Openedge Math Functions

Potish

Member
I need to compute the distance between two locations using their Latitude and Longitude. I found the javascript under the link below that can do this and I am trying to convert this to progress code.

Link to Javascript code is
Finding distances based on Latitude and Longitude

Javascript code is
Code:
dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
c = 2 * atan2( sqrt(a), sqrt(1-a) )
d = R * c (where R is the radius of the Earth)

I did find the link below that shows how to setup up the Sin and Cos functions in openedge
Progress KB - How to use trigonometric functions in ABL on Microsoft Windows systems

I am not able to complete the code in progress because I have not been able to determine how to setup the ^ and atan2 in openedge. Looking for suggestions on how to get these two operators in openedge.

I am running openedge 11.1 on windows
 

joey.jeremiah

ProgressTalk Moderator
Staff member
the slibmath.p library, in the progress standard libraries project, at the oehive.org has 100% progress tan, cos, sin etc. functions.
 

Cringer

ProgressTalk.com Moderator
Staff member
You can also make use of the maths functions in the windows .net framework.
 

TomBascom

Curmudgeon
^ is exponentiation -- the exp() function provides that. IOW 5^2 is the same as exp( 5, 2 ).

sqrt( x ) is the same as exp( x, 0.5 ).
 

Potish

Member
^ is exponentiation -- the exp() function provides that. IOW 5^2 is the same as exp( 5, 2 ).

sqrt( x ) is the same as exp( x, 0.5 ).

Thank you. I think I just need to the progress equivalent of atan2 and I should be able to complete the code.
 

Cecil

19+ years progress programming and still learning.
Me, being crap'ish at maths, this is the sort of thing I like doing of translating other programming languages into the ABL. I understand your problem about some of the limiting factors of the language. Anyway I found some PHP code which I think might be easier to convert into ABL code as is does not use atan2 function. The PHP code does use some unique functions but I believe that they would be simple enough to code.

Calculate Distance by Latitude and Longitude using PHP
 

Cecil

19+ years progress programming and still learning.
Here is my version of the PHP code written in the ABL. I will be the first to admit it looks like dogs breakfast as I have not done any commenting, naming conventions. It just a proof of concept, however it does seem to work and the results are comparable to that of the PHP code. MORE TESTING IS NEEDED!

It's standalone code with no dependences (i.e. includes, dll etc.)

Code:
&GLOBAL-DEFINE pi 3.141592653

DEFINE VARIABLE ACOS_TABLE AS decimal  EXTENT 278 INITIAL [255, 254, 252, 251, 250, 249, 247, 246, 245, 243, 242, 241, 240, 238, 237, 236, 234, 233, 232, 231, 229, 228, 227, 225, 224, 223,
  221, 220, 219, 217, 216, 215, 214, 212, 211, 210, 208, 207, 206, 204, 203, 201, 200, 199, 197, 196, 195, 193, 192, 190, 189, 188,
  186, 185, 183, 182, 181, 179, 178, 176, 175, 173, 172, 170, 169, 167, 166, 164, 163, 161, 160, 158, 157, 155, 154, 152, 150, 149,
  147, 146, 144, 142, 141, 139, 137, 135, 134, 132, 130, 128, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, 105, 103, 101,
  98, 96, 94, 92, 89, 87, 84, 81, 79, 76, 73, 73, 73, 72, 72, 72, 71, 71, 71, 70, 70, 70, 70, 69, 69, 69, 68, 68, 68, 67, 67, 67,
  66, 66, 66, 65, 65, 65, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 61, 60, 60, 59, 59, 59, 58, 58, 58, 57, 57, 57, 56, 56, 55,
  55, 55, 54, 54, 53, 53, 53, 52, 52, 51, 51, 51, 50, 50, 49, 49, 48, 48, 47, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41,
  41, 40, 40, 39, 39, 38, 37, 37, 36, 36, 35, 34, 34, 33, 33, 32, 31, 31, 30, 29, 28, 28, 27, 26, 25, 24, 23, 23, 23, 23, 22, 22,
  22, 22, 21, 21, 21, 21, 20, 20, 20, 19, 19, 19, 19, 18, 18, 18, 17, 17, 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 13, 13, 13, 12,
  12, 11, 11, 10, 10, 9, 9, 8, 7, 6, 6, 5, 3, 0.5 ,0].


function factorial returns decimal (input num as integer):

    define variable factorial as decimal no-undo.
  
    if num le 1 then return 1.
  
    factorial = num * factorial(num - 1).

    return factorial.

end function.

function sin return decimal (input num as dec):

    define variable sin      as decimal no-undo.
    define variable degree   as decimal no-undo.
    define variable pwrSeven as decimal no-undo.
    define variable pwrFive  as decimal no-undo.
    define variable pwrThree as decimal no-undo.
  
    degree = (num * {&pi}) / 180.
  
    pwrSeven = exp(degree, 7).
    pwrFive  = exp(degree, 5).
    pwrThree = exp(degree, 3).
  
    sin = (degree - (pwrThree / 6) + (pwrFive / 120) - ( pwrSeven / 5040) ).
  
    return sin.

end function.

function cos returns dec (input num as dec ):

    define var radian    as dec no-undo.
    define var delta   as dec no-undo.
    define var sumCos  as dec no-undo.
    define var i       as int no-undo.

    assign
        radian  = num
        delta   = 1
        sumCos  = 1
        i       = 0.

    repeat:

        assign
            i       = i + 1
            delta  = ( - delta ) * ( radian * radian ) / ( ( 2 * i - 1 ) * ( 2 * i ) )
            sumCos = sumCos + delta.

        if abs( delta)           lt 0.0000000001  or
           abs( sumCos / delta ) gt 10000000000.0 then
           leave.

    end.

    return sumCos.

end function.

function acos returns dec (input num as dec ):

    define var rads as dec no-undo.
    define var negative as logical no-undo.

    if num < 0 then
        ASSIGN
           negative = true
           num = num * -1.
          
  case true:
    when (num Ge 0 and num lt 0.9) then
        rads = ACOS_TABLE[ int((num * 10000 / 79) ) + 1] * 0.006032438.
  
    when (num ge 0.9 and num lt 0.99) then
        rads = ACOS_TABLE[ int((num * 10000 - 9000) / 8) + 115] * 0.006032438.
      
    when (num ge 0.99 and num le 1) then
        rads = ACOS_TABLE[ int((num * 10000 - 9900) / 2) + 228] * 0.006032438.          
  
  end case.

  if(negative) then
    rads = {&pi} - rads.


  return rads.
  
end function.


function rad2deg returns dec (input radians as dec ):

    return radians * 180 / {&pi}.

end function.

function deg2rad returns dec (input degrees as dec ):

    return degrees * {&pi} / 180.

end function.


function distance returns decimal(input latitudeAlpha   as decimal,
                                  input longitudeAlpha  as decimal,
                                  input latitudeBeta    as decimal,
                                  input longitudeBeta   as decimal,
                                  input unit            as character):
                                
                
    define var theta  as dec no-undo.
    define var dist   as dec no-undo.
    define var miles  as dec no-undo.

    theta = longitudeAlpha - longitudeBeta.
  
    dist = sin(latitudeAlpha) * sin(latitudeBeta) +
           cos(deg2rad(latitudeAlpha)) * cos(deg2rad(latitudeBeta)) *
           cos(deg2rad(theta)).

    dist = acos(dist).

    dist = rad2deg(dist).
  
    miles = dist * 60 * 1.1515.
  
    case CAPS(unit):
        when "K" then
            dist = miles * 1.609344.
        when "N" then
            dist = miles * 0.8684.
        otherwise
            dist = miles.      
    end case.
              
    return dist.                
                
end function.                

message distance(32.9697, -96.80322, 29.46786, -98.53506, "K") skip.
 
Last edited:

Cecil

19+ years progress programming and still learning.
After doing some more testing it does seem that the code is a bit week as distance are not being calculated correctly for small short distance and this is due to the acos function using a lookup array. A better acos function is needed.
 
I need to compute the distance between two locations using their Latitude and Longitude. I found the javascript under the link below that can do this and I am trying to convert this to progress code.

Link to Javascript code is
Finding distances based on Latitude and Longitude

Javascript code is
Code:
dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
c = 2 * atan2( sqrt(a), sqrt(1-a) )
d = R * c (where R is the radius of the Earth)

I did find the link below that shows how to setup up the Sin and Cos functions in openedge
Progress KB - How to use trigonometric functions in ABL on Microsoft Windows systems

I am not able to complete the code in progress because I have not been able to determine how to setup the ^ and atan2 in openedge. Looking for suggestions on how to get these two operators in openedge.

I am running openedge 11.1 on windows

If you don't need too much precision, here a very simple aproximation to atan2 (not valdiated for me) Atan2 Faster Approximation
Code:
r = atan2 (y,x) in radians
-------------
a := min (|x|, |y|) / max (|x|, |y|)
s := a * a
r := ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a
if |y| > |x| then r := 1.57079637 - r
if x < 0 then r := 3.14159274 - r
if y < 0 then r := -r
 

LarryD

Active Member
I realize this was Windows, but for those who are interested here is what we use in Linux to do this calculation:

Code:
PROCEDURE calc_distance.

def input parameter Lat1 as dec decimals 8 no-undo.
def input parameter Lon1 as dec decimals 8 no-undo.
def input parameter Lat2 as dec decimals 8 no-undo.
def input parameter Lon2 as dec decimals 8 no-undo.
def output parameter the_miles as dec no-undo.

def var sinlat1 as dec no-undo.
def var sinlat2 as dec no-undo.
def var coslat1 as dec no-undo.
def var coslat2 as dec no-undo.
def var coslon as dec no-undo.
def var acosl as dec no-undo.
def var rdiv as dec decimals 8 no-undo.

rdiv = 57.29577951.

assign lat1 = lat1 / rdiv
       lat2 = lat2 / rdiv
       lon1 = lon1 / rdiv
       lon2 = lon2 / rdiv.

/*
ACOS( SIN(Lat1) * SIN(Lat2) + COS(Lat1) * COS(Lat2) * COS(lon2 - lon1) )
       * 3956.547.
*/


run sin(lat1, output sinlat1).
run sin(lat2, output sinlat2).
run cos(lat1, output coslat1).
run cos(lat2, output coslat2).
run cos(lon2 - lon1, output coslon).
run acos( sinlat1 * sinlat2 + coslat1 * coslat2 * coslon, output acosl ).


the_miles = acosl * 3956.547.

RETURN.

END PROCEDURE.

PROCEDURE sin EXTERNAL "/usr/lib64/libm.so" CDECL:
    DEFINE INPUT PARAMETER dblValue AS DOUBLE NO-UNDO.
    DEFINE RETURN PARAMETER dblResult AS DOUBLE NO-UNDO.
END PROCEDURE.


PROCEDURE cos EXTERNAL "/usr/lib64/libm.so" CDECL:
    DEFINE INPUT PARAMETER dblValue AS DOUBLE NO-UNDO.
    DEFINE RETURN PARAMETER dblResult AS DOUBLE NO-UNDO.
END PROCEDURE.

PROCEDURE acos EXTERNAL "/usr/lib64/libm.so" CDECL:
    DEFINE INPUT PARAMETER dblValue AS DOUBLE NO-UNDO.
    DEFINE RETURN PARAMETER dblResult AS DOUBLE  NO-UNDO.
END PROCEDURE.
 
Last edited:
Top