Static Poses and Pose Chains

A 2D pose is a couple of the form (point2D,radius) where point2D is a 2D geometric point and radius is a float value representing a rotation angle in (-π, π] expressed in radians. A 3D pose is a tuple of the form (point3D,W,Y,X,Z) where point3D is a 3D geometric point, and W, and X, Y, and Z are four floats representing a unit quaternion. Examples of input of pose values are as follows:

SELECT pose 'Pose(Point(1 1), 0.5)';
SELECT pose 'Pose(Point Z(1 1 1), 0.5, 0.5, 0.5, 0.5)';

An SRID can be specified for a pose either at the begining of the pose literal or before the point literal as shown below.

SELECT pose 'SRID=3812;Pose(Point(1 1), 0.5)';
SELECT pose 'Pose(SRID=5676;Point Z(1 1 1), 0.5, 0.5, 0.5, 0.5)';

As for other spatial types, a pose can be either planar (geometric) or geodetic (geographic). A geodetic pose is denoted by the GeodPose keyword, in the same way that a geodetic stbox is denoted by GEODSTBOX.

SELECT pose 'GeodPose(Point(1 1), 0.5)';
SELECT pose 'SRID=4326;GeodPose(Point Z(1 1 1), 1, 0, 0, 0)';

Values of the pose type must satisfy several constraints so that they are well defined. Examples of incorrect pose type values are as follows.

-- Empty point
select pose 'Pose(Point empty, 0.5)';
-- Incorrect point value
SELECT pose 'Pose(Linestring(1 1,2 2), 1.0)';
-- Incorrect radius value
SELECT pose 'Pose(Point(1 1), -10.0)';
-- Incorrect 3D point
SELECT pose 'Pose(Point Z(1 1), 1.0)';
-- Incomplete 3D orientation
SELECT pose 'Pose(Point Z(1 1 1), 1.0)';

We give next the functions and operators for the pose type.

