Spatial Relationships

The topological relationships such as ST_Intersects and the distance relationships such as ST_DWithin can be generalized for temporal geometries. The arguments of these generalized functions are either a temporal geometry (that is, a tgeometry, a tgeography, a tgeompoint, or a tgeogpoint) and a base type (that is, a geometry or a geography) or two temporal geometries. Furthermore, both arguments must be of the same base type or the same temporal type, for example, these functions do not allow to mix a tgeometry and a geography or a tgeometry and a tgeompoint.

There are three versions of the relationships:

For example, the following query

SELECT eIntersects(geometry 'Polygon((1 1,1 3,3 3,3 1,1 1))',
  tgeompoint '[Point(0 2)@2001-01-01, Point(4 2)@2001-01-05)');
-- t

tests whether the temporal point ever intersects the geometry. In this case, the query is equivalent to the following one

SELECT ST_Intersects(geometry 'Polygon((1 1,1 3,3 3,3 1,1 1))',
  geometry 'Linestring(0 2,4 2)');

where the second geometry is obtained by applying the trajectory function to the temporal point.

In contrast, the query

SELECT tIntersects(geometry 'Polygon((1 1,1 3,3 3,3 1,1 1))',
  tgeompoint '[Point(0 2)@2001-01-01, Point(4 2)@2001-01-05)');
-- {[f@2001-01-01, t@2001-01-02, t@2001-01-04], (f@2001-01-04, f@2001-01-05)}

computes at each instant whether the temporal point intersects the geometry. Similarly, the following query

SELECT eDwithin(tgeompoint '[Point(3 1)@2001-01-01, Point(5 1)@2001-01-03)',
  tgeompoint '[Point(3 1)@2001-01-01, Point(1 1)@2001-01-03)', 2);
-- t

tests whether the distance between the temporal points was ever less than or equal to 2, while the following query

SELECT tDwithin(tgeompoint '[Point(3 1)@2001-01-01, Point(5 1)@2001-01-03)',
  tgeompoint '[Point(3 1)@2001-01-01, Point(1 1)@2001-01-03)', 2);
-- {[t@2001-01-01, t@2001-01-02], (f@2001-01-02, f@2001-01-03)}

computes at each instant whether the distance between the temporal points is less than or equal to 2.

The ever or always relationships are sometimes used in combination with a spatiotemporal index when computing the temporal relationships. For example, the following query

SELECT T.TripId, R.RegionId, tIntersects(T.Trip, R.Geom)
FROM Trips T, Regions R
WHERE eIntersects(T.Trip, R.Geom)

which verifies whether a trip T (which is a temporal point) intersects a region R (which is a geometry), will benefit from a spatiotemporal index on the column T.Trip since the eIntersects function will automatically perform the bounding box comparison T.Trip && R.Geom. This is further explained later in this document.

Not all spatial relationships available in PostGIS have been generalized for temporal geometries, only those derived from the following functions: ST_Contains, ST_Covers, ST_Disjoint, ST_Intersects, ST_Touches, and ST_DWithin. These functions only suport 2D geometries and only the functions ST_Covers, ST_Intersects, and ST_DWithin suport geographies. Consequently, the same applies for the MobilityDB functions derived from them, excepted that they support 3D for temporal points, that is, tgeompoint, and tgeogpoint. As stated above, each of the above PostGIS functions, such as ST_Contains, has three generalized versions in MobilityDB, namely eContains, aContains, and tContains. Furthermore, not all combinations of parameters are meaningful for the generalized functions. For example, tContains(tpoint, geometry) is meaningful only when the geometry is a single point, and tContains(tpoint, tpoint) is equivalent to tintersects(tpoint, geometry).

Ever and Always Relationships

