# Temporal Poses

The `pose` type is used to represent the location and orientation of geometric objects within coordinate systems anchored to the earth's surface or within other astronomical coordinate systems. The location is represented by a 2D or 3D point. For 2D poses, the orientation is defined by a rotation angle in (-π, π] expressed in radians. For 3D poses, the orientation is defined by four float values `W`, `X`, `Y`, `Z`, representing a unit quaternion Q = 〈 W , X , Y , Z 〉 where ∥ Q 2 ∥ = W 2 + X 2 + Y 2 + Z 2 = 1 .

The GeoPose Standards Working Group (SWG), working under the auspices of the Open Geospatial Consortium, has defined a standard for exchanging pose information across different users, devices, and platforms. More information about the standard can be found in the GitHub repository of the GeoPose SWG.

The `pose` type serves as base type for defining the temporal pose type `tpose`. The `tpose` type has similar functionality as the temporal point type `tgeompoint`. Thus, most functions and operators described before for the `tgeompoint` type are also applicable for the `tpose` type. In addition, there are specific functions defined for the `tpose` type.

We cover these functions in this chapter.

The `tpose` type is used for defining the type `trgeometry` (that is, temporal rigid geometry) defined in the next chapter. The implementation of the these types in MobilityDB has been studied in the following PhD thesis.

- Maxime Schoemans, Managing Rigid Temporal Geometries in Moving Object Databases, PhD thesis, Université libre de Bruxelles, 2025.

## Static Poses

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)';

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,pose[]}) → {text,text[]}`

  `asEWKT({pose,pose[]}) → {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), or the Hexadecimal Extended Well-Known Binary (HexEWKB) representation

  `asBinary(pose,endian text='') → bytea`

  `asEWKB(pose,endian text='') → bytea`

  `asHexEWKB(pose,endian text='') → text`

  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 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`

      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)

- 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`

      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)

### Constructors

- Constructor for poses

  `pose(geompoint2D,float) → pose`

  `pose(geompoint3D,float,float,float,float) → pose`

      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)

### 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::stbox`

  `stbox(pose) → stbox`

  `stbox(pose,{timestamptz,tstzspan}) → stbox`

      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

  `point(pose) → geompoint`

      SELECT ST_AsText(point(pose 'Pose(Point(1 1), 0.3)'));
      -- Point(1 1)

- Return the rotation

  `rotation(pose2D) → float`

      SELECT rotation(pose 'Pose(Point(1 1), 0.3)');
      -- 0.3

- Return the orientation

  `orientation(pose3D) → (X,W,Z,T)`

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

### Transformations

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

  `round(pose,integer=0) → pose`

      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

  `srid(pose) → integer`

  `setSRID(pose) → pose`

      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,integer) → pose`

  `transformPipeline(pose,pipeline text,to_srid integer,is_forward bool=true) → pose`

  The `transform` function specifies the transformation with a target SRID. An error is raised when the input pose has an unknown SRID (represented by 0).

  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 `to_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=4326;Pose(POINT(648679.018035 671067.055638),1)

      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)

### 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 {=, <>, <, >, <=, >=} pose`

      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 poses approximately equal with respect to an epsilon value?

  `pose ~= pose → boolean`

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

## Temporal Poses

The temporal pose type `tpose` allows to represent the evolution in time of the position of objects and their orientation. As all temporal types, it comes in three subtypes, namely, instant, sequence, and sequence set. Examples of `tpose` values in these subtypes are given next.

    SELECT tpose 'Pose(Point(1 1), 0.5)@2001-01-01';
    SELECT tpose '{Pose(Point(1 1), 0.3)@2001-01-01, Pose(Point(1 1), 0.5)@2001-01-02,
      Pose(Point(1 1), 0.5)@2001-01-03}';
    SELECT tpose '[Pose(Point(1 1), 0.2)@2001-01-01, Pose(Point(1 1), 0.4)@2001-01-02,
      Pose(Point(1 1), 0.5)@2001-01-03]';
    SELECT tpose '{[Pose(Point(1 1), 1)@2001-01-01, Pose(Point(2 2), 1)@2001-01-02],
      [Pose(Point(2 2), 2)@2001-01-04, Pose(Point(2 2), 3)@2001-01-05]}';

As for temporal point types, the temporal pose type accepts type modifiers (or `typmod` in PostgreSQL terminology) to specify the subtype, the dimensionality of the point, and/or the spatial reference identifier (SRID). The possible values for the subtype are `Instant`, `Sequence`, and `SequenceSet` and the possible values for the geometry type are either `Point` or `PointZ`. The three arguments are optional and if any of them is not specified for a column, values of any subtype, dimensionality, and/or SRID are allowed.

    SELECT asEWKT(tpose(Sequence,5676) 'SRID=5676;[Pose(Point(1 1), 0.2)@2001-01-01,
      Pose(Point(1 1), 0.5)@2001-01-03]');
    -- SRID=5676;[Pose(POINT(1 1),0.2)@2001-01-01, Pose(POINT(1 1),0.5)@2001-01-03]
    SELECT tpose(Sequence) 'Pose(Point(1 1), 0.2)@2001-01-01';
    -- ERROR: Temporal type (Instant) does not match column type (Sequence)
    SELECT tpose(PointZ) 'Pose(Point(1 1), 0.2)@2001-01-01';
    -- Column has Z dimension but the tpose value does not
    SELECT tpose(5676) 'Pose(Point(1 1), 0.2)@2001-01-01';
    -- ERROR:  Temporal pose SRID (0) does not match column SRID (5676)

