<?php # -*- PHP -*-

#
#  Thy (english) reference is the original  Fortran  code!
#  

#
#  Tämä aliohjelma laskee ns. "geodeettisen
#  käänteisfunktion ongelman" tavalla, jonka
#  ensimmäinen esittäjä on  T.Vincenty.
#  Tämä on muunnelma Rainsford:n menetelmästä
#  käyttäen Helmert:n elliptisiä termejä.
#
#  Tämä toimii kaikkiin suuntiin ja etäisyyksiin
#  lukuunottamatta ns. antipodal tilannetta, eli
#  että pisteet ovat täsmälleen vastakkaisilla
#  puolilla.  Lähde-/kohdepiste ei saa myöskään
#  olla navalla.
#

#
#  Input:  $WGS1[La]    Source Latitude,  WGS84, radians
#          $WGS1[Lo]    Source Longitude, WGS84, radians
#          $WGS2[La]    Destination Latitude,  WGS84, radians
#          $WGS2[Lo]    Destination Longitude, WGS84, radians
#          $EL[a]       Reference ellipsoid semimajor axis
#          $EL[f]       Reference ellipsoid flattening
#
#  Example ellipsoid:
#          $EL[a] = 6378137.0
#          $EL[f] = 1.0/298.25722210088
#             a.k.a. 'GRS80'
#          $EL[a] = 6378137.0
#          $EL[f] = 1.0/298.257223563
#             a.k.a. 'WGS84'
#
#  Output: $R[Az]       Az from source to dest, north 0, clockwise, 0..2*Pi
#          $R[rAz]      Az from dest to source, ...  (in radians)
#          $R[dist]     Distance in ellipsoidal units (Depends on what
#                       units you use for  $EL[a]:  meters/miles... )
#

