# Puntos de red temporales

Los puntos temporales que hemos considerado hasta ahora representan el movimiento de objetos que pueden moverse libremente en el espacio ya que se supone que pueden cambiar su posición de un lugar a otro sin ninguna restricción de movimiento. Este es el caso de los animales y de los objetos voladores como aviones o drones. Sin embargo, en muchos casos, los objetos no se mueven libremente en el espacio sino dentro de redes integradas espacialmente, como rutas o ferrocarriles. En este caso, es necesario tener en cuenta de las redes integradas al describir los movimientos de estos objetos en movimiento. Los puntos de red temporales tienen en cuenta estos requisitos.

En comparación con los puntos temporales de espacio libre, los puntos basados en red tienen las siguientes ventajas:

- Los puntos de red temporales proporcionan restricciones que reflejan los movimientos reales de los objetos en movimiento.

- La información geométrica no se almacena con el punto móvil, sino de una vez por todas en las redes fijas. De esta forma, las representaciones e interpolaciones de la ubicación son más precisas.

- Los puntos de red temporales son más eficientes en términos de almacenamiento de datos, actualización de ubicación, formulación de consultas e indexación. Estos aspectos se tratan más adelante en este documento.

Los puntos de red temporales se basan en pgRouting, una extensión de PostgreSQL para desarrollar aplicaciones de enrutamiento de red y realizar análisis de gráficos. Por lo tanto, los puntos de red temporal asumen que la red subyacente está definida en una tabla llamada `ways`, que tiene al menos tres columnas: `gid` que contiene el identificador de ruta único, `length` que contiene la longitud de la ruta y `the_geom` que contiene la geometría de la ruta.

Hay dos tipos de red estáticos, `npoint` (abreviatura de network point) y `nsegment` (abreviatura de network segment), que representan, respectivamente, un punto y un segmento de una ruta. Un valor `npoint` se compone de un identificador de ruta y un número flotante en el rango [0,1] que determina una posición relativa de la ruta, donde 0 corresponde al comienzo de la ruta y 1 al final de la ruta. Un valor de `nsegment` se compone de un identificador de ruta y dos números flotantes en el rango [0,1] que determinan las posiciones relativas de inicio y finalización. Un valor de `nsegment` cuyas posiciones inicial y final son iguales corresponde a un valor de `npoint`.

El tipo `npoint` sirve como tipo base para definir el tipo punto de red temporal `tnpoint`. El tipo `tnpoint` tiene una funcionalidad similar al tipo de punto temporal `tgeompoint` con la excepción de que solo considera dos dimensiones. Por lo tanto, todas las funciones y operadores descritos anteriormente para el tipo `tgeompoint` también son aplicables para el tipo `tnpoint`. Además, hay funciones específicas definidas para el tipo `tnpoint`.

## Tipos de red estáticos

Un valor `npoint` es un par de la forma `(rid, position)` donde `rid` es un valor `bigint` que representa un identificador de ruta y `position` es un valor `float` en el rango [0,1] que indica su posición relativa. Los valores 0 y 1 de `position` denotan, respectivamente, la posición inicial y final de la ruta. La distancia de la ruta entre un valor de `npoint` y la posición inicial de la ruta con el identificador `rid` se calcula multiplicando `position` por `length`, donde este último es la longitud de la ruta. Ejemplos de entrada de valores de puntos de red son los siguientes:

    SELECT npoint 'Npoint(76, 0.3)';
    SELECT npoint 'Npoint(64, 1.0)';

La función de constructor para puntos de red tiene un argumento para el identificador de ruta y un argumento para la posición relativa. Un ejemplo de un valor de punto de red definido con la función constructora es el siguiente:

    SELECT npoint(76, 0.3);

Un valor `nsegment` es un triple de la forma `(rid, startPosition, endPosition)` donde `rid` es un valor `bigint` que representa un identificador de ruta y `startPosition` y `endPosition` son valores de `float` en el rango [0,1] tal que `startPosition ≤ endPosition`. Semánticamente, un segmento de red representa un conjunto de puntos de red `(rid, position)` con `startPosition ≤ position ≤ endPosition`. Si `startPosition = 0` y `endPosition = 1`, el segmento de red es equivalente a la ruta completa. Si `startPosition = endPosition`, el segmento de red representa un único punto de red. Ejemplos de entrada de valores de puntos de red son los siguientes:

    SELECT nsegment 'Nsegment(76, 0.3, 0.5)';
    SELECT nsegment 'Nsegment(64, 0.5, 0.5)';
    SELECT nsegment 'Nsegment(64, 0.0, 1.0)';
    SELECT nsegment 'Nsegment(64, 1.0, 0.0)';
    -- convertido a nsegment 'Nsegment(64, 0.0, 1.0)';