Input and Output

  • Return the Well-Known Text (WKT) or the Extended Well-Known Text (EWKT) representation

    asText({pose,posechain,pose[],posechain[]}) → {text,text[]}
    asEWKT({pose,posechain,pose[],posechain[]}) → {text,text[]}
    
    SELECT asText(pose 'SRID=4326;Pose(Point(0 0),1)');
    -- Pose(POINT(0 0),1)
    SELECT asText(ARRAY[pose 'Pose(Point(0 0),1)', 'Pose(Point(1 1),2)']);
    -- {"Pose(POINT(0 0),1)","Pose(POINT(1 1),2)"}
    SELECT asEWKT(pose 'SRID=4326;Pose(Point(0 0),1)');
    -- SRID=4326;Pose(POINT(0 0),1)
    SELECT asEWKT(ARRAY[pose 'Pose(SRID=5676;Point(0 0),1)', 'Pose(SRID=5676;Point(1 1),2)']);
    -- {"Pose(SRID=5676;POINT(0 0),1)","Pose(SRID=5676;POINT(1 1),2))"}
    
  • Return the Well-Known Binary (WKB), the Extended Well-Known Binary (EWKB), the Hexadecimal Well-Known Binary (HexWKB), or the Hexadecimal Extended Well-Known Binary (HexEWKB) representation

    asBinary({pose,posechain},endian text='') → bytea
    asEWKB({pose,posechain},endian text='') → bytea
    asHexWKB({pose,posechain},endian text='') → text
    asHexEWKB({pose,posechain},endian text='') → text
    

    The chain writes its flags and its one SRID once, then the number of links, then the values of every link in order. The result is encoded using either the little-endian (NDR) or the big-endian (XDR) encoding. If no encoding is specified, then the encoding of the machine is used.

    The result is encoded using either the little-endian (NDR) or the big-endian (XDR) encoding. If no encoding is specified, then the encoding of the machine is used.

    SELECT asBinary(pose 'Pose(Point(1 2),1)');
    -- \x0101000000000000f03f0000000000000040000000000000f03f
    SELECT asEWKB(pose 'SRID=7844;Pose(Point(1 2),1)');
    -- \x0141a41e0000000000000000f03f0000000000000040000000000000f03f
    SELECT asHexWKB(pose 'Pose(Point(1 2),1)');
    -- 0101000000000000F03F0000000000000040000000000000F03F
    SELECT asHexEWKB(pose 'SRID=3812;Pose(Point(1 2),1)');
    -- 0141E40E0000000000000000F03F0000000000000040000000000000F03F
    
  • Input from the Well-Known Text (WKT) or from the Extended Well-Known Text (EWKT) representation

    poseFromText(text) → pose
    poseFromEWKT(text) → pose
    posechainFromText(text) → posechain
    posechainFromEWKT(text) → posechain
    
    SELECT asEWKT(poseFromText(text 'Pose(Point(1 2),1)'));
    -- Pose(POINT(1 2),1)
    SELECT asEWKT(poseFromEWKT(text 'SRID=3812;Pose(Point(1 2),1)'));
    -- SRID=3812;Pose(POINT(1 2),1)
    SELECT asEWKT(posechainFromText('PoseChain(Pose(Point(0 0),0),Pose(Point(1 0),1))'));
    -- PoseChain(Pose(POINT(0 0),0),Pose(POINT(1 0),1))
    SELECT asEWKT(posechainFromEWKT('SRID=3812;PoseChain(Pose(Point(0 0),0))'));
    -- SRID=3812;PoseChain(Pose(POINT(0 0),0))
    
  • Input from the Well-Known Binary (WKB), from the Extended Well-Known Binary (EWKB), or from the Hexadecimal Extended Well-Known Binary (HexEWKB) representation

    poseFromBinary(bytea) → pose
    poseFromEWKB(bytea) → pose
    poseFromHexEWKB(text) → pose
    posechainFromBinary(bytea) → posechain
    posechainFromEWKB(bytea) → posechain
    posechainFromHexEWKB(text) → posechain
    
    SELECT asEWKT(poseFromBinary('\x0101000000000000f03f0000000000000040000000000000f03f'));
    -- Pose(POINT(1 2),1)
    SELECT asEWKT(poseFromEWKB(
      '\x0141a41e0000000000000000f03f0000000000000040000000000000f03f'));
    -- SRID=7844;Pose(POINT(1 2),1)
    SELECT asEWKT(poseFromHexEWKB(
      '0141E40E0000000000000000F03F0000000000000040000000000000F03F'));
    -- SRID=3812;Pose(POINT(1 2),1)
    SELECT posechainFromBinary(asBinary(posechain 'PoseChain(Pose(Point(1 2),0.5))')) =
      posechain 'PoseChain(Pose(Point(1 2),0.5))';
    -- t
    SELECT posechainFromHexEWKB(asHexEWKB( posechain 'SRID=3812;
      PoseChain(Pose(Point(1 2),0.5))')) = posechain 'SRID=3812;PoseChain(Pose(Point(1 2),
      0.5))';
    -- t
    

Constructors

  • Constructor for poses

    pose(geompoint2D,float) → pose
    pose(geompoint3D,float,float,float,float) → pose
    pose(geompoint3D,yaw float,pitch float,roll float) → pose
    

    The three-angle form takes the orientation in the other encoding the OGC GeoPose v1.0 standard prescribes, a yaw / pitch / roll triple in radians under the ZYX intrinsic Tait-Bryan convention, and stores the quaternion it denotes. It is the inverse of ypr.

    SELECT asText(pose(ST_Point(1,1), radians(45)), 6);
    -- Pose(POINT(1 1),0.785398)
    SELECT asEWKT(pose(ST_Point(1,1,3812), radians(45)), 6);
    -- SRID=3812;Pose(POINT(1 1),0.785398)
    SELECT asText(pose(ST_PointZ(1,1,1), 1, 0, 0, 0));
    -- Pose(POINT Z (1 1 1),1,0,0,0)
    SELECT asText(pose(ST_PointZ(1,1,1), radians(90), 0, 0), 6);
    -- Pose(POINT Z (1 1 1),0.707107,0,0,0.707107)
    

Conversions

Values of the pose type can be converted to the geometry point type using an explicit CAST or using the :: notation as shown below.

  • Convert a pose and, optionally, a timestamp or a period, into a spatiotemporal box

    {pose,posechain}::stbox
    stbox({pose,posechain}) → stbox
    stbox({pose,posechain},{timestamptz,tstzspan}) → stbox
    

    The box covers the composed position of every prefix of the chain, not only of the whole of it: every joint is a place, and a query window that meets the elbow but not the hand still meets the chain.

    SELECT stbox(pose 'SRID=5676;Pose(Point(1 1),0.3)');
    -- SRID=5676;STBOX X((1,1),(1,1))
    SELECT stbox(pose 'Pose(Point(1 1),0.3)', timestamptz '2001-01-01');
    -- STBOX XT(((1,1),(1.3,1.3)),[2001-01-01, 2001-01-01])
    SELECT stbox(pose 'Pose(Point(1 1),0.3)', tstzspan '[2001-01-01,2001-01-02]');
    -- STBOX XT(((1,1),(1.3,1.3)),[2001-01-01, 2001-01-02])
    
  • Convert a pose into geometry point

    pose::geompoint
    
    SELECT ST_AsText(pose(ST_Point(1, 1), 1)::geometry);
    -- POINT(1 1)
    SELECT ST_AsEWKT(pose(ST_PointZ(1, 1, 1, 5676), 1, 0, 0, 0)::geometry);
    -- SRID=5676;POINT(1 1 1)
    

Accessors

  • Return the point, which for a pose chain is the point of its innermost frame

    point({pose,posechain}) → geometry
    
    SELECT ST_AsText(point(pose 'Pose(Point(1 1), 0.3)'));
    -- POINT(1 1)
    
  • Return the orientation quaternion of a pose

    quaternion(pose) → quaternion
    

    The components are returned in the order W, X, Y, Z, the Hamilton convention in which a 3D pose stores them. This is one of the two orientation encodings the OGC GeoPose v1.0 standard prescribes; the other, yaw / pitch / roll, is given by ypr. Both are defined for both dimensions: the orientation of a 2D pose is a turn about the local vertical by its stored angle, so it puts half that angle in W and Z and leaves X and Y at zero. This is the quaternion a GeoPose Basic-Quaternion document carries for a planar pose.

    SELECT quaternion(pose 'Pose(Point Z(1 1 1), 0, 0, 0, 1)');
    -- (0,0,0,1)
    SELECT quaternion(pose 'Pose(Point(1 1), 0)');
    -- (1,0,0,0)
    

Transformations

  • Round the point and the orientation of the pose to the number of decimal places

    round({pose,posechain},integer=0) → {pose,posechain}
    
    SELECT asText(round(pose(ST_Point(1.123456789,1.123456789), 0.123456789), 6));
    -- Pose(POINT(1.123457 1.123457),0.123457)
    

Spatial Reference System

  • Return or set the spatial reference identifier, which for a pose chain is the identifier of its outer frame

    SRID({pose,posechain}) → integer
    setSRID({pose,posechain},integer) → {pose,posechain}
    
    SELECT SRID(pose 'Pose(SRID=5676;Point(1 1), 0.3)');
    -- 5676
    SELECT asEWKT(setSRID(pose 'Pose(Point(0 0),1)', 4326));
    -- SRID=4326;Pose(POINT(0 0),1)
    
  • Transform to a spatial reference identifier

    transform({pose,posechain},integer) → {pose,posechain}
    transformPipeline({pose,posechain},pipeline text,srid integer,
      is_forward boolean=true) → {pose,posechain}
    

    The transform function specifies the transformation with a target SRID. An error is raised when the input has an unknown SRID (represented by 0). For a 3D pose the orientation is re-expressed in the basis of the target frame at the pose's point: the correction is defined for the canonical OGC GeoPose pair, WGS-84 geographic (EPSG:4326) ↔ WGS-84 ECEF (EPSG:4978), taking the standard East-North-Up basis at the geographic point as the rotation pivot, and for any other pair of SRIDs transform emits a NOTICE and passes the orientation through unchanged. For a 2D pose the angle is intrinsic to the source projection and is passed through unchanged. In a chain only the outer link names a frame and only it is transformed, every other link being a rigid transform read in the axes of its parent, which a change of the outer frame leaves as they were. The transformPipeline function specifies the transformation with a defined coordinate transformation pipeline represented with the following string format:

    urn:ogc:def:coordinateOperation:AUTHORITY::CODE

    The SRID of the input pose is ignored, and the SRID of the output pose will be set to zero unless a value is provided via the optional srid parameter. As stated by the last parameter, the pipeline is executed by default in a forward direction; by setting the parameter to false, the pipeline is executed in the inverse direction.

    SELECT asEWKT(transform(pose 'SRID=4326;Pose(Point(4.35 50.85),1)', 3812), 6);
    -- SRID=3812;Pose(POINT(648679.018035 671067.055638),1)
    
    -- Round-tripping a 3D pose through ECEF and back lands at the input pose
    SELECT asEWKT(round( transform(transform(pose 'SRID=4326;Pose(Point(8 47 0), 1, 0, 0, 0)',
      4978), 4326), 6));
    -- SRID=4326;Pose(POINT Z (8 47 0),1,0,0,0)
    -- At the equator-meridian (lat=lon=0), the body identity quaternion in the ECEF basis is
    -- the canonical East-North-Up to ECEF rotation
    SELECT asEWKT(round(transform(pose 'SRID=4326;Pose(Point(0 0 0), 1, 0, 0, 0)', 4978), 6));
    -- SRID=4978;Pose(POINT Z (6378137 0 0),0.5,0.5,0.5,0.5)
    
    WITH test(pose, pipeline) AS (
      SELECT pose 'Pose(SRID=4326;Point(4.3525 50.846667),1)',
        text 'urn:ogc:def:coordinateOperation:EPSG::16031' )
    SELECT asEWKT(transformPipeline(transformPipeline(pose, pipeline, 4326), pipeline, 4326,
      false), 6) FROM test;
    -- SRID=4326;Pose(POINT(4.3525 50.846667),1)
    

Distance Operations

  • Return the distance

    distance({geo,pose},pose) → float
    distance(pose,{geo,pose}) → float
    {geo,pose} <-> pose → float
    

    Only the point component of the pose is taken into account, the orientation is ignored. The distance is computed in two dimensions, even when the arguments are three-dimensional. The result is NULL when the geometry is empty.

    SELECT round(distance(geometry 'Point(1 0)', pose 'Pose(Point(4 0),0)'), 6);
    -- 3
    SELECT round(pose 'Pose(Point(0 0),0)' <-> pose 'Pose(Point(3 4),0)', 6);
    -- 5
    SELECT round(pose 'Pose(Point(0 0 0), 1, 0, 0, 0)' <->
      pose 'Pose(Point(3 4 12), 1, 0, 0, 0)', 6);
    -- 5
    SELECT round(geometry 'Point empty' <-> pose 'Pose(Point(4 0),0)', 6);
    -- NULL
    
  • Return the nearest approach distance

    nearestApproachDistance({stbox,pose},{pose,stbox}) → float
    {stbox,pose} |=| {pose,stbox} → float
    

    The value is the least distance over the time the two arguments share, and is NULL when they share none. A pose carries no period, so it is present at every time the box spans. Only the point component of the pose is taken into account, the orientation is ignored.

    SELECT round(nearestApproachDistance(stbox 'STBOX X((1,-1),(3,1))', pose 'Pose(Point(4 0),0)'), 6);
    -- 1
    SELECT round(pose 'Pose(Point(4 0),0)' |=| stbox 'STBOX X((1,-1),(3,1))', 6);
    -- 1
    

Comparisons

The comparison operators (=, <, and so on) are available for poses. Excepted the equality and inequality, the other comparison operators are not useful in the real world but allow B-tree indexes to be constructed on poses.

  • Traditional comparisons

    {pose,posechain} {=, <>, <, >, <=, >=} {pose,posechain} → boolean
    

    The ordering compares the dimension, then the SRID, then the links in order, and last the number of links, so a chain precedes every chain that extends it.

    SELECT pose 'Pose(Point(3 3), 0.5)' = pose 'Pose(Point(3 3), 0.5)';
    -- true
    SELECT pose 'Pose(Point(3 3), 0.5)' <> pose 'Pose(Point(3 3), 0.6)';
    -- true
    SELECT pose 'Pose(Point(3 3), 0.5)' < pose 'Pose(Point(3 3), 0.6)';
    -- true
    SELECT pose 'Pose(Point(3 3), 0.6)' > pose 'Pose(Point(2 2), 0.6)';
    -- true
    SELECT pose 'Pose(Point Z(1 1 1), 0.5, 0.5, 0.5, 0.5)' <=
      pose 'Pose(Point Z(2 2 2), 0.5, 0.5, 0.5, 0.5)';
    -- true
    SELECT pose 'Pose(Point(1 1), 0.6)' >= pose 'Pose(Point(1 1), 0.5)';
    -- true
    
  • Are the two values approximately equal with respect to an epsilon value?

    same(pose,pose) → boolean
    same(posechain,posechain) → boolean
    pose ~= pose → boolean
    posechain ~= posechain → boolean
    
    SELECT pose 'Pose(SRID=5676;Point(1 1), 0.3)' ~= pose 'Pose(SRID=5676;
      Point(1 1.0000001), 0.30000001)';
    -- true