# Functions

The functions described below are implemented without having an operator. If you are missing some functions, see operators and use the operators.

## Area function

The `area` function returns the area of a spherical object in square radians. Supported data types are: `scircle`, `spolygon`, `sbox`, `smoc`. The polygon should be convex, otherwise the behaviour is undefined.

### Area of a spherical circle as a multiple of &pg_pgr;

    sql> SELECT area( scircle '<(0d,90d),60d>' ) / pi() AS area;
     area
    ------
     1
    (1 row)

### Area of a Multi-Order Coverage (MOC) object

    sql> SELECT area(smoc '0/1-3');
           area
    -------------------
     3.141592653589793
    (1 row)

## `spoint` functions

### Longitude and latitude

The functions

                    long
                      spoint p

                    lat
                      spoint p

returns the longitude or latitude value of a spherical position `p` in radians.

#### Get the longitude and latitude of a spherical point in degrees

    sql> SELECT long ( spoint '(10d,20d)' ) * 180.0 / pi() AS longitude;
     longitude
    ------------
     10
    (1 row)

    sql> SELECT lat ( spoint '(10d,20d)' ) * 180.0 / pi() AS latitude;
     latitude
    ----------
     20
    (1 row)

### Cartesian coordinates

The functions

                    x
                      spoint p

                    y
                      spoint p

                    z
                      spoint p

return the Cartesian `x`, `y` or `z` value of a spherical position `p`. The returned values are always between `-1.0` and `+1.0`.

#### Get the Cartesian `z`-value of a spherical point

    sql> SELECT z ( spoint '(10d,-90d)' ) AS z;
     z
    ----
     -1
    (1 row)

You can get a `float8` array of Cartesian values using the function

                    xyz
                      spoint p

#### Get the Cartesian values of a spherical point

    sql> SELECT xyz ( spoint '(0d,0d)' ) AS cart;
      cart
    ---------
     {1,0,0}
    (1 row)

### Point-within-distance function

The function

                    spoint_dwithin
                      spoint p1
                      spoint p2
                      float8 radius

returns a boolean value that signifies whether the points `p1` and `p2` lie within distance `radius` (in radians) of each other, i.e. it computes the boolean expression `p1 <-> p2 <= radius`. On PostgreSQL 12 and later, the function has `GiST` support and the PostgreSQL optimizer will transform it to either `p1 <@ scircle(p2, radius)` or `p2 <@ scircle(p1, radius)` where appropriate.

#### Efficiently join two tables of points with some fuzziness permitted

    sql> SELECT * FROM stars1 JOIN stars2 WHERE spoint_dwithin(stars1.s, stars2.s, 1e-5);

## `strans` functions

### Converting to ZXZ

Using the function `strans_zxz(strans),` you can convert an Euler transformation to `ZXZ` axes transformation.

#### Change the transformation axes to `ZXZ`

Convert the transformation `strans '20d, -270d, 70.5d, XZY'` to a `ZXZ` transformation.

    sql> SELECT strans_zxz ( strans '20d, -270d, 70.5d, XZY' );

### Angles and axes

It is possible to get the components of an Euler transformation.

### Getting Euler transformation attributes

function | description
`phi` | first angle of a transformation
`theta` | second angle of a transformation
`psi` | third angle of a transformation
`axes` | transformation axes as a three letter code

The angles will always returned as a `float8` value in radians. The axes are returned as a three letter code.

#### Get the second axis and its rotation angle

    sql> SELECT theta( strans '20d,30d,40d,XZY' ) * 180 / pi() AS theta;
     theta
    -------
     30
    (1 row)
    sql> SELECT substring ( axes ( strans '20d,30d,40d,XZY' ) from 2 for 1 ) AS axis;
     axis
    ------
      Z
    (1 row)

## scircle functions

You can get the radius of a spherical circle in radians using the `radius` function. The center of the circle is available with the operator `@@` (op.center).

### Radius of a spherical circle in degrees

    sql> SELECT 180.0 * radius( scircle '<(0d,90d),60d>' ) / pi() AS radius;
     radius
    --------
         60
    (1 row)

## `sellipse` functions

pgSphere provides 4 functions to get the parameters of a spherical ellipse:

## Getting spherical ellipse attributes

function | description
`lrad` | the major radius of the ellipse
`srad` | the minor radius of the ellipse
`center` | the center of the ellipse
`inc` | the inclination of the ellipse

To get the ellipse center, you can use the operator `@@` (op.center) instead of using the function `center(sellipse)`.

### Get the minor radius of an ellipse

    sql> SELECT srad ( sellipse '< { 10d, 5d }, ( 20d, 0d ), 90d >' )
            * 180.0/ pi() AS srad ;
     srad
    ------
      5
    (1 row)