Como se puede ver en el último ejemplo, los valores `startPosition` y `endPosition` se invertirán para asegurar que la condición `startPosition ≤ endPosition` siempre se satisface. La función de constructor para segmentos de red tiene un argumento para el identificador de ruta y dos argumentos opcionales para las posiciones inicial y final. Los ejemplos de valores de segmento de red definidos con la función constructora son los siguientes:

    SELECT nsegment(76, 0.3, 0.3);
    SELECT nsegment(76); -- se asume que las posiciones inicial y final son 0 y 1
    SELECT nsegment(76, 0.5); -- se asume que la posición final es 1

Los valores del tipo `npoint` se pueden convertir al tipo `nsegment` usando un `CAST` explícito o usando la notación `::` como se muestra a continuación.

    SELECT npoint(76, 0.33)::nsegment;

Los valores de los tipos de red estáticos deben satisfacer varias restricciones para que estén bien definidos. Estas restricciones se dan a continuación.

- El identificador de ruta `rid` debe encontrarse en la columna `gid` de la tabla `ways`.

- Los valores de `position`, `startPosition` y `endPosition` deben estar en el rango [0,1]. Se genera un error cuando no se cumple una de estas restricciones.

Ejemplos de valores de tipo de red estática incorrectos son los siguientes.

    -- Valor rid incorrecto
    SELECT npoint 'Npoint(87.5, 1.0)';
    -- Valor de posición incorrecto
    SELECT npoint 'Npoint(87, 2.0)';
    -- Valor rid inexistente en la table ways
    SELECT npoint 'Npoint(99999999, 1.0)';

Damos a continuación las funciones y operadores para los tipos de redes estáticas.

### Constructores

- Constructores de puntos o segmentos de red

  `npoint(bigint,double precision) → npoint`

  `nsegment(bigint,double precision,double precision) → nsegment`

      SELECT npoint(76, 0.3);
      SELECT nsegment(76, 0.3, 0.5);

### Conversión de tipos

Los valores de los tipos `npoint` y `nsegment` se pueden convertir al tipo `geometry` utilizando un `CAST` explícito o utilizando la notación `::` como se muestra a continuación. De manera similar, los valores `geometry` del subtipo `point` o `linestring` (restringidos a dos puntos) se pueden convertir, respectivamente, a valores `npoint` y `nsegment`. Para ello, se debe encontrar la ruta que interseca los puntos dados, donde se supone una tolerancia de 0,00001 unidades (según el sistema de coordenadas), por lo que se considera que un punto y una ruta que están cerca se intersecan. Si no se encuentra dicha ruta, se devuelve un valor nulo.

- Convertir entre un punto o un segmento de red y una geometría

  `{npoint,nsegment}::geometry`

  `geometry::{npoint,nsegment}`

      SELECT ST_AsText(npoint(76, 0.33)::geometry);
      -- POINT(21.6338731332283 50.0545869554067)
      SELECT ST_AsText(nsegment(76, 0.33, 0.66)::geometry);
      -- LINESTRING(21.6338731332283 50.0545869554067,30.7475989651999 53.9185062927473)
      SELECT ST_AsText(nsegment(76, 0.33, 0.33)::geometry);
      -- POINT(21.6338731332283 50.0545869554067)

      SELECT geometry 'SRID=5676;Point(279.269156511873 811.497076880187)'::npoint;
      -- NPoint(3,0.781413)
      SELECT geometry 'SRID=5676;LINESTRING(406.729536784738 702.58583437902,
        383.570801314823 845.137059419277)'::nsegment;
      -- NSegment(3,0.6,0.9)
      SELECT geometry 'SRID=5676;Point(279.3 811.5)'::npoint;
      -- NULL
      SELECT geometry 'SRID=5676;LINESTRING(406.7 702.6,383.6 845.1)'::nsegment;
      -- NULL

### Accesores

- Devuelve el identificador de ruta

  `route({npoint,nsegment}) → bigint`

      SELECT route(npoint 'Npoint(63, 0.3)');
      -- 63
      SELECT route(nsegment 'Nsegment(76, 0.3, 0.3)');
      -- 76

- Devuelve la posición

  `getPosition(npoint) → float`

      SELECT getPosition(npoint 'Npoint(63, 0.3)');
      -- 0.3

- Devuelve la posición inicial/final

  `startPosition(nsegment) → float`

  `endPosition(nsegment) → float`

      SELECT startPosition(nsegment 'Nsegment(76, 0.3, 0.5)');
      -- 0.3
      SELECT endPosition(nsegment 'Nsegment(76, 0.3, 0.5)');
      -- 0.5

