Temporal Point Cloud Patches

A tpcpatch is the lifting of pcpatch. It mirrors tpcpoint in every regard, same subtypes, same accessors, same casts and operators, except that each instant carries an entire compressed batch of points instead of a single point. The bounding box is again a tpcbox, computed in O(1) per instant from the patch's embedded PCBOUNDS.

Operations on a tpcpatch come at two granularities, because the points of a patch sit in a compressed payload that the bounding box layer cannot inspect. At patch level each instant's patch is kept or dropped as a whole, read from its 4-double PCBOUNDS header (xmin / xmax / ymin / ymax) and the instant's timestamp alone: this is the granularity of atTpcbox / minusTpcbox, of the bounding box operators and of the extent aggregate, it decompresses no payload, and it costs O(number of instants). PCBOUNDS being 2D, the Z dimension of a tpcbox argument is ignored there even when the schema has one.

At point level every point of every instant is walked in C. points emits one row per instant timestamp and point, while atTpcboxFine / minusTpcboxFine, atGeometry / minusGeometry and eIntersects(tpcpatch,geometry) apply their predicate to the actual coordinates and rebuild each surviving instant from the points that passed, dropping the instants that keep none. Prune at patch level first, with atTpcbox or a GiST / SP-GiST index scan, and refine the survivors when point-level fidelity is needed.

Input and Output

  • Return the text representation of a tpcpatch, or of an array of them, and cast a tpcpatch to text

    asText(tpcpatch) → text
    asText(tpcpatch[]) → text[]
    tpcpatch::text → text
    
    -- The pcpatch payload renders as hex-encoded WKB.
    SELECT left(asText(tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz)), 24);
    -- EC0100000100000000000000
    
  • Return the Moving Features JSON (MF-JSON) representation

    asMFJSON(tpcpatch,options int=0,flags int=0,maxdecimaldigits int=15) → text
    

    A tpcpatch is emitted under the type tag "MovingPCPatch", each instant stating the object {"pcid":N, "npoints":N, "bounds":[xmin,xmax,ymin,ymax]}; the compressed point payload stays out of the JSON, so a lossless round trip goes through asBinary or asHexWKB.

    SELECT asMFJSON(tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz));
    /* {"type":"MovingPCPatch","values":[{"pcid":1,"npoints":2,"bounds":[1,2,1,2]}],
       "datetimes":["2001-01-01T00:00:00"],"interpolation":"None"} */
    

As for a tpcpoint, asText takes no maxdecimaldigits argument and there is no tpcpatchFromText. MF-JSON is output-only, its per-instant summary dropping the per-point payload; for a lossless round trip use asBinary / tpcpatchFromBinary or asHexWKB / tpcpatchFromHexWKB.

Constructors

  • Construct a temporal pcpatch of instant subtype

    tpcpatch(pcpatch,timestamptz) → tpcpatch
    
    SELECT tempSubtype(tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz));
    -- Instant
    
  • Construct a temporal pcpatch of sequence subtype

    tpcpatchSeq(tpcpatch[]) → tpcpatch
    tpcpatchSeq(tpcpatch[],text) → tpcpatch
    
    SELECT numInstants(tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)),
      '2001-01-02'::timestamptz)])), interp(tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)),
      '2001-01-02'::timestamptz)]));
    -- 2 | Step
    
  • Construct a temporal pcpatch of sequence-set subtype

    tpcpatchSeqSet(tpcpatch[]) → tpcpatch
    
    SELECT numSequences(tpcpatchSeqSet(ARRAY[tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3),
      pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz)])]));
    -- 1
    

Conversions

  • Convert a temporal patch into the temporal geometry of the multipoints its patches occupy

    tgeometry(tpcpatch) → tgeometry
    

    Each instant's patch becomes the multipoint of the positions its points occupy, read through the schema its pcid names

    SELECT asText(tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz)::tgeometry);
    -- MULTIPOINT Z ((1 1 1),(2 2 2))@2001-01-01
    