Temporal pose values of sequence or sequence set subtype are converted into a normal form so that equivalent values have identical representations. For this, consecutive instant values are merged when possible. Three consecutive instant values can be merged into two if the linear functions defining the evolution of values are the same. Examples of transformation into a normal form are as follows.

    SELECT asText(tpose '[Pose(Point(1 1), 0.2)@2001-01-01,
      Pose(Point(2 2), 0.4)@2001-01-02, Pose(Point(3 3), 0.6)@2001-01-03)');
    -- [Pose(Point(1 1),0.2)@2001-01-01, Pose(Point(3 3),0.6)@2001-01-03)
    SELECT asText(tpose '{[Pose(Point(1 1), 0.2)@2001-01-01,
      Pose(Point(2 2), 0.3)@2001-01-02, Pose(Point(2 2), 0.5)@2001-01-03),
      [Pose(Point(2 2), 0.5)@2001-01-03, Pose(Point(2 2), 0.7)@2001-01-04)}');
    /* {[Pose(Point(1 1),0.2)@2001-01-01, Pose(Point(2 2),0.3)@2001-01-02,
       Pose(Point(2 2),0.7)@2001-01-04)} */

## Validity of Temporal Poses

Temporal pose values must satisfy the constraints specified in ttype_validity so that they are well defined. An error is raised whenever one of these constraints are not satisfied. Examples of incorrect values are as follows.

    -- Null values are not allowed
    SELECT tpose 'NULL@2001-01-01 08:05:00';
    SELECT tpose 'Point(0 0)@NULL';
    -- Base type is not a pose
    SELECT tpose 'Point(0 0)@2001-01-01 08:05:00';

We give next the functions and operators for temporal poses. Most functions and operators for temporal types and spatiotemporal types described in the previous chapters can be applied for temporal pose types. Therefore, in the signatures of the functions, the type `pose` can be used whenever the types `base` and `spatial` are specified, and the type `tpose` can be used whenever the types `ttype` and `tpatial` are specified. To avoid redundancy, we only present some examples of these functions and operators for temporal poses and we refer to previous chapters for detailed explanations about them.

## Input and Output

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

  `asText({tpose,tpose[]}) → {text,text[]}`

  `asEWKT({tpose,tpose[]}) → {text,text[]}`

      SELECT asText(tpose 'SRID=4326;[Pose(Point(0 0),1)@2001-01-01,
        Pose(Point(1 1),2)@2001-01-02)');
      -- [Pose(Point(0 0),1)@2001-01-01, Pose(Point(1 1),2)@2001-01-02)
      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(tpose 'SRID=4326;[Pose(Point(0 0),1)@2001-01-01,
        Pose(Point(1 1),2)@2001-01-02)');
      -- SRID=4326;[Pose(Point(0 0),1)@2001-01-01, Pose(Point(1 1),2)@2001-01-02)
      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 Moving Features JSON (MF-JSON) representation

  `asMFJSON(tpose) → text`

      SELECT asMFJSON(tpose 'Pose(Point(1 2),0.5)@2001-01-01', 3);
      /* {"type":"MovingPose","bbox":[[1,2],[1,2]],"period":{"begin":"2001-01-01T00:00:00+01",
        "end":"2001-01-01T00:00:00+01","lower_inc":true,"upper_inc":true},
        "values":[{"position":{"lat":2,"lon":1},"rotation":0.5}],
        "datetimes":["2001-01-01T00:00:00+01"],"interpolation":"None"} */
      SELECT asMFJSON(tpose 'Pose(Point Z(1 2 3),1,0,0,0)@2001-01-01', 3);
      /* {"type":"MovingPose","bbox":[[1,2,3],[1,2,3]],
        "period":{"begin":"2001-01-01T00:00:00+01","end":"2001-01-01T00:00:00+01",
        "lower_inc":true,"upper_inc":true},
        "values":[{"position":{"lat":2,"lon":1,"h":3},"quaternion":{"x":0,"y":0,"z":0,"w":1}}],
        "datetimes":["2001-01-01T00:00:00+01"],"interpolation":"None"} */

- Return the Well-Known Binary (WKB), the Extended Well-Known Binary (EWKB) representation, or the Hexadecimal Extended Well-Known Binary (HexEWKB) representation

  `asBinary(tpose,endian text='') → bytea`

  `asEWKB(tpose,endian text='') → bytea`

  `asHexEWKB(tpose,endian text='') → text`

  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(tpose 'Pose(Point(1 2),1)@2001-01-01');
      -- \x013a0001000000000000f03f0000000000000040000000000000f03f009c57d3c11c0000
      SELECT asEWKB(tpose 'SRID=7844;Pose(Point(1 2),1)@2001-01-01');
      -- \x013a0001000000000000f03f0000000000000040000000000000f03f009c57d3c11c0000
      SELECT asHexEWKB(tpose 'SRID=3812;Pose(Point(1 2),1)@2001-01-01');
      -- 013A0001000000000000F03F0000000000000040000000000000F03F009C57D3C11C0000