### Transformaciones

- Redondear la(s) posición(es) del punto de red or el segmento de red en el número de posiciones decimales

  `round({npoint,nsegment},integer=0) → {npoint,nsegment}`

      SELECT round(npoint(76, 0.123456789), 6);
      --  NPoint(76,0.123457)
      SELECT round(nsegment(76, 0.123456789, 0.223456789), 6);
      --  NSegment(76,0.123457,0.223457)

### Operaciones espaciales

- Devuelve el identificador de referencia espacial

  `SRID({npoint,nsegment}) → integer`

      SELECT SRID(npoint 'Npoint(76, 0.3)');
      -- 5676
      SELECT SRID(nsegment 'Nsegment(76, 0.3, 0.5)');
      -- 5676

Dos valores `npoint` pueden tener diferentes identificadores de ruta pero pueden representar el mismo punto espacial en la intersección de las dos rutas. La función `equals` se utiliza para verificar la igualdad espacial de los puntos de la red.

- Igualdad espacial para puntos de red

  `equals(npoint, npoint)::Boolean`

      WITH inter(geom) AS (
        SELECT st_intersection(t1.the_geom, t2.the_geom)
        FROM ways t1, ways t2 WHERE t1.gid = 1 AND t2.gid = 2),
      fractions(f1, f2) AS (
        SELECT ST_LineLocatePoint(t1.the_geom, i.geom), ST_LineLocatePoint(t2.the_geom, i.geom)
        FROM ways t1, ways t2, inter i WHERE t1.gid = 1 AND t2.gid = 2)
      SELECT equals(npoint(1, f1), npoint(2, f2)) FROM fractions;
      -- true

### Comparaciones

Los operadores de comparación (=, < y así sucesivamente) para tipos de red estáticos requieren que los argumentos izquierdo y derecho sean del mismo tipo. Excepto la igualdad y la desigualdad, los otros operadores de comparación no son útiles en el mundo real pero permiten que los índices de árbol B se construyan en tipos de red estáticos.

- Comparaciones tradicionales

  `npoint {=, <>, <, >, <=, >=} npoint`

  `nsegment {=, <>, <, >, <=, >=} nsegment`

      SELECT npoint 'Npoint(3, 0.5)' = npoint 'Npoint(3, 0.5)';
      -- true
      SELECT npoint 'Npoint(3, 0.5)' <> npoint 'Npoint(3, 0.6)';
      -- true
      SELECT nsegment 'Nsegment(3, 0.5, 0.5)' < nsegment 'Nsegment(3, 0.5, 0.6)';
      -- true
      SELECT nsegment 'Nsegment(3, 0.5, 0.5)' > nsegment 'Nsegment(2, 0.5, 0.5)';
      -- true
      SELECT npoint 'Npoint(1, 0.5)' <= npoint 'Npoint(2, 0.5)';
      -- true
      SELECT npoint 'Npoint(1, 0.6)' >= npoint 'Npoint(1, 0.5)';
      -- true

## Puntos de red temporales

El tipo de punto de red temporal `tnpoint` permite representar el movimiento de objetos en una red. Corresponde al tipo de punto temporal `tgeompoint` restringido a coordenadas bidimensionales. Como todos los demás tipos temporales, se presenta en tres subtipos, a saber, instante, secuencia y conjunto de secuencias. A continuación se dan ejemplos de valores de `tnpoint` en estos subtipos.

    SELECT tnpoint 'Npoint(1, 0.5)@2001-01-01';
    SELECT tnpoint '{Npoint(1, 0.3)@2001-01-01, Npoint(1, 0.5)@2001-01-02,
      Npoint(1, 0.5)@2001-01-03}';
    SELECT tnpoint '[Npoint(1, 0.2)@2001-01-01, Npoint(1, 0.4)@2001-01-02,
      Npoint(1, 0.5)@2001-01-03]';
    SELECT tnpoint '{[Npoint(1, 0.2)@2001-01-01, Npoint(1, 0.4)@2001-01-02,
      Npoint(1, 0.5)@2001-01-03], [Npoint(2, 0.6)@2001-01-04, Npoint(2, 0.6)@2001-01-05]}';

El tipo de punto de red temporal acepta modificadores de tipo (o `typmod` en la terminología de PostgreSQL). Los valores posibles para el modificador de tipo son `Instant`, `Sequence` y `SequenceSet`. Si no se especifica ningún modificador de tipo para una columna, se permiten valores de cualquier subtipo.

    SELECT tnpoint(Sequence) '[Npoint(1, 0.2)@2001-01-01, Npoint(1, 0.4)@2001-01-02,
      Npoint(1, 0.5)@2001-01-03]';
    SELECT tnpoint(Sequence) 'Npoint(1, 0.2)@2001-01-01';
    -- ERROR: Temporal type (Instant) does not match column type (Sequence)