Accessors

  • Return the number of points in the patch carried by the first or last instant

    startNumPoints(tpcpatch) → integer
    endNumPoints(tpcpatch) → integer
    
    SELECT startNumPoints(tpcpatch(pcpatch(pcpoint(1, 10.0, 20.0, 30.0)),
      '2024-02-01'::timestamptz));
    -- 1
    
  • Return the total number of points across every instant's patch

    numPoints(tpcpatch) → bigint
    

    Read directly from each patch's header, no decompression.

    SELECT numPoints(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1.0, 1.0, 1.0),
      pcpoint(1, 2.0, 2.0, 2.0)), '2024-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3.0, 3.0, 3.0)), '2024-01-02'::timestamptz)]));
    -- 3
    
  • Set-returning function: emits one row per (instant timestamp, point) by walking each instant's patch and decomposing it through pgPointCloud's in-memory C API

    points(tpcpatch) → setof (t timestamptz,point pcpoint)
    

    Useful for joining a tpcpatch column against per-point predicates that the bbox-level operators can't express. Cost is O(total points), one per-instant decompression plus one row emission per point.

    SELECT t,
      point FROM points(tpcpatch(pcpatch(pcpoint(1, 1.0, 1.0, 1.0),
      pcpoint(1, 2.0, 2.0, 2.0)), '2024-01-01'::timestamptz));
    -- ('2024-01-01',
    -- '01:0000000000000000000000F03F0000000000000000F03F00000000000000F03F'::pcpoint)
    -- ('2024-01-01',
    -- '01:0000000000000000000000004000000000000000400000000000000040'::pcpoint)
    

Transformations

  • Transform a tpcpatch to another subtype

    tpcpatchInst(tpcpatch) → tpcpatch
    tpcpatchSeq(tpcpatch,interp text='step') → tpcpatch
    tpcpatchSeqSet(tpcpatch) → tpcpatch
    
    SELECT tempSubtype(tpcpatchSeq(tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz)));
    -- Sequence
    
  • Transform a tpcpatch to another interpolation

    setInterp(tpcpatch,interp) → tpcpatch
    
    SELECT interp(setInterp(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz)],
      'discrete'), 'step'));
    -- Step
    

Modifications

  • Insert a tpcpatch into another one, or update another one with it

    insert(tpcpatch,tpcpatch,connect boolean=true) → tpcpatch
    update(tpcpatch,tpcpatch,connect boolean=true) → tpcpatch
    
    SELECT numInstants(insert(tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)),
      '2001-01-02'::timestamptz)]), tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 5, 5, 5)), '2001-01-03'::timestamptz)])));
    -- 3
    
  • Delete a time selector (timestamp, set, period, or spanset) from a tpcpatch

    deleteTime(tpcpatch,time,connect boolean=true) → tpcpatch
    
    -- Deleting the middle instant splits the sequence into {[2001-01-01, 2001-01-02),
    -- (2001-01-02, 2001-01-03]}; each half stores its bound at the deleted timestamp, giving
    -- four instants.
    SELECT numInstants(deleteTime(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 5, 5, 5)), '2001-01-03'::timestamptz)]),
      timestamptz '2001-01-02'));
    -- 4
    
  • Append an instant or a sequence to a tpcpatch

    appendInstant(tpcpatch,tpcpatch) → tpcpatch
    appendSequence(tpcpatch,tpcpatch) → tpcpatch
    
    SELECT numInstants(appendInstant(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3),
      pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz)]),
      tpcpatch(pcpatch(pcpoint(1, 5, 5, 5)), '2001-01-03'::timestamptz)));
    -- 3
    