- Input from the Well-Known Text (WKT) representation or from the Extended Well-Known Text (EWKT) representation

  `tposeFromText(text) → tpose`

  `tposeFromEWKT(text) → tpose`

      SELECT asEWKT(tposeFromText(text '[Pose(Point(1 2),1)@2001-01-01,
        Pose(Point(3 4),2)@2001-01-02]'));
      -- [Pose(POINT(1 2),1)@2001-01-01, Pose(POINT(3 4),2)@2001-01-02]
      SELECT asEWKT(tposeFromEWKT(text 'SRID=3812;[Pose(Point(1 2),1)@2001-01-01,
        Pose(Point(3 4),2)@2001-01-02]'));
      -- SRID=3812;[Pose(Point(1 2),1)@2001-01-01, Pose(Point(3 4),2)@2001-01-02]

- Input from the Moving Features JSON (MF-JSON) representation

  `tposeFromMFJSON(bytea) → tpose`

      SELECT asEWKT(tposeFromMFJSON(asMFJSON(tpose
        'SRID=3812;Pose(Point(1 2),0.5)@2001-01-01', 3)));
      -- SRID=3812;Pose(POINT(1 2),0.5)@2001-01-01
      SELECT asEWKT(tposeFromMFJSON(asMFJSON(tpose
        'SRID=5676;Pose(Point Z(1 2 3),1,0,0,0)@2001-01-01', 3)));
      -- SRID=5676;Pose(POINT Z(1 2 3),1,0,0,0)@2001-01-01

- Input from the Well-Known Binary (WKB) representation, from the Extended Well-Known Binary (EWKB) representation, or from the Hexadecimal Extended Well-Known Binary (HexEWKB) representation

  `tposeFromBinary(bytea) → tpose`

  `tposeFromEWKB(bytea) → tpose`

  `tposeFromHexEWKB(text) → tpose`

      SELECT asEWKT(tposeFromBinary(
        '\x013a0001000000000000f03f0000000000000040000000000000f03f009c57d3c11c0000'));
      -- Pose(POINT(1 2),1)@2001-01-01
      SELECT asEWKT(tposeFromEWKB(
        '\x013a0001000000000000f03f0000000000000040000000000000f03f009c57d3c11c0000'));
      -- SRID=7844;Pose(Point(1 1),2)@2001-01-01
      SELECT asEWKT(tposeFromHexEWKB(
        '013A0041E40E0000E40E0000000000000000F03F...40000000000000F03F009C57D3C11C0000'));
      -- SRID=3812;Pose(POINT(1 2),1)@2001-01-01

## Constructors

- Constructor for temporal poses having a constant value

  `tpose(pose,timestamptz) → tposeInst`

  `tpose(pose,tstzset) → tposeDiscSeq`

  `tpose(pose,tstzspan,interp='linear') → tposeContSeq`

  `tpose(pose,tstzspanset,interp='linear') → tposeSeqSet`

      SELECT asText(tpose('Pose(Point(1 1), 0.5)', timestamptz '2001-01-01'));
      -- Pose(Point(1 1),0.5)@2001-01-01
      SELECT asText(tpose('Pose(Point Z(1 1 1), 0.5, 0.5, 0.5, 0.5)',
        tstzset '{2001-01-01, 2001-01-05}'));
      /* {Pose(POINT Z (1 1 1),0.5,0.5,0.5,0.5)@2001-01-01,
        Pose(POINT Z (1 1 1),0.5,0.5,0.5,0.5)@2001-01-05} */
      SELECT asText(tpose('Pose(Point(1 1), 0.5)',
        tstzspan '[2001-01-01, 2001-01-02]'));
      -- [Pose(Point(1 1),0.5)@2001-01-01, Pose(Point(1 1),0.5)@2001-01-02]
      SELECT asText(tpose('Pose(Point(1 1), 0.2)',
        tstzspanset '{[2001-01-01, 2001-01-03]}', 'step'));
      -- Interp=Step;{[Pose(Point(1 1),0.2)@2001-01-01, Pose(Point(1 1),0.2)@2001-01-03]}

- Constructor for temporal poses of sequence subtype

  `tposeSeq(tposeInst[],interp={'step','linear'},leftInc bool=true,`

  `rightInc bool=true) → tposeSeq`

      SELECT asText(tposeSeq(ARRAY[tpose 'Pose(Point(1 1), 0.3)@2001-01-01',
        'Pose(Point(2 2), 0.5)@2001-01-02', 'Pose(Point(1 1), 0.5)@2001-01-03']));
      /* {Pose(Point(1 1),0.3)@2001-01-01, Pose(Point(2 2),0.5)@2001-01-02,
         Pose(Point(1 1),0.5)@2001-01-03} */
      SELECT asText(tposeSeq(ARRAY[tpose 'Pose(Point(1 1), 0.2)@2001-01-01',
        'Pose(Point(1 1), 0.4)@2001-01-02', 'Pose(Point(1 1), 0.5)@2001-01-03']));
      /* [Pose(Point(1 1),0.2)@2001-01-01, Pose(Point(1 1),0.4)@2001-01-02,
         Pose(Point(1 1),0.5)@2001-01-03] */

- Constructor for temporal poses of sequence set subtype

  `tposeSeqSet(tpose[]) → tposeSeqSet`

  `tposeSeqSetGaps(tposeInst[],maxt=NULL,maxdist=NULL,interp='linear') → tposeSeqSet`

      SELECT asText(tposeSeqSet(ARRAY[tpose
        '[Pose(Point(1 1),0.2)@2001-01-01, Pose(Point(2 2),0.4)@2001-01-02]',
        '[Pose(Point(2 2),0.6)@2001-01-03, Pose(Point(2 2),0.8)@2001-01-04]']));
      /* {[Pose(Point(1 1),0.2)@2001-01-01, Pose(Point(2 2),0.4)@2001-01-02],
         [Pose(Point(2 2),0.6)@2001-01-03, Pose(Point(2 2),0.6)@2001-01-04]} */
      SELECT asText(tposeSeqSetGaps(ARRAY[tpose 'Pose(Point(1 1),0.1)@2001-01-01',
        'Pose(Point(1 1),0.3)@2001-01-03', 'Pose(Point(1 1),0.5)@2001-01-05'], '1 day'));
      /* {[Pose(Point(1 1),0.1)@2001-01-01], [Pose(Point(1 1),0.3)@2001-01-03],
         [Pose(Point(1 1),0.5)@2001-01-05]} */

- Construct a 2D temporal pose from a temporal geometry point and a temporal float

  `tpose(tgeompoint, tfloat) → tpose`

  The time frame of the result is the intersection of the time frames of the temporal point and the temporal float. If they do not intersect, a null value is returned

      SELECT asText(tpose(tgeompoint '[POINT(1 1)@2001-01-01, POINT(2 2)@2001-01-02)',
        tfloat '[1@2001-01-01, 2@2001-01-02)'));
      -- [Pose(Point(1 1),1)@2001-01-01, Pose(Point(1 1),2)@2001-01-02)
      SELECT asText(tpose(tgeompoint '[POINT(1 1)@2001-01-01, POINT(2 2)@2001-01-02)',
        tfloat '[2@2001-01-03, 3@2001-01-04)'));
      -- NULL

## Conversions

A temporal pose value can be converted to and from a temporal geometry point. This can be done using an explicit `CAST` or using the `::` notation. A null value is returned if any of the composing geometry point values cannot be converted into a `pose` value.

- Convert a temporal pose into a temporal geometry point

  `tpose::tgeompoint`

      SELECT asText((tpose '[Pose(Point(1 1), 0.2)@2001-01-01,
        Pose(Point(1 1), 0.3)@2001-01-02)')::tgeompoint);
      -- [POINT(1 1)@2001-01-01, POINT(1 1)@2001-01-02)
      SELECT asEWKT((tpose '[Pose(Point Z(1 1 1), 0.5, 0.5, 0.5, 0.5)@2001-01-01,
        Pose(Point Z(2 2 2), 1, 0, 0, 0)@2001-01-02)')::tgeompoint);
      -- [POINT Z (1 1 1)@2001-01-01, POINT Z (2 2 2)@2001-01-02)

## Accessors

- Return the values

  `getValues(tpose) → poseset`

      SELECT asText(getValues(tpose '{[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-02)}'));
      -- {"Pose(Point(1 1),0.3)","Pose(Point(1 1),0.5)"}
      SELECT asEWKT(getValues(tpose 'SRID=5676;{[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.3)@2001-01-02)}'));
      -- SRID=5676;{"Pose(Point(1 1),0.3)"}

- Return the points

  `points(tpose) → geomset`

      SELECT asEWKT(points(tpose 'SRID=5676;{Pose(Point(3 3), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-02}'));
      -- SRID=5676;{Point(1 1), Point(3 3)}

- Return the rotation

  `rotation(tpose2d) → tfloat`

      SELECT rotation(tpose 'SRID=5676;{[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.3)@2001-01-02)}');
      -- {[0.3@2001-01-01, 0.3@2001-01-02)}

- Return the value at a timestamp

  `valueAtTimestamp(tpose,timestamptz) → pose`

      SELECT asText(valueAtTimestamp(tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(3 3), 0.5)@2001-01-03)', '2001-01-02'));
      -- Pose(Point(2 2),0.4)
      SELECT asText(valueAtTimestamp(tpose
        '[Pose(Point Z(1 1 1), 0.5, 0.5, 0.5, 0.5)@2001-01-01,
          Pose(Point Z(3 3 3), 1, 0, 0, 0)@2001-01-03)', timestamptz '2001-01-02'), 6);
      -- Pose(POINT Z (2 2 2),0.866025,0.288675,0.288675,0.288675)

## Transformations

- Transform to another subtype

  `tposeInst(tpose) → tposeInst`

  `tposeSeq(tpose) → tposeSeq`

  `tposeSeqSet(tpose) → tposeSeqSet`

      SELECT asText(tposeSeq(tpose 'Pose(Point(1 1), 0.5)@2001-01-01', 'discrete'));
      -- {Pose(Point(1 1),0.5)@2001-01-01}
      SELECT asText(tposeSeq(tpose 'Pose(Point(1 1), 0.5)@2001-01-01'));
      -- [Pose(Point(1 1),0.5)@2001-01-01]
      SELECT asText(tposeSeqSet(tpose 'Pose(PointZ(1 1 1), 0.5, 0.5, 0.5, 0.5)@2001-01-01'));
      -- {[Pose(POINT Z (1 1 1),0.5,0.5,0.5,0.5)@2001-01-01]}

- Transform to another interpolation

  `setInterp(tpose, interp) → tpose`

      SELECT asText(setInterp(tpose 'Pose(Point(1 1),0.2)@2001-01-01','linear'));
      -- [Pose(Point(1 1),0.2)@2001-01-01]
      SELECT asText(setInterp(tpose '{[Pose(Point Z(1 1 1),1,0,0,0)@2001-01-01],
        [Pose(Point Z(2 2 2),0,0,0,1)@2001-01-02]}', 'discrete'));
      -- {Pose(POINT Z (1 1 1),1,0,0,0)@2001-01-01, Pose(POINT Z (2 2 2),0,0,0,1)@2001-01-02}

- Round the points and the orientations of the temporal pose to the number of decimal places

  `round(tpose,integer=0) → tpose`

      SELECT asText(round(tpose '{[Pose(Point(1 1.123456789),0.123456789)@2001-01-01,
        Pose(Point(1 1),0.5)@2001-01-02)}', 3));
      -- {[Pose(POINT(1 1.123),0.123)@2001-01-01, Pose(POINT(1 1),0.5)@2001-01-02)}

## Modifications

- Append a temporal instant or a temporal sequence

  `appendInstant(tpose,tposeInst) → tpose`

  `appendSequence(tpose,tposeSeq) → tpose`

      SELECT asText(appendInstant(tpose 'Pose(Point(1 1), 0.5)@2001-01-01', 'Pose(Point(2 2), 1)@2001-01-02'));
      -- [Pose(POINT(1 1),0.5)@2001-01-01, Pose(POINT(2 2),1)@2001-01-02]
      SELECT asText(appendSequence(tpose '[Pose(Point(1 1), 0.5)@2001-01-01]', '[Pose(Point(2 2), 1)@2001-01-02]'));
      -- {[Pose(POINT(1 1),0.5)@2001-01-01], [Pose(POINT(2 2),1)@2001-01-02]}

- Merge the temporal poses

  `merge(tpose,tpose) → tpose`

  `merge(tpose[]) → tpose`

  `merge(tpose) → tpose`

      SELECT asText(merge(tpose
        '[Pose(Point(1 1 1),1,0,0,0)@2001-01-01, Pose(Point(2 2 2),0,1,0,0)@2001-01-02]',
        '[Pose(Point(2 2 2),0,1,0,0)@2001-01-02, Pose(Point(3 3 3),0,0,0,1)@2001-01-03]'));
      /* [Pose(POINT Z (1 1 1),1,0,0,0)@2001-01-01, Pose(POINT Z (2 2 2),0,1,0,0)@2001-01-02,
          Pose(POINT Z (3 3 3),0,0,0,1)@2001-01-03] */
      SELECT asText(merge(ARRAY[tpose
        '{[Pose(Point(1 1),0.1)@2001-01-01, Pose(Point(2 2),0.2)@2001-01-02],
          [Pose(Point(3 3),0.3)@2001-01-03, Pose(Point(4 4),0.4)@2001-01-04]}',
        '[Pose(Point(4 4),0.4)@2001-01-04, Pose(Point(5 5),0.5)@2001-01-05]']));
      /* {[Pose(POINT(1 1),0.1)@2001-01-01, Pose(POINT(2 2),0.2)@2001-01-02],
          [Pose(POINT(3 3),0.3)@2001-01-03, Pose(POINT(5 5),0.5)@2001-01-05]} */
      WITH temp(inst) AS (
        SELECT tpose 'Pose(Point(1 1),0.1)@2001-01-01' UNION
        SELECT tpose 'Pose(Point(2 2),0.2)@2001-01-02' UNION
        SELECT tpose 'Pose(Point(3 3),0.3)@2001-01-03' )
      SELECT asText(merge(inst)) FROM temp;
      /* {Pose(POINT(1 1),0.1)@2001-01-01, Pose(POINT(2 2),0.2)@2001-01-02,
          Pose(POINT(3 3),0.3)@2001-01-03} */

## Restrictions

- TODO Restrict to (the complement of) a set of values

  `atValues(tpose,values) → tpose`

  `minusValues(tpose,values) → tpose`

      SELECT atValues(tpose '[Pose(Point(2 2), 0.3)@2001-01-01,
        Pose(Point(2 2), 0.7)@2001-01-03]', 'Pose(Point(2 2), 0.5)');
      -- {[Pose(Point(2 2),0.5)@2001-01-02]}
      SELECT minusValues(tpose '[Pose(Point(2 2), 0.3)@2001-01-01,
        Pose(Point(2 2), 0.7)@2001-01-03]', 'Pose(Point(2 2), 0.5)');
      /* {[Pose(Point(2 2),0.3)@2001-01-01, Pose(Point(2 2),0.5)@2001-01-02),
         (Pose(Point(2 2),0.5)@2001-01-02, Pose(Point(2 2),0.7)@2001-01-03]} */

- TODO Restrict to (the complement of) a geometry

  `atGeometry(tpose,geometry) → tpose`

  `minusGeometry(tpose,geometry) → tpose`

      SELECT atGeometry(tpose '[Pose(Point(2 2), 0.3)@2001-01-01,
        Pose(Point(2 2), 0.7)@2001-01-03]',
        'Polygon((40 40,40 50,50 50,50 40,40 40))');
      SELECT minusGeometry(tpose '[Pose(Point(2 2), 0.3)@2001-01-01,
        Pose(Point(2 2), 0.7)@2001-01-03]',
        'Polygon((40 40,40 50,50 50,50 40,40 40))');
      /* {(Pose(Point(2 2),0.342593)@2001-01-01 05:06:40.364673+01,
         Pose(Point(2 2),0.7)@2001-01-03]} */

## Spatial Reference System

- Return or set the spatial reference identifier

  `SRID(tpose) → integer`

  `setSRID(tpose) → tpose`

      SELECT SRID(tpose 'SRID=5676;[Pose(Point(0 0),1)@2001-01-01,
        Pose(Point(1 1),2)@2001-01-02)'));
      -- 5676
      SELECT asEWKT(setSRID(tpose '[Pose(Point(0 0),1)@2001-01-01,
        Pose(Point(1 1),2)@2001-01-02)', 5676));
      -- SRID=5676;[Pose(POINT(0 0),1)@2001-01-01, Pose(POINT(1 1),2)@2001-01-02)

- Transform to a spatial reference identifier

  `transform(tpose,integer) → tpose`

  `transformPipeline(tpose,pipeline text,to_srid integer,is_forward bool=true) → tpose`

      SELECT asEWKT(transform(tpose 'SRID=4326;Pose(Point(4.35 50.85),1)@2001-01-01',
        3812));
      -- SRID=3812;Pose(POINT(648679.0180353033 671067.0556381135),1)@2001-01-01

      WITH test(tpose, pipeline) AS (
        SELECT tpose 'SRID=4326;{Pose(Point(4.3525 50.846667),1)@2001-01-01,
          Pose(Point(-0.1275 51.507222),2)@2001-01-02}',
          text 'urn:ogc:def:coordinateOperation:EPSG::16031' )
      SELECT asEWKT(transformPipeline(transformPipeline(tpose, pipeline, 4326),  pipeline,
        4326, false), 6)
      FROM test;
      /* SRID=4326;{Pose(POINT(4.3525 50.846667),1)@2001-01-01,
         Pose(POINT(-0.1275 51.507222),2)@2001-01-02} */

## Bounding Box Operations

- Topological operators

  `{tstzspan,stbox,tpose} {&&, <@, @>, ~=, -|-} {tstzspan,stbox,tpose} → boolean`

      SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-03]' && tstzspan '[2001-01-02,2001-01-04]';
      -- true
      SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-02]' @> stbox(pose 'Pose(Point(1 1), 0.5)');
      -- true
      SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-03]' ~= tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.35)@2001-01-02, Pose(Point(1 1), 0.5)@2001-01-03]';
      -- true