Los valores de puntos de red temporales del subtipo de secuencia et interpolación linear o escalonada deben definirse en una única ruta. Por lo tanto, se necesita un valor de subtipo de conjunto de secuencias para representar el movimiento de un objeto que atraviesa varias rutas, incluso si no hay un espacio temporal. Por ejemplo, en el siguiente valor

    SELECT tnpoint '{[NPoint(1, 0.2)@2001-01-01, NPoint(1, 0.5)@2001-01-03),
      [NPoint(2, 0.4)@2001-01-03, NPoint(2, 0.6)@2001-01-04)}';

el punto de red cambia su ruta en 2001-01-03.

Los valores de puntos de red temporal del subtipo de secuencia o conjunto de secuencias se convierten en una forma normal para que los valores equivalentes tengan representaciones idénticas. Para ello, los valores instantáneos consecutivos se fusionan cuando es posible. Tres valores instantáneos consecutivos se pueden fusionar en dos si las funciones lineales que definen la evolución de los valores son las mismas. Los ejemplos de transformación a una forma normal son los siguientes.

    SELECT tnpoint '[NPoint(1, 0.2)@2001-01-01, NPoint(1, 0.4)@2001-01-02,
      NPoint(1, 0.6)@2001-01-03)';
    -- [NPoint(1,0.2)@2001-01-01, NPoint(1,0.6)@2001-01-03)
    SELECT tnpoint '{[NPoint(1, 0.2)@2001-01-01, NPoint(1, 0.3)@2001-01-02,
      NPoint(1, 0.5)@2001-01-03), [NPoint(1, 0.5)@2001-01-03, NPoint(1, 0.7)@2001-01-04)}';
    -- {[NPoint(1,0.2)@2001-01-01, NPoint(1,0.3)@2001-01-02, NPoint(1,0.7)@2001-01-04)}

## Validez de los puntos de red temporal

Los valores de los puntos de red temporal deben satisfacer las restricciones especificadas en la ttype_validity para que estén bien definidos. Se genera un error cuando no se cumple una de estas restricciones. Ejemplos de valores incorrectos son los siguientes.

    -- No se permiten valores nulos
    SELECT tnpoint 'NULL@2001-01-01 08:05:00';
    SELECT tnpoint 'Point(0 0)@NULL';
    -- El tipo base no es un punto de red
    SELECT tnpoint 'Point(0 0)@2001-01-01 08:05:00';
    -- Múltiples rutas en una secuencia
    SELECT tnpoint '[Npoint(1, 0.2)@2001-01-01 09:00:00, Npoint(2, 0.2)@2001-01-01 09:05:00)';

Damos a continuación las funciones y operadores para los tipos de puntos de red. La mayoría de las funciones para tipos temporales descritas en los capítulos precendentes se pueden aplicar para tipos de puntos de red temporales. Por lo tanto, en las firmas de las funciones, la notación `base` también representa un `npoint` y las notaciones `ttype`, `tpoint` y `tgeompoint` también representan un `tnpoint`. Además, las funciones que tienen un argumento de tipo `geometry` aceptan además un argumento de tipo `npoint`. Para evitar la redundancia, a continuación solo presentamos algunos ejemplos de estas funciones y operadores para puntos de red temporales.

## Constructores

- Constructor para puntos de red temporales con valor constante

  `tnpoint(npoint,timestamptz) → tnpointInst`

  `tnpoint(npoint,tstzset) → tnpointDiscSeq`

  `tnpoint(npoint,tstzspan,interp='linear') → tnpointContSeq`

  `tnpoint(npoint,tstzspanset,interp='linear') → tnpointSeqSet`

      SELECT tnpoint('Npoint(1, 0.5)', timestamptz '2001-01-01');
      -- NPoint(1,0.5)@2001-01-01
      SELECT tnpoint('Npoint(1, 0.3)', tstzset '{2001-01-01, 2001-01-03, 2001-01-05}');
      -- {NPoint(1,0.3)@2001-01-01, NPoint(1,0.3)@2001-01-03, NPoint(1,0.3)@2001-01-05}
      SELECT tnpoint('Npoint(1, 0.5)', tstzspan '[2001-01-01, 2001-01-02]');
      -- [NPoint(1,0.5)@2001-01-01, NPoint(1,0.5)@2001-01-02]
      SELECT tnpoint('Npoint(1, 0.2)', tstzspanset '{[2001-01-01, 2001-01-03]}', 'step');
      -- Interp=Step;{[NPoint(1,0.2)@2001-01-01, NPoint(1,0.2)@2001-01-03]}