Restrictions

  • Restrict a tpcpatch to (the complement of) a pcpatch value or a set of pcpatch values

    atValue(tpcpatch,pcpatch) → tpcpatch
    minusValue(tpcpatch,pcpatch) → tpcpatch
    atValues(tpcpatch,pcpatchset) → tpcpatch
    minusValues(tpcpatch,pcpatchset) → tpcpatch
    
    -- The matching value is held up to the next instant; the closing bound is stored as a
    -- second instant.
    SELECT numInstants(atValue(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)),
      '2001-01-02'::timestamptz)]), pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2))));
    -- 2
    SELECT numInstants(minusValue(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)),
      '2001-01-02'::timestamptz)]), pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2))));
    -- 1
    
  • Restrict a tpcpatch to the instants whose patch passes a coarse PCBOUNDS overlap test against the tpcbox, or remove them

    atTpcbox(tpcpatch,tpcbox,border_inc boolean=true) → tpcpatch
    minusTpcbox(tpcpatch,tpcbox,border_inc boolean=true) → tpcpatch
    

    Granularity is patch-level: each surviving instant keeps its pcpatch payload verbatim, with no per-point decompression. Because pgPointCloud's PCBOUNDS is 2D, the Z dimension of the box is ignored at this granularity. Returns NULL when the tpcbox's pcid does not match.

    SELECT numInstants(atTpcbox(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3),
      pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz)]),
      tpcboxXT(0, 0, 2, 2, tstzspan '[2001-01-01, 2001-01-03]', 1)));
    -- 1
    -- The dropped patch stays present on the open interval before its instant,
    -- so the complement keeps two instants.
    SELECT numInstants(minusTpcbox(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3),
      pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz)]),
      tpcboxXT(0, 0, 2, 2, tstzspan '[2001-01-01, 2001-01-03]', 1)));
    -- 2
    
  • Restrict a tpcpatch to the points of each instant that the tpcbox holds, or remove them

    atTpcboxFine(tpcpatch,tpcbox,border_inc boolean=true) → tpcpatch
    minusTpcboxFine(tpcpatch,tpcbox,border_inc boolean=true) → tpcpatch
    

    Each surviving instant carries a freshly built pcpatch holding only the points inside, or outside for the minus form, the tpcbox in two dimensions, and in three when the box has a Z dimension. Instants whose patch filters to zero points are dropped. Slower than the coarse variant because every patch is decompressed and rebuilt; use when you need point-level fidelity.

    SELECT numInstants(atTpcboxFine(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3),
      pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz)]),
      tpcboxXT(0, 0, 1, 1, tstzspan '[2001-01-01, 2001-01-03]', 1)));
    -- 1
    
  • Restrict a tpcpatch to the points whose XY projection intersects (or does not intersect, for minus) a 2D geometry

    atGeometry(tpcpatch,geometry) → tpcpatch
    minusGeometry(tpcpatch,geometry) → tpcpatch
    

    Z is ignored. SRID compatibility between the patch schema and the geometry must be ensured by the caller.

    -- The polygon boundary touches the point (3 3) of the patch at 2001-01-02, so that patch
    -- survives both the at and the minus side.
    SELECT numInstants(atGeometry(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)),
      '2001-01-02'::timestamptz)]), geometry 'POLYGON((0 0, 0 3, 3 3, 3 0, 0 0))'));
    -- 2
    SELECT numInstants(minusGeometry(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)),
      '2001-01-02'::timestamptz)]), geometry 'POLYGON((0 0, 0 3, 3 3, 3 0, 0 0))'));
    -- 1
    
  • Restrict a tpcpatch to the instants before or after a timestamp

    beforeTimestamp(tpcpatch,timestamptz,strict boolean=true) → tpcpatch
    afterTimestamp(tpcpatch,timestamptz,strict boolean=true) → tpcpatch
    

    The strict flag excludes the instant at the timestamp itself

    SELECT timeSpan(beforeTimestamp(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 5, 5, 5)), '2001-01-03'::timestamptz)]),
      timestamptz '2001-01-02'));
    -- [2001-01-01, 2001-01-02)
    SELECT timeSpan(afterTimestamp(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 5, 5, 5)), '2001-01-03'::timestamptz)]),
      timestamptz '2001-01-02'));
    -- (2001-01-02, 2001-01-03]
    