We present next the ever and always relationships. These relationships automatically include a bounding box comparison that makes use of any spatial indexes that are available on the arguments.

  • Ever or always contains

    eContains({geometry,tgeom},{geometry,tgeom}) → boolean

    aContains({geometry,tgeom},{geometry,tgeom}) → boolean

    This function returns true if the temporal geometry and the geometry ever or always intersect at their interior. Recall that a geometry does not contain things in its boundary and thus, polygons and lines do not contain lines and points lying in their boundary. Please refer to the documentation of the ST_Contains function in PostGIS.

    SELECT eContains(geometry 'Linestring(1 1,3 3)',
      tgeompoint '[Point(4 2)@2001-01-01, Point(2 4)@2001-01-02]');
    -- false
    SELECT eContains(geometry 'Linestring(1 1,3 3,1 1)',
      tgeompoint '[Point(4 2)@2001-01-01, Point(2 4)@2001-01-03]');
    -- true
    SELECT eContains(geometry 'Polygon((1 1,1 3,3 3,3 1,1 1))',
     tgeompoint '[Point(0 1)@2001-01-01, Point(4 1)@2001-01-02]');
    -- false
    SELECT eContains(geometry 'Polygon((1 1,1 3,3 3,3 1,1 1))',
      tgeometry '[Linestring(1 1,4 4)@2001-01-01, Point(3 3)@2001-01-04]');
    -- true
    
  • Ever or always covers

    eCovers({geometry,tgeom},{geometry,tgeom}) → boolean

    aCovers({geometry,tgeom},{geometry,tgeom}) → boolean

    Please refer to the documentation of the ST_Contains and the ST_Covers function in PostGIS for detailed explanations about the difference between the two functions.

    SELECT eCovers(geometry 'Linestring(1 1,3 3)',
      tgeompoint '[Point(4 2)@2001-01-01, Point(2 4)@2001-01-02]');
    -- false
    SELECT eCovers(geometry 'Linestring(1 1,3 3,1 1)',
      tgeompoint '[Point(4 2)@2001-01-01, Point(2 4)@2001-01-03]');
    -- true
    SELECT eCovers(geometry 'Polygon((1 1,1 3,3 3,3 1,1 1))',
     tgeompoint '[Point(0 1)@2001-01-01, Point(4 1)@2001-01-02]');
    -- false
    SELECT eCovers(geometry 'Polygon((1 1,1 3,3 3,3 1,1 1))',
      tgeometry '[Linestring(1 1,4 4)@2001-01-01, Point(3 3)@2001-01-04]');
    -- true
    
  • Is ever or always disjoint

    eDisjoint({geo,tgeo},{geo,tgeo}) → boolean

    aDisjoint({geo,tgeo},{geo,tgeo}) → boolean

    SELECT eDisjoint(geometry 'Polygon((0 0,0 1,1 1,1 0,0 0))',
      tgeompoint '[Point(0 0)@2001-01-01, Point(1 1)@2001-01-03)');
    -- false
    SELECT eDisjoint(geometry 'Polygon((0 0 0,0 1 1,1 1 1,1 0 0,0 0 0))',
      tgeometry '[Linestring(1 1 1,2 2 2)@2001-01-01, Point(2 2 2)@2001-01-03]');
    -- true
    
  • Is ever or always at distance within

    eDwithin({geo,tgeo},{geo,tgeo},float) → boolean

    aDwithin({geometry,tgeom},{geometry,tgeom},float) → boolean

    SELECT eDwithin(geometry 'Point(1 1 1)',
      tgeompoint '[Point(0 0 0)@2001-01-01, Point(1 1 0)@2001-01-02]', 1);
    -- true
    SELECT eDwithin(geometry 'Polygon((0 0 0,0 1 1,1 1 1,1 0 0,0 0 0))',
      tgeompoint '[Point(0 2 2)@2001-01-01,Point(2 2 2)@2001-01-02]', 1);
    -- false
    
  • Ever or always intersects

    eIntersects({geo,tgeo},{geo,tgeo}) → boolean

    aIntersects({geometry,tgeom},{geometry,tgeom}) → boolean

    SELECT eIntersects(geometry 'Polygon((0 0 0,0 1 0,1 1 0,1 0 0,0 0 0))',
      tgeompoint '[Point(0 0 1)@2001-01-01, Point(1 1 1)@2001-01-03)');
    -- false
    SELECT eIntersects(geometry 'Polygon((0 0 0,0 1 1,1 1 1,1 0 0,0 0 0))',
      tgeompoint '[Point(0 0 1)@2001-01-01, Point(1 1 1)@2001-01-03)');
    -- true
    
  • Ever or always touches

    eTouches({geometry,tgeom},{geometry,tgeom}) → boolean

    aTouches({geometry,tgeom},{geometry,tgeom}) → boolean

    SELECT eTouches(geometry 'Polygon((0 0,0 1,1 1,1 0,0 0))',
      tgeompoint '[Point(0 0)@2001-01-01, Point(0 1)@2001-01-03)');
    -- true
    

Spatiotemporal Relationships

We present next the spatiotemporal relationships. A common requirement regarding them is to restrict the result of the relationship to the instants when the value of the result is true or false. As an example, the following query computes for each trip the time spent traveling in the Brussels municipality.

SELECT TripId, duration(atValues(tintersects(T.trip, M.geom), True))
FROM Trips T, Municipality M
WHERE M.Name = "Brussels" AND atValues(tintersects(T.trip, M.geom), True) IS NOT NULL;