- Constructor para puntos de red temporal de subtipo secuencia

  `tnpointSeq(tnpointInst[],interp={'step','linear'},leftInc bool=true,`

  `rightInc bool=true) → tnpointSeq`

      SELECT tnpointSeq(ARRAY[tnpoint 'Npoint(1, 0.3)@2001-01-01',
        'Npoint(1, 0.5)@2001-01-02', 'Npoint(1, 0.5)@2001-01-03']);
      -- {NPoint(1,0.3)@2001-01-01, NPoint(1,0.5)@2001-01-02, NPoint(1,0.5)@2001-01-03}
      SELECT tnpointSeq(ARRAY[tnpoint 'Npoint(1, 0.2)@2001-01-01',
        'Npoint(1, 0.4)@2001-01-02', 'Npoint(1, 0.5)@2001-01-03']);
      -- [NPoint(1,0.2)@2001-01-01, NPoint(1,0.4)@2001-01-02, NPoint(1,0.5)@2001-01-03]

- Constructor para puntos de red temporal de subtipo conjunto de secuencias

  `tnpointSeqSet(tnpoint[]) → tnpointSeqSet`

  `tnpointSeqSetGaps(tnpointInst[],maxt=NULL,maxdist=NULL,interp='linear') →`

  `tnpointSeqSet`

      SELECT tnpointSeqSet(ARRAY[tnpoint '[Npoint(1,0.2)@2001-01-01, Npoint(1,0.4)@2001-01-02,
        Npoint(1,0.5)@2001-01-03]', '[Npoint(2,0.6)@2001-01-04, Npoint(2,0.6)@2001-01-05]']);
      /* {[NPoint(1,0.2)@2001-01-01, NPoint(1,0.4)@2001-01-02, NPoint(1,0.5)@2001-01-03],
         [NPoint(2,0.6)@2001-01-04, NPoint(2,0.6)@2001-01-05]} */
      SELECT tnpointSeqSetGaps(ARRAY[tnpoint 'NPoint(1,0.1)@2001-01-01',
        'NPoint(1,0.3)@2001-01-03', 'NPoint(1,0.5)@2001-01-05'], '1 day');
      -- {[NPoint(1,0.1)@2001-01-01], [NPoint(1,0.3)@2001-01-03], [NPoint(1,0.5)@2001-01-05]}

## Conversión de tipos

Un valor de punto de red temporal se puede convertir en y desde un punto de geometría temporal. Esto se puede hacer usando un `CAST` explícito o usando la notación `::`. Se devuelve un valor nulo si alguno de los valores de puntos de geometría que componen no se puede convertir en un valor `npoint`.

- Convertir entre un punto de red temporal y un punto de geometría temporal

  `tnpoint::tgeompoint`

  `tgeompoint::tnpoint`

      SELECT astext((tnpoint '[NPoint(1, 0.2)@2001-01-01,
        NPoint(1, 0.3)@2001-01-02)')::tgeompoint);
      /* [POINT(23.057077727326 28.7666335767956)@2001-01-01,
         POINT(48.7117553116406 20.9256801894708)@2001-01-02) */
      SELECT tgeompoint '[POINT(23.057077727326 28.7666335767956)@2001-01-01,
        POINT(48.7117553116406 20.9256801894708)@2001-01-02)'::tnpoint
      -- [NPoint(1,0.2)@2001-01-01, NPoint(1,0.3)@2001-01-02)
      SELECT tgeompoint '[POINT(23.057077727326 28.7666335767956)@2001-01-01,
        POINT(48.7117553116406 20.9)@2001-01-02)'::tnpoint
      -- NULL

## Accessores

- Devuelve los valores

  `getValues(tnpoint) → npoint[]`

      SELECT getValues(tnpoint '{[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-02)}');
      -- {"NPoint(1,0.3)","NPoint(1,0.5)"}
      SELECT getValues(tnpoint '{[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.3)@2001-01-02)}');
      -- {"NPoint(1,0.3)"}

- Devuelve los identificadores de ruta

  `routes(tnpoint) → bigintset`

      SELECT routes(tnpoint '{NPoint(3, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-02}');
      -- {1, 3}

- Devuelve el valor en una marca de tiempo

  `valueAtTimestamp(tnpoint,timestamptz) → npoint`

      SELECT valueAtTimestamp(tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-03)',
        '2001-01-02');
      -- NPoint(1,0.4)

