# ST_Azimuth for Oracle: AKA Cogo.Bearing

Many years ago I wrote a Coordinate Geometry (COGO) package for Oracle Sdo_Geometry that contained a Bearing function that, given two points, would return the angle in radians from the horizontal of the vector defined by point A and B.

PostGIS has a similar function called “ST_Azimuth”:http://postgis.refractions.net/documentation/manual-svn/ST_Azimuth.html.

Here are the relevant declarations of the Bearing function and overloaded ST_Azimuth interfaces that implement ST_Azimuth function wrappers which would allow some level of portability between Oracle and PostGIS.

``` CREATE OR REPLACE PACKAGE "COGO"
AUTHID CURRENT_USER
As

.........

/* ----------------------------------------------------------------------------------------
** function   : Bearing
** precis     : Returns a value between 0 and 2*PI representing the bearing
**               North = 0, East = PI/2, South = PI, West = 3*PI/4
**               To convert to degrees multiply by (180/PI).
** version.   : 1.0
** usage      : FUNCTION Bearing( dE1 in number,
**                               dN1 in number,
**                               dE2 in number,
**                               dN2 in number)
**                        RETURN NUMBER DETERMINISTIC;
**               eg :new.shape := CODESYS.cogo.Bearing(299900, 5200000, 300000, 5200100);
** param      : dE1     : X Ordinate of the start point for the vector
** paramtype  : dE1     : NUMBER
** param      : dN1     : Y Ordinate of the start point for the vector
** paramtype  : dN1     : NUMBER
** param      : dE2     : X Ordinate of the end point for the vector
** paramtype  : dE2     : NUMBER
** param      : dN2     : Y Ordinate of the end point for the vector
** paramtype  : dN2     : NUMBER
** return     : Bearing : the angle in radians between 0 and 2*PI representing the bearing
** rtnType    : Bearing : NUMBER
** note       : Does not throw exceptions
** note       : Assumes planar projection eg UTM.
** @history   : Simon Greener - Feb 2005 - Original coding.
*/
Function Bearing( dE1 in number,
dN1 in number,
dE2 in number,
dN2 in number)
Return Number Deterministic;

/** Alternate binding: 1
**/
Function Bearing( startCoord in mdsys.sdo_point_type,
endCoord in mdsys.sdo_point_type)
Return Number Deterministic;

/** Alternate binding: 2
**/
Function Bearing( p_startCoord in mdsys.sdo_point_type,
p_endCoord in mdsys.sdo_point_type,
p_planar_srid in number,
p_geographic_srid in number := 8311
)
Return Number Deterministic;

/* Alternate binding for SQL/MM
**/
Function ST_Azimuth( p_startCoord in mdsys.ST_Point,
p_endCoord   in mdsys.ST_Point)
Return Number Deterministic;

.....

END Cogo;
```

Now, some examples of the use of these functions.

``` /* What happens when NULL points are provided */
SELECT COGO.Bearing(NULL,NULL)
FROM DUAL;

AZIMUTH
----------------------
NULL

1 rows selected

/* What happens if start and end point are the same? */
SELECT ROUND(COGO.Bearing(mdsys.sdo_point_type(1,2,null), mdsys.sdo_point_type(1,2,null)) / ( 2 * Constants.pi ) * 360) as degAz
FROM DUAL;

DEGAZ
----------------------
NULL

1 rows selected

/* PostGIS example */
SELECT ST_Azimuth(ST_MakePoint(1,2), ST_MakePoint(3,4))/(2*pi())*360 as degAz,
ST_Azimuth(ST_MakePoint(3,4), ST_MakePoint(1,2))/(2*pi())*360 As degAzrev

degaz  degazrev
------ ---------
45     225

/* Oracle version of PostGIS example using "native" interfaces */
SELECT ROUND(COGO.Bearing(mdsys.sdo_point_type(1,2,null), mdsys.sdo_point_type(3,4,null)) / ( 2 * Constants.pi ) * 360) as degAz,
ROUND(COGO.Bearing(mdsys.sdo_point_type(3,4,null), mdsys.sdo_point_type(1,2,null)) / ( 2 * Constants.pi ) * 360) as degAzRev
FROM DUAL;

DEGAZ                  DEGAZREV
---------------------- ----------------------
45                     225

1 rows selected

/* PostGIS example using "equivalent" ST_* interfaces */
SELECT Round(Cogo.ST_Azimuth(mdsys.ST_Point(1,2), mdsys.ST_Point(3,4))/(2*Constants.pi)*360) as degAz,
Round(Cogo.ST_Azimuth(mdsys.ST_Point(3,4), mdsys.ST_Point(1,2))/(2*Constants.pi)*360) As degAzrev
FROM dual;

DEGAZ                  DEGAZREV
---------------------- ----------------------
45                     225

1 rows selected
```

I hope this is useful to someone.