- Position operators

  `{stbox,tpose} {<<, &<, >>, &>} {stbox,tpose} → boolean`

  `{stbox,tpose} {<<|, &<|, |>>, |&>} {stbox,tpose} → boolean`

  `{stbox,tpose} {<</, &</, />>, /&>} {stbox,tpose} → boolean`

  `{tstzspan,stbox,tpose} {<<#, &<#, #>>, #&>} {tstzspan,stbox,tpose} → boolean`

      SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-02]' << stbox(pose 'Pose(Point(2 2), 0.5)');
      -- true
      SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-02]' <<| stbox(pose 'Pose(Point(2 2), 0.5)');
      -- true
      SELECT tpose '[Pose(Point(1 1 1), 1,0,0,0)@2001-01-01,
        Pose(Point(1 1 1), 1,0,0,0)@2001-01-02]' <</ stbox(pose 'Pose(Point(2 2 2), 1,0,0,0)');
      -- true
      SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-02]' <<# tstzspan '[2001-01-03, 2001-01-04]';
      -- true
      SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-03,
        Pose(Point(1 1), 0.5)@2001-01-05]' #>>
        tpose '[Pose(Point(1 1), 0.3)@2001-01-01, Pose(Point(1 1), 0.5)@2001-01-02]';
      -- true