## `sline` functions

### Begin and end

To get the beginning and the end of a line, pgSphere provides two functions:

                      sl_beg
                        sline line

                      sl_end
                        sline line

#### Get the beginning of a line

    sql> SELECT sl_beg( sline '(10d, 90d, 270d, ZXZ ), 20d';

### Create a meridian

You can create a meridian as a line using the function

                        meridian
                          float8 lng

The function returns a line starting at a latitude of -90° and ending at a latitude of 90°. The line goes along the given longitude `lng` in radians.

#### A meridian for longitude 20°

    sql> SELECT set_sphere_output('DEG');
     set_sphere_output
    -------------------
     SET DEG
    (1 row)

    sql> SELECT meridian (20.0 *pi() / 180.0 );
                 sline
    -------------------------------
     ( 270d, 90d, 20d, ZXZ ), 180d
    (1 row)

## `spath` functions

### Count of points

You can get the count of points of a spherical path using the function:

                    npoints
                      spath path

#### Count of spath's points

    sql> SELECT npoints ( spath '{(0,0),(1,0)}' );
     npoints
    ---------
           2
     (1 row)

### Positions at a path

pgSphere provides three functions to get points at a path.

                    spoint
                      spath path
                      int4 i

                    spoint
                      spath  path
                      float8 f

                    spath_as_array
                      spath  path

The first function returns the `i`-th point of a path. If `i` is less than 1 or larger than the count of `spath` points, the function returns `NULL`. The second function does nearly the same, but does linear interpolation between edge positions.

#### Get the “center” of a one segment `spath`

    sql> SELECT spoint ( spath '{(0d,0d),(30d,0d)}', 1.5 );
      spoint
    ------------
     (15d , 0d)
    (1 row)

#### Get i-th point of a path

    sql> SELECT spoint( spath '{(0, 0),(1, 1)}', 1 );
       spoint
    ------------
      (0 , 0)
    (1 row)

    sql> SELECT spoint( spath '{(0, 0),(1, 1)}', 2 );
       spoint
    ------------
      (1 , 1)
    (1 row)

#### Get array representation of points

    sql> SELECT spath_as_array( spath '{(0, 0),(1, 1)}');
        spath_as_array
    -----------------------
     {"(0 , 0)","(1 , 1)"}
    (1 row)

## `spoly` functions

### Count of edges

Similar to an `spath` (funcs.spath.npts), you can get the count of edges of a spherical polygon using the function:

                    npoints
                      spoly polygon

#### Count of edges of a spherical polygon

    sql> SELECT npoints ( spoly '{(0,0),(1,0),(1,1)}' );
     npoints
    ---------
           3
     (1 row)

### Positions at a polygon

pgSphere provides two functions to get points at a path.

                    spoint
                      spoly path
                      int4 i

                    spoly_as_array
                      spath  path

#### Get by index

    sql> SELECT  spoint( spoly '{(0,0),(1,0),(1,1)}', 1 );
     spoint
    ---------
     (0 , 0)
     (1 row)

    sql> SELECT  spoint( spoly '{(0,0),(1,0),(1,1)}', 2 );
     spoint
    ---------
     (1 , 0)
     (1 row)

    sql> SELECT  spoint( spoly '{(0,0),(1,0),(1,1)}', 3 );
     spoint
    ---------
     (1 , 1)
     (1 row)

#### Represent points as array

    sql> SELECT  spoly_as_array( spoly '{(0,0),(1,0),(1,1)}' );
             spoly_as_array
    ---------------------------------
     {"(0 , 0)","(1 , 0)","(1 , 1)"}
    (1 row)

### Spoly is convex

Returns true if the specified spherical polygon is convex. Returns false otherwise.

                    spoly_is_convex
                      spoly polygon

#### Check if polygon is convex

    sql> SELECT spoly_is_convex( spoly '{(0,0),(1,0),(1,1),(1,2)}' );
     spoly_is_convex
    -----------------
     t
     (1 row)

## `sbox` functions

The functions

                  sw
                    sbox box

                  ne
                    sbox box

                  se
                    sbox box

                  nw
                    sbox box

return the corresponding southwest, northeast, southeast, or northwest edge. The returned value will be a spherical point.

### The southwest edge of a box

    sql> SELECT sw ( sbox '( (0d,0d), (90d,0d) )' ) ;

## `smoc` functions

                  smoc_info
                    smoc

Returns information about the internal representation of the smoc.

### A circle

    sql> SELECT smoc_info('0/4 1/0 2 12-13 34-35 45 47 2/4 6 12 14 56-57 60-61 88 90-91 116-117 119 130-131 134-135 177 179 185 187');
                                                               smoc_info
    --------------------------------------------------------------------------------------------------------------------------------
     version: 0, order: 2, depth: 1, first: 0, last: 3458764513820540928, area: 1261007895663738880, tree_begin: 48, data_begin: 72

                  smoc_degrade
                    order int
                    smoc

Adjusts the order of an smoc to be more or less precise.

When order is smaller than smoc's maximal order, the MOC resolution is degraded to the new order, and its maximal order is set to that order. When order is larger than the smoc's maximal order, smoc's shape is not modified, but its maximal order is raised to order.

                  sum
                    smoc

                  intersection
                    smoc

`smoc` union and intersection are available as aggregate functions that compute the aggretated coverage over a given column.

### Computing the overall coverage of a catalog

    SELECT sum(coverage) FROM ivoa;
        sum
    -----------
     0/0-11 6/

                  max_order
                    smoc

Returns the maximal order of an smoc.

The maximal order of a MOC can be higher than than the highest order appearing in the serialisation. For instance, in the example below the full-sky coverage given at order 6 means that no patch larger than about 1 degree is not covered. In the ASCII serialisation, give the maximum order with an with an empty cell list.

### Obtaining a MOC order

    SELECT max_order(smoc('0/0-11 6/')) as order;
        order
    -----------
     6

## Epoch propagation

### 6-Parameter Epoch Propagation

                    double precision[6]
                        epoch_prop
                      spoint pos
                      double precision parallax
                      double precision pm_long
                      double precision pm_lat
                      double precision radial_velocity
                      double precision delta_t

Propagates a spherical phase vector in time (in particular, applies proper motion to positions)

Following both pg_sphere and, where missing, astronomical conventions makes units somewhat eclectic here; pm_long and pm_lat need to be in rad/yr, whereas parallax is in mas, and radial_velocity in km/s. The time difference must be in (Julian) years.

This function returns a 6-array of [long, lat, parallax, pm_long, pm_lat, radial_velocity] of the corresponding values delta_t years after the reference epoch for the original position. As in the function arguments, long and lat are in rad, pm_lon and pm_lat are in rad/yr, parallax is in mas, and radial_velocity is in km/s. If you are only interested in the position, consider the epoch_prop_pos functions below that have a somewhat less contorted signature.

It is an error to have either pos or delta_t NULL. For all other arguments, NULLs are turned into 0s, except for parallax, where some very small default is put in. Whatever is NULL on the input is NULL on the output. In addition, we null out a non-NULL input on one component of the proper motion if the other component is NULL, and we null out the radial velocity if the parallax is missing, as it would be horribly off with the propagation algorithm we use here.

This uses the rigorous method derived in "The Hipparcos and Tycho Catalogues", ESA Special Publication 1200 (1997), p 94f. It does not take into account relativistic effects, and it also does not account for secular aberration.

#### Propagating Barnard's star into the past

    SELECT
       to_char(DEGREES(tp[1]), '999D9999999999'),
       to_char(DEGREES(tp[2]), '999D9999999999'),
       to_char(tp[3], '999D999'),
       to_char(DEGREES(tp[4])*3.6e6, '999D999'),
       to_char(DEGREES(tp[5])*3.6e6, '99999D999'),
       to_char(tp[6], '999D999')
    FROM (
      SELECT epoch_prop(
        spoint(radians(269.45207695), radians(4.693364966)), 546.9759,
        RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110,
                   -100) AS tp) AS q;
         to_char     |     to_char     | to_char  | to_char  |  to_char   | to_char
    -----------------+-----------------+----------+----------+------------+----------
      269.4742714391 |    4.4072939987 |  543.624 | -791.442 |  10235.412 | -110.450

### Epoch Propagation of Positions Only

                  spoint
                      epoch_prop_pos
                    spoint pos
                    double precision parallax
                    double precision pm_long
                    double precision pm_lat
                    double precision radial_velocity
                    double precision delta_t

                  spoint
                      epoch_prop_pos
                    spoint pos
                    double precision pm_long
                    double precision pm_lat
                    double precision delta_t

These are simplified versions of epoch_prop returning only spoints; the propagated values for the other coordinates are discarded (but still internallay computed; these functions do not run any faster than epoch_prop itself).

As with epoch_prop itself, missing values (except for pos and delta_t) are substituted by 0 (or a very small value in the case of parallax).

#### Barnard's star, position and proper motion

    SELECT epoch_prop_pos(
      spoint(radians(269.45207695), radians(4.693364966)),
      RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6),
      20) AS tp;
                       tp
    -----------------------------------------
     (4.70274793061952 , 0.0829193989380876)