Un tpcpatch es la elevación temporal de pcpatch. Es el espejo de tpcpoint en todos los aspectos, mismos subtipos, mismas funciones de acceso, mismas conversiones y operadores, excepto que cada instante contiene un lote comprimido completo de puntos en lugar de un único punto. La caja delimitadora es de nuevo un tpcbox, calculada en O(1) por instante a partir del PCBOUNDS embebido en el parche.
Construir un pcpatch temporal de subtipo instante
tpcpatch(pcpatch,timestamptz) → tpcpatch
SELECT tempSubtype(tpcpatch(pcpatch(pcpoint(1, 1, 1, 1), pcpoint(1, 2, 2, 2)), '2001-01-01'::timestamptz)); -- Instant
Construir un pcpatch temporal de subtipo secuencia
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
Construir un pcpatch temporal de subtipo conjunto de secuencias
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
Se aplican todos los accesores temporales genéricos, además del pcid y el SRID al estilo de tpcpoint. Adicionalmente:
Devolver el número de puntos del parche contenido en el primer o último instante
startNumPoints(tpcpatch) → integer endNumPoints(tpcpatch) → integer
SELECT startNumPoints(tpcpatch(PC_Patch(PC_MakePoint(1, ARRAY[10.0, 20.0, 30.0])), '2024-02-01'::timestamptz)); -- 1
Devolver el número total de puntos de todos los parches de todos los instantes. Se lee directamente de la cabecera de cada parche, sin descompresión.
numPoints(tpcpatch) → bigint
SELECT numPoints(tpcpatchSeq(ARRAY[
tpcpatch(PC_Patch(ARRAY[PC_MakePoint(1, ARRAY[1.0, 1.0, 1.0]),
PC_MakePoint(1, ARRAY[2.0, 2.0, 2.0])]),
'2024-01-01'::timestamptz),
tpcpatch(PC_Patch(ARRAY[PC_MakePoint(1, ARRAY[3.0, 3.0, 3.0])]),
'2024-01-02'::timestamptz)]));
-- 3
Función devuelve-conjunto: emite una fila por cada (marca de tiempo de instante, punto) recorriendo el parche de cada instante y descomponiéndolo mediante la API C en memoria de pgPointCloud. Útil para combinar una columna tpcpatch con predicados por punto que los operadores de nivel de caja delimitadora no pueden expresar. El coste es O(total de puntos), una descompresión por instante más una emisión de fila por punto.
points(tpcpatch) → setof (t timestamptz, point pcpoint)
SELECT t, point FROM points(tpcpatch(
PC_Patch(ARRAY[PC_MakePoint(1, ARRAY[1.0, 1.0, 1.0]),
PC_MakePoint(1, ARRAY[2.0, 2.0, 2.0])]),
'2024-01-01'::timestamptz));
-- ('2024-01-01',
-- '01:0000000000000000000000F03F0000000000000000F03F00000000000000F03F'::pcpoint)
-- ('2024-01-01',
-- '01:0000000000000000000000004000000000000000400000000000000040'::pcpoint)
Véase “Operaciones por punto: qué está y qué no está disponible” para conocer los límites de estos accesores y qué está y qué no está disponible a nivel de granularidad por punto.
Transformar un tpcpatch en otro subtipo
tpcpatchInst(tpcpatch) → tpcpatch tpcpatchSeq(tpcpatch,interp='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
Transformar un tpcpatch a otra interpolación
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
Restringir un tpcpatch a (al complemento de) un valor pcpatch o un conjunto de valores pcpatch
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
Restringir un tpcpatch a los instantes cuyo parche supera una prueba de superposición aproximada de PCBOUNDS frente al tpcbox, o eliminarlos. La granularidad es a nivel de parche: cada instante superviviente conserva su payload pcpatch textualmente, sin descompresión por punto. Como el PCBOUNDS de pgPointCloud es 2D, la dimensión Z de la caja se ignora a esta granularidad. Devuelve NULL cuando el pcid del tpcbox no coincide.
atTpcbox(tpcpatch,tpcbox,border_inc boolean=TRUE) → tpcpatch minusTpcbox(tpcpatch,tpcbox,border_inc boolean=TRUE) → tpcpatch
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)]), tpcbox_xt(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)]), tpcbox_xt(0, 0, 2, 2, tstzspan '[2001-01-01, 2001-01-03]', 1))); -- 2
Variante por punto de la anterior: cada instante superviviente contiene un pcpatch recién construido que incluye solo los puntos dentro (o fuera, en el caso de minus) del tpcbox en 2D, y en 3D cuando la caja tiene dimensión Z. Los instantes cuyo parche filtra hasta cero puntos se descartan. Más lenta que la variante aproximada porque cada parche se descomprime y reconstruye; úsela cuando se necesite fidelidad a nivel de punto.
atTpcboxFine(tpcpatch,tpcbox,border_inc boolean=TRUE) → tpcpatch minusTpcboxFine(tpcpatch,tpcbox,border_inc boolean=TRUE) → tpcpatch
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)]), tpcbox_xt(0, 0, 1, 1, tstzspan '[2001-01-01, 2001-01-03]', 1))); -- 1
Restringir un tpcpatch a los puntos cuya proyección XY intersecta (o no intersecta, en el caso de minus) una geometría 2D. Z se ignora. El llamador debe garantizar la compatibilidad de SRID entre el esquema del parche y la geometría.
atGeometry(tpcpatch,geometry) → tpcpatch minusGeometry(tpcpatch,geometry) → tpcpatch
-- 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
Restringir un tpcpatch a los instantes anteriores o posteriores a una marca de tiempo. El indicador strict excluye el instante en la marca de tiempo misma
beforeTimestamp(tpcpatch,timestamptz,strict boolean=TRUE) → tpcpatch afterTimestamp(tpcpatch,timestamptz,strict boolean=TRUE) → tpcpatch
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]
Insertar un tpcpatch en otro, o actualizar otro con él
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
Eliminar un selector de tiempo (marca de tiempo, conjunto, período o conjunto de spans) de un tpcpatch
deleteTime(tpcpatch,timestamptz,connect boolean=TRUE) → tpcpatch deleteTime(tpcpatch,tstzset,connect boolean=TRUE) → tpcpatch deleteTime(tpcpatch,tstzspan,connect boolean=TRUE) → tpcpatch deleteTime(tpcpatch,tstzspanset,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
Añadir un instante o una secuencia a un 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
Devolver los valores distintos de un tpcpatch con el conjunto de spans durante el cual toma cada uno de ellos
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]}
Fragmentar un tpcpatch en fragmentos, uno por cada intervalo de tiempo
timeSplit(tpcpatch,bin_width 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
Devuelve el arreglo de lapsos de tiempo de los segmentos de un tpcpatch
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]"}
Devuelve los lapsos de tiempo de un tpcpatch dividido en un número dado de contenedores, o con un número dado de segmentos por contenedor
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]"}
Devolver verdadero si y solo si al menos un punto de alguno de los instantes del tpcpatch intersecta la geometría (solo XY).
eIntersects(tpcpatch,geometry) → boolean
Las relaciones alguna vez y siempre cubren la misma matriz: eContains, eCovers, eDisjoint, eIntersects, eTouches y eDwithin, cada una en los tres órdenes de argumentos, y sus gemelas siempre. eIntersects(tpcpatch,geometry) es la que el tipo responde de forma nativa, recorriendo los puntos de cada instante y deteniéndose en el primer acierto; las demás convierten el parche a la geometría temporal de sus multipuntos.
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
Convierte un parche temporal en la geometría temporal de los multipuntos que ocupan sus parches. El parche de cada instante se convierte en el multipunto de las posiciones que ocupan sus puntos, leídas a través del esquema que nombra su pcid
tgeometry(tpcpatch) → tgeometry
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
Las relaciones temporales calculan la relación topológica o de distancia en cada instante y dan como resultado un tbool. Un parche llega al motor de geometría a través de la conversión a tgeometry anterior, por lo que basta con que un punto del parche esté dentro del argumento para que el parche lo intersecte. Un tpcpatch lleva la Z que declara su esquema, y tContains, tCovers y tTouches son relaciones planas que rechazan una dimensión Z, de modo que el tipo responde las tres que un valor con Z puede responder.
Relaciones espaciales temporales
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
Un parche llega al motor de geometría como el multipunto de las posiciones que ocupan sus puntos, de modo que declara la matriz que declara la geometría temporal: cada predicado en cada dirección. Las planares responden para un esquema cuyas dimensiones no incluyen Z, y un esquema que lleva Z encuentra el rechazo 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]
La misma superficie de operadores de caja que en “Operadores de caja delimitadora” se aplica a tpcpatch. El predicado se evalúa sobre el tpcbox del valor, calculado en O(1) por instante a partir del PCBOUNDS embebido en el parche.
Predicados topológicos: &&, @>, <@, ~=, -|-. Véase “Operadores Topológicos”.
Predicados direccionales estrictos sobre los ejes X / Y / Z / tiempo (<<, >>, <<|, |>>, <</, />>, <<#, #>>) y sus variantes «solapa-o-X» (&<, &>, &<|, |&>, &</, /&>, &<#, #&>). Véase “Operadores de Posición”.
La distancia de aproximación más cercana (|=|) es ordenable KNN a través de la clase de operador GiST.
nearestApproachDistance(tpcpatch,tpcbox) → float nearestApproachDistance(tpcpatch,tpcpatch) → float
Comprobar si el valor en algún instante (alguna vez) o en todos los instantes (siempre) es igual a, o distinto de, un pcpatch u otro tpcpatch
eEq(pcpatch,tpcpatch) → boolean eEq(tpcpatch,pcpatch) → boolean eEq(tpcpatch,tpcpatch) → boolean
aEq, eNe y aNe reciben los mismos tres pares de argumentos
pcpatch ?= tpcpatch → boolean tpcpatch ?= pcpatch → boolean tpcpatch ?= tpcpatch → boolean
Los operadores %=, ?<> y %<> reciben los mismos tres pares de operandos
SELECT eEq(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 aEq(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
Devolver la igualdad o desigualdad temporal de un tpcpatch con un pcpatch o con otro tpcpatch, como un tbool
tEq(pcpatch,tpcpatch) → tbool tEq(tpcpatch,pcpatch) → tbool tEq(tpcpatch,tpcpatch) → tbool
tNe recibe los mismos tres pares de argumentos
pcpatch #= tpcpatch → tbool tpcpatch #= pcpatch → tbool tpcpatch #= tpcpatch → tbool
El operador #<> recibe los mismos tres pares de operandos
SELECT tEq(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]
La clase de operador tpcpatch_btree_ops produce un orden total sobre los valores tpcpatch, pero ese orden no es espacial. El comparador sobre el pcpatch subyacente es byte a byte (memcmp sobre los bytes varlena significativos); el comparador al nivel temporal es la combinación lexicográfica de las marcas de tiempo por instante y el orden de bytes de pcpatch por instante. Las consecuencias observables son:
pcid es el discriminador primario. Un parche con un pcid menor se ordena antes que uno con un pcid mayor, independientemente de las coordenadas de los puntos, su cantidad o la compresión. Esto hace que ORDER BY sobre una columna de pcid mixto agrupe las filas primero por esquema, lo que a veces resulta útil como paso de agrupación gruesa «por esquema de origen».
Dentro de un mismo pcid, el orden sigue la disposición de bytes en disco: esquema de compression, luego npoints, luego el PCBOUNDS 2D (xmin, xmax, ymin, ymax) y finalmente el payload data comprimido. Este orden está bien definido y es estable para una versión dada de pgPointCloud, pero no es un orden geométrico o espacial, dos parches cuyos cuadros delimitadores se superponen en el espacio 3D pueden ordenarse de forma arbitraria entre sí si difieren en su esquema de compresión o en el número de puntos.
La igualdad es igualdad exacta de bytes sobre los bytes significativos (se excluye el relleno de ceros al final que reserva el varlena de pgPointCloud). Dos parches construidos a partir del mismo conjunto de puntos en el mismo orden, con la misma compresión, son iguales; reordenar los puntos o cambiar la compresión los hace desiguales.
Para un orden con sentido espacial, use el operador KNN de GiST |=| (véase distancia de aproximación más cercana en tpcpatch); para un orden con sentido temporal, proyecte a startTimestamp o timespan y ordene sobre ese valor.
Las operaciones sobre valores tpcpatch se realizan a dos granularidades: nivel de parche y por punto. La distinción importa porque los parches de pgPointCloud almacenan sus puntos en un payload comprimido que la capa de caja delimitadora no puede inspeccionar.
Nivel de parche, soportado. El parche de cada instante se trata como opaco y se conserva o descarta como un todo, usando únicamente la cabecera PCBOUNDS de 4 valores double (xmin / xmax / ymin / ymax) y la marca de tiempo del instante. Esta es la granularidad de atTpcbox / minusTpcbox y de los operadores de caja delimitadora en “Operadores de caja delimitadora”, así como del agregado tpcbox basado en caja. No se produce descompresión del payload; las consultas son O(número de instantes).
Como PCBOUNDS es 2D, la dimensión Z de cualquier argumento tpcbox se ignora a esta granularidad, incluso cuando el esquema subyacente tiene dimensión Z.
Inspección por punto, soportada. La función devuelve-conjunto points emite una fila por cada (marca de tiempo de instante, punto) descomponiendo el parche de cada instante mediante la API C en memoria de pgPointCloud. El coste es O(total de puntos), una descompresión por instante más una emisión de fila por punto.
Filtrado / construcción por punto, soportado. atTpcboxFine / minusTpcboxFine, atGeometry / minusGeometry y eIntersects(tpcpatch, geometry) recorren en C cada punto de cada instante, aplicando su predicado sobre las coordenadas reales del punto en lugar de limitarse al cuadro delimitador del parche. Los instantes supervivientes contienen un parche recién construido que incluye solo los puntos que superaron el predicado; los instantes cuyos parches filtran hasta cero puntos se descartan.
El flujo de trabajo recomendado cuando ambas granularidades están disponibles es: (a) podar al nivel de parche con atTpcbox o un escaneo de índice SP-GiST/GiST para descartar los instantes completos cuyo PCBOUNDS no se superpone con el área de interés, y (b) refinar sobre los supervivientes con atTpcboxFine / atGeometry cuando se necesite fidelidad a nivel de punto.