## Distance Operations

We present next the functions that compute distance operations for temporal poses. Notice that for these operations only the point component is considered, not the orientation.

- Return the smallest distance ever

  `{geo,pose,tpose} |=| {geo,pose,tpose} → float`

      SELECT tpose '[Pose(Point(2 2), 0.3)@2001-01-01, Pose(Point(2 2), 0.7)@2001-01-02]' |=|
        geometry 'Linestring(50 50,55 55)';
      -- 67.88225099390856
      SELECT tpose '[Pose(Point(2 2), 0.3)@2001-01-01, Pose(Point(2 2), 0.7)@2001-01-02]' |=|
        pose 'Pose(Point(1 1), 0.5)';
      -- 1.4142135623730951
      SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-03]' |=| pose 'Pose(Point(2 2), 0.2)';
      -- 1.4142135623730951
      SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-03]' |=| geometry 'Linestring(2 2,2 1,3 1)';
      -- 1

  The operator `|=|` can be used for doing nearest neightbor searches using GiST or SP-GiST indexes (see ttype_indexing).

- Return the instant of the first temporal pose at which the two arguments are at the nearest distance

  `nearestApproachInstant({geo,pose,tpose},{geo,pose,tpose}) → tpose`

      SELECT asText(nearestApproachInstant(tpose '[Pose(Point(2 2), 0.3)@2001-01-01,
        Pose(Point(2 2), 0.7)@2001-01-02]', geometry 'Linestring(50 50,55 55)'));
      -- Pose(POINT(2 2),0.3)@2001-01-01
      SELECT asText(nearestApproachInstant(tpose '[Pose(Point(2 2), 0.3)@2001-01-01,
        Pose(Point(2 2), 0.7)@2001-01-02]', pose 'Pose(Point(1 1), 0.5)'));
      -- Pose(POINT(2 2),0.3)@2001-01-01

- Return the line connecting the nearest approach point

  `shortestLine({geo,pose,tpose},{geo,pose,tpose}) → geometry`

  The function will only return the first line that it finds if there are more than one.

      SELECT ST_AsText(shortestLine(tpose '[Pose(Point(2 2), 0.3)@2001-01-01,
        Pose(Point(2 2), 0.7)@2001-01-02]', geometry 'Linestring(50 50,55 55)'));
      -- LINESTRING(2 2,50 50)
      SELECT ST_AsText(shortestLine(tpose '[Pose(Point(2 2), 0.3)@2001-01-01,
        Pose(Point(2 2), 0.7)@2001-01-02]', pose 'Pose(Point(1 1), 0.5)'));
      -- LINESTRING(2 2,1 1)

- Return the temporal distance

  `tpose <-> tpose → tfloat`

      SELECT round(tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-03]' <-> pose 'Pose(Point(2 2), 0.2)', 6);
      -- [1.414214@2001-01-01, 1.414214@2001-01-03]
      SELECT round(tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-03]' <-> geometry 'Point(50 50)', 6);
      -- [69.296465@2001-01-01, 69.296465@2001-01-03]
      SELECT round(tpose '[Pose(Point(1 1), 0.3)@2001-01-01,
        Pose(Point(2 2), 0.5)@2001-01-03]' <->
        tpose '[Pose(Point(1 2), 0.3)@2001-01-02, Pose(Point(2 1), 0.5)@2001-01-04]', 6);
      -- [0.707107@2001-01-02, 0.5@2001-01-02 12:00:00+01, 0.707107@2001-01-03]

## Spatial Relationships

The topological and distance relationships described in tgeo_spatial_rel such as `eIntersects`, `aDwithin`, or `tContains` only consider the location of the geometries, not their orientation. To be able to apply these spatial relationships to the temporal poses, they must be transformed to temporal geometry points. This can be easily performed using the functions `geometry` and `tgeompoint` or using an explicit casting `::` as shown in the examples below.

- Ever and always relationships

      SELECT eContains(geometry 'Polygon((0 0,0 50,50 50,50 0,0 0))',
        tgeompoint(tpose '[Pose(Point(1 1),0.1)@2001-01-01, Pose(Point(1 1),0.3)@2001-01-03)'));
      -- true
      SELECT eDisjoint(geometry(pose 'Pose(Point(2 2), 0.0)'),
        tgeompoint(tpose '[Pose(Point(1 1),0.1)@2001-01-01, Pose(Point(1 1),0.3)@2001-01-03)'));
      -- true
      SELECT eIntersects(
        tpose '[Pose(Point(1 1),0.1)@2001-01-01, Pose(Point(1 1),0.3)@2001-01-03)'::tgeompoint,
        tpose '[Pose(Point(2 2),0.0)@2001-01-01, Pose(Point(2 2),1)@2001-01-03)'::tgeompoint);
      -- false

- Spatiotemporal relationships

      SELECT tContains(geometry 'Polygon((0 0,0 50,50 50,50 0,0 0))',
        tgeompoint(tpose '[Pose(Point(1 1),0.1)@2001-01-01, Pose(Point(1 1),0.3)@2001-01-03)'));
      -- {[t@2001-01-01 00:00:00+01, t@2001-01-03 00:00:00+01)}
      SELECT tDisjoint(geometry(pose 'Pose(Point(2 2), 0.0)'),
        tgeompoint(tpose '[Pose(Point(1 1),0.1)@2001-01-01, Pose(Point(1 1),0.3)@2001-01-03)'));
      -- [t@2001-01-01, t@2001-01-03)
      SELECT tDwithin(
       tpose '[Pose(Point(1 1),0.3)@2001-01-01,Pose(Point(1 1),0.5)@2001-01-03)'::tgeompoint,
       tpose '[Pose(Point(1 1),0.5)@2001-01-01,Pose(Point(3 3),0.3)@2001-01-03)'::tgeompoint,1);
      /* {[t@2001-01-01 00:00:00+01, t@2001-01-01 16:58:14.025894+01],
        (f@2001-01-01 16:58:14.025894+01, f@2001-01-03 00:00:00+01)} */

## Comparisons

- Traditional comparisons

  `tpose {=, <>, <, >, <=, >=} tpose → boolean`

      SELECT tpose '{[Pose(Point(1 1), 0.1)@2001-01-01,
        Pose(Point(1 1), 0.3)@2001-01-02),
        [Pose(Point(1 1), 0.3)@2001-01-02, Pose(Point(1 1), 0.5)@2001-01-03]}' =
        tpose '[Pose(Point(1 1), 0.1)@2001-01-01, Pose(Point(1 1), 0.5)@2001-01-03]';
      -- true
      SELECT tpose '{[Pose(Point(1 1), 0.1)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-03]}' <>
        tpose '[Pose(Point(1 1), 0.1)@2001-01-01, Pose(Point(1 1), 0.5)@2001-01-03]';
      -- false
      SELECT tpose '[Pose(Point(1 1), 0.1)@2001-01-01,
        Pose(Point(1 1), 0.5)@2001-01-03]' <
        tpose '[Pose(Point(1 1), 0.1)@2001-01-01, Pose(Point(1 1), 0.6)@2001-01-03]';
      -- true