- Devuelve la longitud atravesada por el punto de red temporal

  `length(tnpoint) → float`

      SELECT length(tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-02]');
      -- 54.3757408468784

- Devuelve la longitud acumulada atravesada por el punto de red temporal

  `cumulativeLength(tnpoint) → tfloat`

      SELECT cumulativeLength(tnpoint '{[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-02,
        NPoint(1, 0.5)@2001-01-03], [NPoint(1, 0.6)@2001-01-04, NPoint(1, 0.7)@2001-01-05]}');
      /* {[0@2001-01-01, 54.3757408468784@2001-01-02, 54.3757408468784@2001-01-03],
         [54.3757408468784@2001-01-04, 81.5636112703177@2001-01-05]} */

- Devuelve la velocidad del punto de red temporal en unidades por segundo

  `speed({tnpointSeq, tnpointSeqSet}) → tfloatSeqSet`

      SELECT speed(tnpoint '[NPoint(1, 0.1)@2001-01-01, NPoint(1, 0.4)@2001-01-02,
        NPoint(1, 0.6)@2001-01-03]') * 3600 * 24;
      /* Interp=Step;[21.4016800272077@2001-01-01, 14.2677866848051@2001-01-02,
         14.2677866848051@2001-01-03] */

## Transformaciones

- Transformar un punto de red temporal en otro subtipo

  `tnpointInst(tnpoint) → tnpointInst`

  `tnpointSeq(tnpoint,interp) → tnpointSeq`

  `tnpointSeqSet(tnpoint) → tnpointSeqSet`

      SELECT tnpointSeq(tnpoint 'NPoint(1, 0.5)@2001-01-01', 'discrete');
      -- {NPoint(1,0.5)@2001-01-01}
      SELECT tnpointSeq(tnpoint 'NPoint(1, 0.5)@2001-01-01');
      -- [NPoint(1,0.5)@2001-01-01]
      SELECT tnpointSeqSet(tnpoint 'NPoint(1, 0.5)@2001-01-01');
      -- {[NPoint(1,0.5)@2001-01-01]}

- Transformar un punto de red temporal en otra interpolación

  `setInterp(tnpoint, interp) → tnpoint`

      SELECT setInterp(tnpoint 'NPoint(1,0.2)@2001-01-01','linear');
      -- [NPoint(1,0.2)@2001-01-01]
      SELECT setInterp(tnpoint '{[NPoint(1,0.1)@2001-01-01], [NPoint(1,0.2)@2001-01-02]}',
        'discrete');
      -- {NPoint(1,0.1)@2001-01-01, NPoint(1,0.2)@2001-01-02}

- Redondear la fracción del punto de red temporal en el número de lugares decimales

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

      SELECT round(tnpoint '{[NPoint(1,0.123456789)@2001-01-01, NPoint(1,0.5)@2001-01-02)}', 6);
      -- {[NPoint(1,0.123457)@2001-01-01 00:00:00+01, NPoint(1,0.5)@2001-01-02 00:00:00+01)}

## Restricciones

- Restringir al (complemento de) un valor

  `atValues(tnpoint,values) → tnpoint`

  `minusValues(tnpoint,values) → tnpoint`

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

- Restringir al (complemento de) una geometría

  `atGeometry(tnpoint,geometry) → tnpoint`

  `minusGeometry(tnpoint,geometry) → tnpoint`

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

## Operaciones de distancia

- Devuelve la distancia más cercana

  `{geo,npoint,tnpoint} |=| {geo,npoint,tnpoint} → float`

  El operador `|=|` se puede utilizar para realizar búsquedas más cercanas utilizando un índice GiST o SP-GIST (ver ttype_indexing).

      SELECT tnpoint '[NPoint(2, 0.3)@2001-01-01, NPoint(2, 0.7)@2001-01-02]' |=|
         geometry 'SRID=5676;Linestring(50 50,55 55)';
      -- 31.69220882252415
      SELECT tnpoint '[NPoint(2, 0.3)@2001-01-01, NPoint(2, 0.7)@2001-01-02]' |=|
        npoint 'NPoint(1, 0.5)';
      -- 19.49691305292373
      SELECT tnpoint '[NPoint(2, 0.3)@2001-01-01, NPoint(2, 0.7)@2001-01-02]' |=|
        tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.7)@2001-01-02]';
      -- 5.231180723735304