function ellipsoidal_great_circle($WGS1$WGS2$EL) {

    global 
$Debug;

    
$iter 40;

    
$epsilon 0.5E-13;
    
$r 1.0 $EL[f];

    if (
abs($WGS1[La] - $WGS2[La]) < $epsilon &&
        
abs($WGS1[Lo] - $WGS2[Lo]) < $epsilon) {
        
$R[Az]   = 0.0;
        
$R[rAz]  = 0.0;
        
$R[dist] = 0.0;
        return 
$R;
    }

    
#
    # Formulate initial estimates
    #
    
$tu1 $r sin($WGS1[La])/cos($WGS1[La]);
    
$tu2 $r sin($WGS2[La])/cos($WGS2[La]);
    
$cu1 1.0 sqrt($tu1 $tu1 1.0);
    
$su1 $cu1 $tu1;
    
$cu2 1.0 sqrt($tu2 $tu2 1.0);
    
$s $cu1 $cu2;
    
$baz $s $tu2;
    
$faz $baz $tu1;
    
$x $WGS2[Lo] - $WGS1[Lo];
    
#
    # Now iterate until the error is below 'epsilon'.
    #

    
while (--$iter 0) { # Max limit, usually 3-4 rounds..

        
$sx sin($x);
        
$cx cos($x);
        
$tu1 $cu2 $sx;
        
$tu2 $baz $su1 $cu2 $cx;
        
$sy sqrt($tu1 $tu1 $tu2 $tu2);
        
$cy $s $cx $faz;
        
$y atan2($sy,$cy);
        
$sa $s $sx $sy;
        
$c2a 1.0 $sa $sa;
        
$cz $faz $faz;
        if (
$c2a 0.0)
            
$cz $cy $cz/$c2a;
        
$e $cz $cz 2.0 1.0;
        
$c = ((4.0 3.0 $c2a) * $EL[f] + 4.0)
            * 
$c2a $EL[f] / 16.0;

        
$d $x# Previous version of X
        
$x = (($e $cy $c $cz) * $sy $c $y) * $sa;
        
$x = (1.0 $c) * $x $EL[f] + $WGS2[Lo] - $WGS1[Lo];

        if (
$Debug)
            
printf("ellip-GCD: x-x'/epsilon = %f\n",($d-$x)/$epsilon);

        if (
abs($d-$x) < $epsilon) break;
    }
    
$faz atan2($tu1,$tu2);
    
$baz atan2($cu1 $sx$baz $cx $su1 $cu2) + M_PI;
    
$x sqrt(((1.0 / ($r $r)) - 1.0) * $c2a 1.0) + 1.0;
    
$x = ($x 2.0) / $x;
    
$c 1.0 $x;

    
$xx $x $x;
    
$c = ($xx 4.0 1.0) / $c;
    
$d = (0.375 $xx 1.0) * $x;

    
$x $e $cy;

    
$s 1.0 $e $e;
    
$s = (((($sy $sy 4.0 3.0)
            * 
$s $cz $d 6.0 $x)
           * 
$d 4.0 $cz)
          * 
$sy $d $y)
        * 
$c $EL[a] * $r;

    
# Normalize into  0..2Pi  range
    
if ($faz 0$faz += M_PI M_PI;
    if (
$baz 0$baz += M_PI M_PI;

    
$R[dist] = $s;
    
$R[Az]   = $faz;
    
$R[rAz]  = $baz;

    return 
$R;
}



#       SUBROUTINE INVER1(GLAT1,GLON1,GLAT2,GLON2,FAZ,BAZ,S)
# C
# C *** SOLUTION OF THE GEODETIC INVERSE PROBLEM AFTER T.VINCENTY
# C *** MODIFIED RAINSFORD'S METHOD WITH HELMERT'S ELLIPTICAL TERMS
# C *** EFFECTIVE IN ANY AZIMUTH AND AT ANY DISTANCE SHORT OF ANTIPODAL
# C *** STANDPOINT/FOREPOINT MUST NOT BE THE GEOGRAPHIC POLE
# C
# C *** A IS THE SEMI-MAJOR AXIS OF THE REFERENCE ELLIPSOID
# C *** F IS THE FLATTENING (NOT RECIPROCAL) OF THE REFERNECE ELLIPSOID
# C *** LATITUDES AND LONGITUDES IN RADIANS POSITIVE NORTH AND EAST
# C *** FORWARD AZIMUTHS AT BOTH POINTS RETURNED IN RADIANS FROM NORTH
# C
# C *** PROGRAMMED FOR CDC-6600 BY LCDR L.PFEIFER NGS ROCKVILLE MD 18FEB75
# C *** MODIFIED FOR IBM SYSTEM 360 BY JOHN G GERGEN NGS ROCKVILLE MD 7507
# C
#       IMPLICIT REAL*8 (A-H,O-Z)
#       COMMON/CONST/PI,RAD
#       COMMON/ELIPSOID/A,F
#       DATA EPS/0.5D-13/
#       R=1.D0-F
#       TU1=R*DSIN(GLAT1)/DCOS(GLAT1)
#       TU2=R*DSIN(GLAT2)/DCOS(GLAT2)
#       CU1=1./DSQRT(TU1*TU1+1.)
#       SU1=CU1*TU1
#       CU2=1./DSQRT(TU2*TU2+1.)
#       S=CU1*CU2
#       BAZ=S*TU2
#       FAZ=BAZ*TU1
#       X=GLON2-GLON1
#   100 SX=DSIN(X)
#       CX=DCOS(X)
#       TU1=CU2*SX
#       TU2=BAZ-SU1*CU2*CX
#       SY=DSQRT(TU1*TU1+TU2*TU2)
#       CY=S*CX+FAZ
#       Y=DATAN2(SY,CY)
#       SA=S*SX/SY
#       C2A=-SA*SA+1.
#       CZ=FAZ+FAZ
#       IF(C2A.GT.0.)CZ=-CZ/C2A+CY
#       E=CZ*CZ*2.-1.
#       C=((-3.*C2A+4.)*F+4.)*C2A*F/16.
#       D=X
#       X=((E*CY*C+CZ)*SY*C+Y)*SA
#       X=(1.-C)*X*F+GLON2-GLON1
#       IF(DABS(D-X).GT.EPS) GO TO 100
#       FAZ=DATAN2(TU1,TU2)
#       BAZ=DATAN2(CU1*SX,BAZ*CX-SU1*CU2)+PI
#       X=DSQRT((1./R/R-1.)*C2A+1.)+1.
#       X=(X-2.)/X
#       C=1.-X
#       C=(X*X/4.+1.)/C
#       D=(0.375*X*X-1.)*X
#       X=E*CY
#       S=1.-E-E
#       S=((((SY*SY*4.-3.)*S*CZ*D/6.-X)*D/4.+CZ)*SY*D+Y)*C*A*R
#       RETURN
#       END


if ($_REQUEST["SOURCE"] != "" || $_REQUEST["source"] != "") {
    
printf("\n<FONT SIZE=1>\n");
    
# highlight_file("geodinver.php");
    
show_source("geodinver.php");
    
printf("</FONT><P><HR><P>\n");
    include(
"../include/sign-oh2mqk.inc");
    
printf("<P></TR></TABLE>\n");
    include(
"../include/base.inc");
    include(
"../include/foot.inc"); 
    exit;
}



?>


Matti Aarnio <matti.aarnio@zmailer.org>; OH2MQK

 

Valid HTML 4.01!   Z Elisa Communications
This page is Links enhanced for additional browsing pleasure.