Splitting Operations

  • Return the distinct values of a tpcpatch with the span set on which each of them is taken

    unnest(tpcpatch) → {(value,time)}
    
    SELECT (un).time FROM (SELECT unnest(tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)), '2024-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 5, 5, 5), pcpoint(1, 6, 6, 6)), '2024-01-02'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2024-01-03'::timestamptz)])) AS un) t;
    -- {[2024-01-02, 2024-01-03)}
    -- {[2024-01-01, 2024-01-02), [2024-01-03, 2024-01-03]}
    
  • Split a tpcpatch into fragments, one per time bin

    timeSplit(tpcpatch,duration interval,
      origin timestamptz='2000-01-03') → {(time,tpcpatch)}
    
    SELECT (ts).time, numInstants((ts).temp) FROM (SELECT timeSplit(tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)), '2024-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 5, 5, 5), pcpoint(1, 6, 6, 6)), '2024-01-02'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)),
      '2024-01-03'::timestamptz)]),
      interval '1 day', '2024-01-01'::timestamptz) AS ts) t;
    -- 2024-01-01 | 2
    -- 2024-01-02 | 2
    -- 2024-01-03 | 1
    
  • Return the array of time spans of a tpcpatch's segments

    spans(tpcpatch) → tstzspan[]
    
    SELECT spans(tpcpatchSeq(ARRAY[tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2024-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 5, 5, 5), pcpoint(1, 6, 6, 6)), '2024-01-02'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2024-01-03'::timestamptz)]));
    -- {"[2024-01-01, 2024-01-02]","[2024-01-02, 2024-01-03]"}
    
  • Return the time spans of a tpcpatch split into a given number of bins, or with a given number of segments per bin

    splitNSpans(tpcpatch,integer) → tstzspan[]
    splitEachNSpans(tpcpatch,integer) → tstzspan[]
    
    SELECT splitNSpans(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2024-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 5, 5, 5), pcpoint(1, 6, 6, 6)), '2024-01-02'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2024-01-03'::timestamptz)]), 2);
    -- {"[2024-01-01, 2024-01-02]","[2024-01-02, 2024-01-03]"}
    

Bounding Box Operations

The same bbox operator surface as the section called “Bounding Box Operations” applies to tpcpatch. The predicate evaluates against the value's tpcbox, computed in O(1) per instant from the patch's embedded PCBOUNDS.

  • Topological operators

    {tstzspan,tpcbox,tpcpatch} {&&, @>, <@, ~=, -|-} {tstzspan,tpcbox,tpcpatch} → boolean
    
    SELECT tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz)])
      && tstzspan '[2001-01-01, 2001-01-03]';
    -- true
    
  • Position operators

    {tpcbox,tpcpatch} {<<, >>, <<|, |>>, <</, />>} {tpcbox,tpcpatch} → boolean
    {tstzspan,tpcbox,tpcpatch} {<<#, #>>} {tstzspan,tpcbox,tpcpatch} → boolean
    
    SELECT tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz)])
      <<# tstzspan '[2001-01-05, 2001-01-06]';
    -- true
    

Distance Operations

  • Return the smallest distance ever

    nearestApproachDistance(tpcpatch,{tpcbox,tpcpatch}) → float
    
    SELECT round(nearestApproachDistance(tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 8, 8, 8), pcpoint(1, 9, 9, 9)),
      '2001-01-01'::timestamptz))::numeric, 4);
    -- 8.4853
    