- Ever and always comparisons

  `tpose {?=, %=} tpose → boolean`

      SELECT tpose '[Pose(Point(1 1), 0.2)@2001-01-01,
        Pose(Point(1 1), 0.4)@2001-01-04)' ?= Pose(Point(1 1), 0.3);
      -- true
      SELECT tpose '[Pose(Point(1 1), 0.2)@2001-01-01,
        Pose(Point(1 1), 0.2)@2001-01-04)' &= Pose(Point(1 1), 0.2);
      -- true

- Temporal comparisons

  `tpose {#=, #<>} tpose → tbool`

      SELECT tpose '[Pose(Point(1 1), 0.2)@2001-01-01,
        Pose(Point(1 1), 0.4)@2001-01-03)' #= pose 'Pose(Point(1 1), 0.3)';
      -- {[f@2001-01-01, t@2001-01-02], (f@2001-01-02, f@2001-01-03)}
      SELECT tpose '[Pose(Point(1 1), 0.2)@2001-01-01,
        Pose(Point(1 1), 0.8)@2001-01-03)' #<>
        tpose '[Pose(Point(1 1), 0.3)@2001-01-01, Pose(Point(1 1), 0.7)@2001-01-03)';
      -- {[t@2001-01-01, f@2001-01-02], (t@2001-01-02, t@2001-01-03)}