- Devuelve el instante del primer punto de red temporal en el que los dos argumentos están a la distancia más cercana

  `nearestApproachInstant({geo,npoint,tnpoint},{geo,npoint,tnpoint}) → tnpoint`

      SELECT nearestApproachInstant(tnpoint '[NPoint(2, 0.3)@2001-01-01,
        NPoint(2, 0.7)@2001-01-02]', geometry 'Linestring(50 50,55 55)');
      -- NPoint(2,0.349928)@2001-01-01 02:59:44.402905+01
      SELECT nearestApproachInstant(tnpoint '[NPoint(2, 0.3)@2001-01-01,
        NPoint(2, 0.7)@2001-01-02]', npoint 'NPoint(1, 0.5)');
      -- NPoint(2,0.592181)@2001-01-01 17:31:51.080405+01

- Devuelve la línea que conecta el punto de aproximación más cercano entre los dos argumentos

  `shortestLine({geo,npoint,tpoint},{geo,npoint,tpoint}) → geometry`

  La función devuelve la primera línea que encuentre si hay más de una.

      SELECT ST_AsText(shortestLine(tnpoint '[NPoint(2, 0.3)@2001-01-01,
        NPoint(2, 0.7)@2001-01-02]', geometry 'Linestring(50 50,55 55)'));
      -- LINESTRING(50.7960725266492 48.8266286733015,50 50)
      SELECT ST_AsText(shortestLine(tnpoint '[NPoint(2, 0.3)@2001-01-01,
        NPoint(2, 0.7)@2001-01-02]', npoint 'NPoint(1, 0.5)'));
      -- LINESTRING(77.0902838115125 66.6659083092593,90.8134936900394 46.4385792121146)

- Devuelve la distancia temporal

  `tgeompoint <-> tnpoint → tfloat`

      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-03]' <->
        npoint 'NPoint(1, 0.2)';
      -- [2.34988300875063@2001-01-02 00:00:00+01, 2.34988300875063@2001-01-03 00:00:00+01]
      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-03]' <->
        geometry 'Point(50 50)';
      -- [25.0496666945044@2001-01-01 00:00:00+01, 26.4085688426232@2001-01-03 00:00:00+01]
      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-03]' <->
        tnpoint '[NPoint(1, 0.3)@2001-01-02, NPoint(1, 0.5)@2001-01-04]'
      -- [2.34988300875063@2001-01-02 00:00:00+01, 2.34988300875063@2001-01-03 00:00:00+01]

## Operaciones espaciales

- Devuelve el centroide ponderado en el tiempo

  `twCentroid(tnpoint) → geometry(Point)`

      SELECT ST_AsText(twCentroid(tnpoint '{[NPoint(1, 0.3)@2001-01-01,
        NPoint(1, 0.5)@2001-01-02, NPoint(1, 0.5)@2001-01-03, NPoint(1, 0.7)@2001-01-04)}'));
      -- POINT(79.9787466444847 46.2385558051041)

## Operaciones de cuadro delimitador

- Operadores topológicos

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

      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-02]' &&
        tstzspan '[2001-01-02,2001-01-03]';
      -- true
      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-02]' @>
        stbox(npoint 'NPoint(1, 0.5)');
      -- true
      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-03]' ~=
        tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.35)@2001-01-02,
        NPoint(1, 0.5)@2001-01-03]';
      -- true

- Operadores de posición

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

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

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

      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-02]' <<
        stbox(npoint 'NPoint(1, 0.2)');
      -- true
      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-02]' <<|
        stbox(npoint 'NPoint(1, 0.5)');
      -- false
      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-03, NPoint(1, 0.5)@2001-01-05]' #&>
        tstzspan '[2001-01-01,2001-01-03]';
      -- true
      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-03, NPoint(1, 0.3)@2001-01-05]' #>>
        tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.3)@2001-01-02]';
      -- true

## Relaciones espaciales

Las relaciones topológicas y de distancia descritas en tgeo_spatial_rel, como `eIntersects`, `aDwithin` o `tContains`, se definen en el espacio geográfico, mientras que los puntos de la red temporal se definen en el espacio de la red. Para aplicar estas relaciones espaciales a los puntos de la red temporal, estos deben transformarse en puntos geométricos temporales. Esto se puede realizar fácilmente mediante las funciones `geometry` y `tgeompoint` o mediante una conversión explícita de valores con `::`, como se muestra en los ejemplos a continuación.

- Relaciones alguna vez y siempre

      SELECT eContains(geometry 'SRID=5676;Polygon((0 0,0 50,50 50,50 0,0 0))',
        tgeompoint(tnpoint '[NPoint(1, 0.1)@2001-01-01, NPoint(1, 0.3)@2001-01-03)'));
      -- false
      SELECT eDisjoint(geometry(npoint 'NPoint(2, 0.0)'),
        tgeompoint(tnpoint '[NPoint(1, 0.1)@2001-01-01, NPoint(1, 0.3)@2001-01-03)'));
      -- true
      SELECT eIntersects(
        tnpoint '[NPoint(1, 0.1)@2001-01-01, NPoint(1, 0.3)@2001-01-03)'::tgeompoint,
        tnpoint '[NPoint(2, 0.0)@2001-01-01, NPoint(2, 1)@2001-01-03)'::tgeompoint);
      -- false

