Public Const Pi = 3.14159265358979 Public Function Radians(x) Radians = Pi * x / 180# End Function Private Function arccos(x) arccos = Atn(-x / Sqr(-x * x + 1)) + Pi / 2 End Function Private Function arcsin(x) arcsin = Pi / 2# - arccos(x) End Function Public Function Bearing(Lat1, Lon1, Lat2, Lon2) ' Lat1, Lon1 - lat and lon for position 1 ' Lat2, Lon2 - lat and lon for position 2 ' Returns initial bearing (degrees) of great circle route from ' position 1 to position 2 ' Assumes input is North = + , East = + If (Lon1 = Lon2) Then If (Lat1 < Lat2) Then Bearing = 0# Else Bearing = 180# End If Else dd = Posdist(Lat1, -Lon1, Lat2, -Lon2) arad = arccos((Sin(Radians(Lat2)) - Sin(Radians(Lat1)) * Cos(Radians(dd / 60))) / _ (Sin(Radians(dd / 60)) * Cos(Radians(Lat1)))) Bearing = arad * 180 / Pi If (Sin(Radians(Lon2 - Lon1)) < 0) Then Bearing = 360 - Bearing End If End If End Function Public Function Posdist(Lat1, Lon1, Lat2, Lon2) ' Lat1, Lon1 - lat and lon for position 1 ' Lat2, Lon2 - lat and lon for position 2 ' Returns distance between 2 positions in nautical miles If (Lat1 = Lat2 And Lon1 = Lon2) Then Posdist = 0 Else Rlat1 = Radians(Lat1) Rlat2 = Radians(Lat2) Rlon = Radians(Lon2 - Lon1) Posdist = 60 * (180 / Pi) * arccos(Sin(Rlat1) * Sin(Rlat2) + _ Cos(Rlat1) * Cos(Rlat2) * Cos(Rlon)) End If End Function Public Function NewPosLat(Lat1, Lon1, Bearing, Distance) ' Computes latitude of a new position at a particular initial ' bearing and distance from an initial position (lat1, lon1) ' following a great circle route ' north = + east = + ' reference for formulas - std mathematical tables pg 176 ' Latitude will not be correct if looped around pole in north-south direction ' nor across the equator - possibly this could be corrected ' Lat1, Lon1 - original position in decimal degrees ' Initial bearing to new point in true degrees ' Distance to new point in nautical miles ' Returns latitude in decimal degrees for new point If (Bearing = 0 Or Bearing = 180 Or Bearing = 360) Then If (Bearing = 180) Then NewPosLat = Lat1 - Distance / 60 Else NewPosLat = Lat1 + Distance / 60 End If Else a = Radians(90 - Lat1) Rlon1 = Radians(Lon1) b = Pi * Distance / (60 * 180) CAngle = Radians(Bearing) APlusB = 2# * Atn(Cos((a - b) / 2#) / (Cos((a + b) / 2#) * Tan(CAngle / 2#))) AMinusB = 2# * Atn(Sin((a - b) / 2#) / (Sin((a + b) / 2#) * Tan(CAngle / 2#))) BAngle = (APlusB - AMinusB) / 2# Aangle = (AMinusB + APlusB) / 2# If (Lat1 < 0) Then NewPosLat = (180# * arcsin(Sin(b) * Sin(CAngle) / Sin(BAngle)) / Pi) - 90# Else NewPosLat = Abs((180# * arcsin(Sin(b) * Sin(CAngle) / Sin(BAngle)) / Pi) - 90#) End If End If If (NewPosLat > 90) Then NewPosLat = NewPosLat - 90 Else If (NewPosLat < -90) Then NewPosLat = -(NewPosLat + 180) End If End If End Function Public Function NewPosLon(Lat1, Lon1, Bearing, Distance) ' Computes longitude of a new position at a particular initial ' bearing and distance from an initial position (lat1, lon1) ' following a great circle route ' north = + east = + ' reference for formulas - std mathematical tables pg 176 ' Longitude will not be correct if taken over either pole ' Lat1, Lon1 - original position in decimal degrees ' Initial bearing to new point in true degrees ' Distance to new point in nautical miles ' Returns longitude in decimal degrees for new point If (Bearing = 0) Bearing=360 a = Radians(90 - Lat1) Rlon1 = Radians(Lon1) b = Pi * Distance / (60 * 180) CAngle = Radians(Bearing) APlusB = 2# * Atn(Cos((a - b) / 2#) / (Cos((a + b) / 2#) * Tan(CAngle / 2#))) AMinusB = 2# * Atn(Sin((a - b) / 2#) / (Sin((a + b) / 2#) * Tan(CAngle / 2#))) BAngle = (APlusB - AMinusB) / 2# Aangle = (AMinusB + APlusB) / 2# NewPosLon = Lon1 + BAngle * 180 / Pi If (NewPosLon > 180) Then NewPosLon = NewPosLon - 360 Else If (NewPosLon < -180) Then NewPosLon = NewPosLon + 360 End If End If End Function Public Function RetDist(Height, RadPerReticle, Reticles) ' Height in meters ' RaderReticle = Radians per reticle mark ' Reticles = number of reticles below horizon ' RetDist = distance in nautical miles x = Sqr(2 * 6366 * Height / 1000 + (Height / 1000) ^ 2) If (Reticles = 0) Then RetDist = x / 1.852 Else Angle = Atn(x / 6366) RetDist = (1 / 1.852) * ((6366 + Height / 1000) * Sin(Angle + Reticles * RadPerReticle) - _ Sqr(6366 ^ 2 - ((6366 + Height / 1000) * Cos(Angle + Reticles * RadPerReticle)) ^ 2)) End If End Function Public Function RetDist7x50(Height, Reticles) ' Height in meters ' RadPerReticle = Radians per reticle mark ' Reticles = number of reticles below horizon ' RetDist = distance in nautical miles RadPerReticle = 0.00497 RetDist7x50 = RetDist(Height, RadPerReticle, Reticles) End Function Public Function RetDistBE(Height, Reticles) ' Height in meters ' RadPerReticle = Radians per reticle mark ' Reticles = number of reticles below horizon ' RetDist = distance in nautical miles RadPerReticle = 0.00136 RetDistBE = RetDist(Height, RadPerReticle, Reticles) End Function Public Function MinSecToDeg(MinSec) ' Converts position field from degrees.minutes seconds ' specified as deg.mmss (e.g., 36 degrees, 58 minutes and 34 seconds is ' 36.5834 )to decimal degrees xMinSec = Abs(MinSec) MinSecToDeg = Sign(MinSec) * (Int(xMinSec) + Int((xMinSec - Int(xMinSec)) * 100 + 0.00001) _ / 60 + 100 * (xMinSec * 100 - Int(xMinSec * 100 + 0.00001)) / 3600) End Function Public Function DegToMinSec(DecDeg) ' Converts position field from decimal degrees to ' degrees.minutes seconds (deg.mmss) xDecDeg = Abs(DecDeg) Ideg = Int(xDecDeg) Decim = xDecDeg - Ideg imin = Int(Decim * 60) isec = Int((Decim * 60 - imin) * 60 + 0.5) DegToMinSec = Sign(DecDeg) * (Ideg + imin / 100 + isec / 10000) End Function Public Function DegToMinTen(DecDeg) ' Converts position field from decimal degrees to degrees.minutes tenths ' specified as deg.mmtt xDecDeg = Abs(DecDeg) Ideg = Int(xDecDeg) Decim = xDecDeg - Ideg imin = Decim * 0.6 DegToMinTen = Sign(DecDeg) * (Ideg + imin) End Function Public Function MinTenToDeg(MinTen) ' Converts position field from degrees.minutes hundreds of minutes ' specified as deg.mmtt (e.g., 36 degrees, 58.77 minutes is ' 36.5877 )to decimal degrees xMinTen = Abs(MinTen) MinTenToDeg = Sign(MinTen) * (Int(xMinTen) + Int((xMinTen - Int(xMinTen)) * 100 + 0.00001) / 60 + _ 100 * (xMinTen * 100 - Int(xMinTen * 100 + 0.00001)) / 6000) End Function Public Function ClinoDist(Altitude, Angle) ' Computes ground distance from altitude and angle from horizon ' Distance units are the same as altitude units ClinoDist = Altitude * Tan(Radians(90 - Angle)) End Function Public Function ClinoArcDist(Altitude, Angle) ' Computes ground distance from altitude and angle from horizon ' Altitude should be specified in meters ' Output distance units are nautical miles EarthRadius = 3440 Height = Altitude / 1852 Alpha = ((2 * Height * EarthRadius + Height ^ 2) ^ 0.5) / EarthRadius If (Radians(Angle) < Alpha) Then ClinoArcDist = "Beyond horizon" Else ClinoArcDist = EarthRadius * (Radians(Angle) - arccos((EarthRadius + Height) * Cos(Radians(Angle)) / EarthRadius)) End If End Function Public Function DistRet(Height, RadPerReticle, Distance) ' Height in meters ' RaderReticle = Radians per reticle mark ' Distance = distance in nautical miles ' DistRet = number of reticles from the horizon x1 = Distance / (6366 / 1.852) Angle = arccos(6366 / (6366 + Height / 1000)) x2 = (x1 - Angle) ^ 2 / (2 * x1) DistRet = x2 / RadPerReticle End Function Public Function SASB(b, a, c) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' SASB - returns angle B SideA = SASa(b, a, c) SASB = 180 * arccos((c ^ 2 - b ^ 2 + SideA ^ 2) / (2 * c * SideA)) / Pi End Function Public Function SASC(b, a, c) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' SASC - returns angle C SideA = SASa(b, a, c) SASC = 180 * arccos((b ^ 2 - c ^ 2 + SideA ^ 2) / (2 * SideA * b)) / Pi End Function Public Function SASa(b, a, c) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' SASa - returns length of a SASa = (b ^ 2 + c ^ 2 - 2 * b * c * Cos(Radians(a))) ^ 0.5 End Function Public Function ASAb(b, a, c) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' ASAb - returns length of b AngleA = 180 - b - c ASAb = a * Sin(Radians(b)) / Sin(Radians(AngleA)) End Function Public Function ASAc(b, a, c) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' ASAc - returns length of c AngleA = 180 - b - c ASAc = a * Sin(Radians(c)) / Sin(Radians(AngleA)) End Function Public Function SSSA(a, b, c) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' SSSA - returns angle A SSSA = 180 * arccos((b ^ 2 + c ^ 2 - a ^ 2) / (2 * b * c)) / Pi End Function Public Function SSSB(a, b, c) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' SSSB - returns angle B SSSB = 180 * arccos((a ^ 2 + c ^ 2 - b ^ 2) / (2 * a * c)) / Pi End Function Public Function SSSC(a, b, c) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' SSSC - returns angle C SSSC = 180 * arccos((a ^ 2 + b ^ 2 - c ^ 2) / (2 * a * b)) / Pi End Function Public Function SSAC(a, c, AngleA) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' SSAC - returns angle C SSAC = 180 * arcsin(c * Sin(Radians(AngleA)) / a) / Pi End Function Public Function SSAB(a, c, AngleA) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' SSAB - returns angle B SSAB = 180 - AngleA - SSAC(a, c, AngleA) End Function Public Function SSASb(a, c, AngleA) ' Triangle with sides a,b,c and angles A,B,C ' Angle A is between b and c opposite a ' Angle B is between c and a opposite b ' Angle C is between a and b opposite c ' SSASB - returns side b SSASb = a * Sin(Radians(SSAB(a, c, AngleA))) / Sin(Radians(AngleA)) End Function Function ClosestDistance(x1, y1, x2, y2, xp, yp) ' Computes the closest distance between a point (xp,yp) and the line ' segment defined by the points (x1,y1) and (x2,y2). Slope = (y2 - y1) / (x2 - x1) Int1 = y1 - x1 * Slope Int2 = yp + xp / Slope x0 = (Int2 - Int1) * Slope / (Slope ^ 2 + 1) y0 = Int2 - x0 / Slope If (y1 <> y2) Then If ((y0 - y1) * Sign(y2 - y1) < 0) Then ClosestDistance = ((yp - y1) ^ 2 + (xp - x1) ^ 2) ^ 0.5 ElseIf ((y0 - y2) * Sign(y2 - y1) > 0) Then ClosestDistance = ((yp - y2) ^ 2 + (xp - x2) ^ 2) ^ 0.5 Else ClosestDistance = ((yp - y0) ^ 2 + (xp - x0) ^ 2) ^ 0.5 End If Else If ((x0 - x1) * Sign(x2 - x1) < 0) Then ClosestDistance = ((yp - y1) ^ 2 + (xp - x1) ^ 2) ^ 0.5 ElseIf ((x0 - x2) * Sign(x2 - x1) > 0) Then ClosestDistance = ((yp - y2) ^ 2 + (xp - x2) ^ 2) ^ 0.5 Else ClosestDistance = ((yp - y0) ^ 2 + (xp - x0) ^ 2) ^ 0.5 End If End If End Function Function Sign(x) ' Sign function - if x<0 = -1, else 1 If (x < 0) Then Sign = -1 Else Sign = 1 End If End Function