Ever and Always Relationships

  • Return true iff at least one point in any of the tpcpatch's instants intersects the geometry (XY only)

    eIntersects(tpcpatch,geometry) → boolean
    

    The ever and always relationships cover the same matrix: eContains, eCovers, eDisjoint, eIntersects, eTouches and eDwithin, each in the three argument orders, and their always twins. eIntersects(tpcpatch,geometry) is the one the type answers natively, walking the points of each instant and stopping at the first hit; the rest convert the patch to the temporal geometry of its multipoints.

    SELECT eIntersects(tpcpatchSeq(ARRAY[ tpcpatch(pcpatch(pcpoint(1, 1, 1, 1),
      pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3),
      pcpoint(1, 4, 4, 4)), '2001-01-02'::timestamptz)]), geometry 'POINT(1 1)');
    -- t
    

Spatiotemporal Relationships

The temporal relationships compute the topological or distance relationship at each instant and result in a tbool. A patch reaches the geometry engine through the tgeometry conversion above, so one point of a patch inside the argument is enough for the patch to intersect it. A tpcpatch carries the Z its schema declares, and tContains, tCovers and tTouches are planar relationships that refuse a Z dimension, so the type answers the three that a Z-carrying value can.

  • Temporal spatial relationships

    tDisjoint({geometry,tpcpatch},{geometry,tpcpatch}) → tbool
    tDwithin({geometry,tpcpatch},{geometry,tpcpatch},float) → tbool
    tIntersects({geometry,tpcpatch},{geometry,tpcpatch}) → tbool
    tContains({geometry,tpcpatch},{geometry,tpcpatch}) → tbool
    tCovers({geometry,tpcpatch},{geometry,tpcpatch}) → tbool
    tTouches({geometry,tpcpatch},{geometry,tpcpatch}) → tbool
    

    A patch reaches the geometry engine as the multipoint of the positions its points occupy, so it declares the matrix that temporal geometry declares: every predicate in every direction. The planar ones answer for a schema whose dimensions do not include Z, and a schema carrying Z meets the refusal The tgeometry cannot have Z dimension.

    SELECT tIntersects(tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 9, 9, 9)),
      '2001-01-01'::timestamptz), geometry 'Polygon((0 0,0 2,2 2,2 0,0 0))');
    -- t@2001-01-01
    SELECT tDisjoint(tpcpatch(pcpatch(pcpoint(1, 9, 9, 9)), '2001-01-02'::timestamptz),
      geometry 'Polygon((0 0,0 2,2 2,2 0,0 0))');
    -- t@2001-01-02
    SELECT tDwithin(tpcpatch(pcpatch(pcpoint(1, 1, 1, 1)), '2001-01-01'::timestamptz),
      geometry 'Point(1 5)', 2.0);
    -- f@2001-01-01
    SELECT tIntersects(tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 9, 9, 9)), '2001-01-02'::timestamptz)]),
      geometry 'Polygon((0 0,0 2,2 2,2 0,0 0))');
    -- [t@2001-01-01, f@2001-01-02]
    

Comparisons

  • Ever and always comparisons

    {pcpatch,tpcpatch} {?=, %=, ?<>, %<>} {pcpatch,tpcpatch} → boolean
    
    SELECT pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)) ?= tpcpatchSeq(ARRAY[
      tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz),
      tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)),
      '2001-01-02'::timestamptz)]);
    -- t
    SELECT tpcpatchSeq(ARRAY[tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)),
      '2001-01-01'::timestamptz), tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)),
      '2001-01-02'::timestamptz)]) %= pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2));
    -- f
    
  • Temporal comparisons

    {pcpatch,tpcpatch} {#=, #<>} {pcpatch,tpcpatch} → tbool
    
    SELECT tpcpatchSeq(ARRAY[tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)),
      '2001-01-01'::timestamptz), tpcpatch(pcpatch(pcpoint(1, 3, 3, 3), pcpoint(1, 4, 4, 4)),
      '2001-01-02'::timestamptz)]) #= pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2));
    -- [t@2001-01-01, f@2001-01-02]