## Aggregations

The three aggregate functions for temporal poses are illustrated next.

- Temporal count

  `tCount(tpose) → {tintSeq,tintSeqSet}`

      WITH Temp(temp) AS (
        SELECT tpose '[Pose(Point(1 1), 0.1)@2001-01-01,
          Pose(Point(1 1), 0.3)@2001-01-03)' UNION
        SELECT tpose '[Pose(Point(1 1), 0.2)@2001-01-02,
          Pose(Point(1 1), 0.4)@2001-01-04)' UNION
        SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-03,
          Pose(Point(1 1), 0.5)@2001-01-05)' )
      SELECT tCount(Temp)
      FROM Temp;
      -- {[1@2001-01-01, 2@2001-01-02, 1@2001-01-04, 1@2001-01-05)}

- Window count

  `wCount(tpose) → {tintSeq,tintSeqSet}`

      WITH Temp(temp) AS (
        SELECT tpose '[Pose(Point(1 1), 0.1)@2001-01-01,
          Pose(Point(1 1), 0.3)@2001-01-03)' UNION
        SELECT tpose '[Pose(Point(1 1), 0.2)@2001-01-02,
          Pose(Point(1 1), 0.4)@2001-01-04)' UNION
        SELECT tpose '[Pose(Point(1 1), 0.3)@2001-01-03,
          Pose(Point(1 1), 0.5)@2001-01-05)' )
      SELECT wCount(Temp, '1 day')
      FROM Temp;
      /* {[1@2001-01-01, 2@2001-01-02, 3@2001-01-03, 2@2001-01-04, 1@2001-01-05,
         1@2001-01-06)} */

## Indexing

GiST and SP-GiST indexes can be created for table columns of temporal poses. An example of index creation is follows:

    CREATE INDEX Trips_Trip_SPGist_Idx ON Trips USING SPGist(Trip);

The GiST and SP-GiST indexes store the bounding box for the temporal poses, which is an `stbox`, as all spatiotemporal types.

A GiST or SP-GiST index can accelerate queries involving the following operators:

- `<<`, `&<`, `&>`, `>>`, `<<|`, `&<|`, `|&>`, `|>>`, which only consider the spatial dimension in temporal poses,

- `<<#`, `&<#`, `#&>`, `#>>`, which only consider the time dimension in temporal poses,

- `&&`, `@>`, `<@`, `~=`, `-|-`, and `|=|` , which consider as many dimensions as they are shared by the indexed column and the query argument.

These operators work on bounding boxes, not the entire values.