To simplify query writing, the spatiotemporal relationships have an optional last parameter, which if given applies the atValue function (see the section called “Restrictions”) to the result of the relationship. In this way, the above query can be written as follows.

SELECT TripId, duration(tintersects(T.trip, M.geom, True))
FROM Trips T, Municipality M
WHERE M.Name = "Brussels" AND tintersects(T.trip, M.geom, True) IS NOT NULL;
  • Temporal contains

    tContains(geometry,tgeom,atValue boolean=NULL) → tbool

    SELECT tContains(geometry 'Linestring(1 1,3 3)',
      tgeompoint '[Point(4 2)@2001-01-01, Point(2 4)@2001-01-02]');
    -- {[f@2001-01-01, f@2001-01-02]}
    SELECT tContains(geometry 'Linestring(1 1,3 3,1 1)',
      tgeompoint '[Point(4 2)@2001-01-01, Point(2 4)@2001-01-03]');
    -- {[f@2001-01-01, t@2001-01-02], (f@2001-01-02, f@2001-01-03]}
    SELECT tContains(geometry 'Polygon((1 1,1 3,3 3,3 1,1 1))',
      tgeompoint '[Point(0 1)@2001-01-01, Point(4 1)@2001-01-02]');
    -- {[f@2001-01-01, f@2001-01-02]}
    SELECT tContains(geometry 'Polygon((1 1,1 3,3 3,3 1,1 1))',
      tgeompoint '[Point(1 4)@2001-01-01, Point(4 1)@2001-01-04]');
    -- {[f@2001-01-01, f@2001-01-02], (t@2001-01-02, f@2001-01-03, f@2001-01-04]}
    
  • Temporal disjoint

    tDisjoint({geo,tgeo},{geo,tgeo},atValue boolean=NULL) → tbool

    The function only supports 3D or geographies for two temporal points

    SELECT tDisjoint(geometry 'Polygon((1 1,1 2,2 2,2 1,1 1))',
      tgeompoint '[Point(0 0)@2001-01-01, Point(3 3)@2001-01-04)');
    -- {[t@2001-01-01, f@2001-01-02, f@2001-01-03], (t@2001-01-03, t@2001-01-04]}
    SELECT tDisjoint(tgeompoint '[Point(0 3)@2001-01-01, Point(3 0)@2001-01-05)',
      tgeompoint '[Point(0 0)@2001-01-01, Point(3 3)@2001-01-05)');
    -- {[t@2001-01-01, f@2001-01-03], (t@2001-01-03, t@2001-01-05)}
    
  • Temporal distance within

    tDwithin({geo,tgeo},{geo,tgeo},float,atValue boolean=NULL) → tbool

    SELECT tDwithin(geometry 'Point(1 1)',
      tgeompoint '[Point(0 0)@2001-01-01, Point(2 2)@2001-01-03)', sqrt(2));
    --  {[t@2001-01-01, t@2001-01-03)}
    SELECT tDwithin(tgeompoint '[Point(1 0)@2001-01-01, Point(1 4)@2001-01-05]',
      tgeompoint 'Interp=Step;[Point(1 2)@2001-01-01, Point(1 3)@2001-01-05]', 1);
    -- {[f@2001-01-01, t@2001-01-02, t@2001-01-04], (f@2001-01-04, t@2001-01-05]}
    
  • Temporal intersects

    tIntersects({geo,tgeo},{geo,tgeo},atValue boolean=NULL) → tbool

    The function only supports 3D or geographies for two temporal points

    SELECT tIntersects(geometry 'MultiPoint(1 1,2 2)',
      tgeompoint '[Point(0 0)@2001-01-01, Point(3 3)@2001-01-04)');
    /* {[f@2001-01-01, t@2001-01-02], (f@2001-01-02, t@2001-01-03],
       (f@2001-01-03, f@2001-01-04]} */
    SELECT tIntersects(tgeompoint '[Point(0 3)@2001-01-01, Point(3 0)@2001-01-05)',
      tgeompoint '[Point(0 0)@2001-01-01, Point(3 3)@2001-01-05)');
    -- {[f@2001-01-01, t@2001-01-03], (f@2001-01-03, f@2001-01-05)}
    
  • Temporal touches

    tTouches({geometry,tgeom},{geometry,tgeom},atValue boolean=NULL) → tbool

    SELECT tTouches(geometry 'Polygon((1 0,1 2,2 2,2 0,1 0))',
      tgeompoint '[Point(0 0)@2001-01-01, Point(3 0)@2001-01-04)');
    -- {[f@2001-01-01, t@2001-01-02, t@2001-01-03], (f@2001-01-03, f@2001-01-04]}