- Relaciones espaciotemporales

      SELECT tContains(geometry 'SRID=5676;Polygon((0 0,0 50,50 50,50 0,0 0))',
        tgeompoint(tnpoint '[NPoint(1, 0.1)@2001-01-01, NPoint(1, 0.3)@2001-01-03)'));
      -- [f@2001-01-01 00:00:00+01, f@2001-01-03 00:00:00+01)
      SELECT tDisjoint(geometry(npoint 'NPoint(2, 0.0)'),
        tgeompoint(tnpoint '[NPoint(1, 0.1)@2001-01-01, NPoint(1, 0.3)@2001-01-03)'));
      -- [t@2001-01-01 00:00:00+01, t@2001-01-03 00:00:00+01)
      SELECT tDwithin(
        tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-03)'::tgeompoint,
        tnpoint '[NPoint(1, 0.5)@2001-01-01, NPoint(1, 0.3)@2001-01-03)'::tgeompoint, 1);
      /* {[t@2001-01-01 00:00:00+01, t@2001-01-01 22:35:55.379053+01],
         (f@2001-01-01 22:35:55.379053+01, t@2001-01-02 01:24:04.620946+01,
         t@2001-01-03 00:00:00+01)} */

## Comparaciones

- Comparaciones tradicionales

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

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

- Comparaciones alguna vez y siempre

  `{npoint,tnpoint} {?=, %=} {npoint,tnpoint} → boolean`

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

- Comparaciones temporales

  `{npoint,tnpoint} {#=, #<>} {npoint,tnpoint} → tbool`

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

## Agregacions

Las tres funciones agregadas para puntos de red temporales se ilustran a continuación.

- Conteo temporal

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

      WITH Temp(temp) AS (
      SELECT tnpoint '[NPoint(1, 0.1)@2001-01-01, NPoint(1, 0.3)@2001-01-03)' UNION
      SELECT tnpoint '[NPoint(1, 0.2)@2001-01-02, NPoint(1, 0.4)@2001-01-04)' UNION
      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-03, NPoint(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)}

- Conteo de ventana

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

      WITH Temp(temp) AS (
      SELECT tnpoint '[NPoint(1, 0.1)@2001-01-01, NPoint(1, 0.3)@2001-01-03)' UNION
      SELECT tnpoint '[NPoint(1, 0.2)@2001-01-02, NPoint(1, 0.4)@2001-01-04)' UNION
      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-03, NPoint(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)} */

- Centroide temporal

  `tCentroid(tnpoint) → tgeompoint`

      WITH Temp(temp) AS (
      SELECT tnpoint '[NPoint(1, 0.1)@2001-01-01, NPoint(1, 0.3)@2001-01-03)' UNION
      SELECT tnpoint '[NPoint(1, 0.2)@2001-01-01, NPoint(1, 0.4)@2001-01-03)' UNION
      SELECT tnpoint '[NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.5)@2001-01-03)' )
      SELECT astext(tCentroid(Temp))
      FROM Temp
      /* {[POINT(72.451531682218 76.5231414472853)@2001-01-01,
         POINT(55.7001249027598 72.9552602410653)@2001-01-03)} */

## Indexación

Se pueden crear índices GiST y SP-GiST para columnas de tabla de puntos de redes temporales. A continuación, se muestra un ejemplo de creación de índice:

    CREATE INDEX Trips_Trip_SPGist_Idx ON Trips USING SPGist(Trip);

Los índices GiST y SP-GiST almacenan el cuadro delimitador para los puntos de la red temporal, que es un `stbox` y, por lo tanto, almacena las coordenadas absolutas del espacio subyacente.

Un índice GiST o SP-GiST puede acelerar las consultas que involucran a los siguientes operadores:

- `<<`, `&<`, `&>`, `>>`, `<<|`, `&<|`, `|&>`, `|>>`, que solo consideran la dimensión espacial en puntos de la red temporal,

- `<<#`, `&<#`, `#&>`, `#>>`, que solo consideran la dimensión temporal en puntos de la red temporal,

- `&&`, `@>`, `<@`, `~=`, `-|-` y `|=|`, que consideran tantas dimensiones como compartan la columna indexada y el argumento de consulta.

Estos operadores trabajan con cuadros delimitadores, no con los valores completos.