Integración con PDAL: readers.tpcpatch y writers.tpcpatch

MobilityDB incluye complementos PDAL nativos bajo contrib/pdal/ que leen y escriben valores tpcpatch directamente sin pasar por readers.pgpointcloud + tpcpatchSeq(). Compílelos con:

cd contrib/pdal
cmake -B build && cmake --build build -j
sudo cmake --install build

PDAL descubre los complementos mediante PDAL_DRIVER_PATH o, tras la instalación, en su ruta de búsqueda por defecto. Verifique con pdal --drivers | grep tpcpatch.

readers.tpcpatch

Lee cualquier consulta SQL que devuelva filas de (timestamp, pcpatch, pcid) y emite un PointView de PDAL con todas las dimensiones del esquema más una dimensión time_t que lleva microsegundos desde la época. La decodificación se delega a pc_patch_from_wkb de pgPointCloud, por lo que se manejan los tres tipos de compresión (PC_NONE, PC_DIMENSIONAL, PC_LAZPERF).

Para descomprimir un tpcpatch almacenado en filas por instante que el lector pueda consumir:

{
  "type": "readers.tpcpatch",
  "connection": "host=/tmp dbname=mydb",
  "query": "SELECT (EXTRACT(EPOCH FROM timestampN(traj, n))*1000000)::bigint AS t,
                   valueN(traj, n)              AS pcp,
                   PC_PCId(valueN(traj, n))     AS pcid
            FROM trajectories,
                 generate_series(1, numInstants(traj)) n
            WHERE id = 42
            ORDER BY n"
}

writers.tpcpatch

Recibe un PointView con una dimensión de tiempo configurable, agrupa los puntos por marca de tiempo en valores pcpatch por instante, luego despacha un INSERT, UPDATE, fusión-append o upsert contra una columna tpcpatch usando los constructores tpcpatch(pcpatch, timestamptz) + tpcpatchSeq(pcpatch[]) de MobilityDB. La codificación se delega a pc_patch_to_wkb de pgPointCloud con pc_patch_compress opcional. La escala / desplazamiento del esquema se aplica simétricamente — los valores fluyen como sus unidades semánticas (metros, grados, …) a través de PDAL incluso cuando el esquema los almacena como int32 escalado.

Opciones:

  • connection (posicional) — cadena de conexión libpq.

  • table (posicional) — nombre de la tabla de destino.

  • column — nombre de la columna tpcpatch (por defecto traj).

  • pcid (requerido) — entrada en pointcloud_formats cuyo esquema deben coincidir las dimensiones de entrada.

  • id_column, id_value — identifican la fila de destino para cualquier modo distinto de insert.

  • modeinsert (por defecto — nueva fila por ejecución de la tubería), update (sobrescribe la fila identificada por id_column = id_value), append (concatena mediante merge() sobre la fila existente), o upsert (inserta si está ausente, añade si está presente). append / update generan un error claro «matched no row» si no se encuentra id_value, por lo que no pueden ocurrir escrituras silenciosas de cero filas.

  • time_dim — nombre de la dimensión de tiempo de origen (por defecto time_t; establézcalo en GpsTime para consumir marcas de tiempo LAS directamente sin una etapa filters.assign).

  • time_format — interpretación de time_dim: unix_microseconds (por defecto), unix_seconds, o gps_adjusted (Tiempo GPS Estándar Ajustado LAS-1.4 — el escritor aplica el desplazamiento de época GPS-Unix y el offset de segundo intercalar de 2024).

  • compressionnone (por defecto), dimensional, o laz. MobilityDB normaliza el almacenamiento en disco de tpcpatch a PC_NONE, por lo que la opción solo afecta al tamaño de transporte libpq — la reducción típica es ~3x para dimensional en datos con dimensiones redundantes.

  • flush_threshold (por defecto 1024) — número de parches por instante completados almacenados en memoria antes de emitir un INSERT/append. Se respeta para mode=append/upsert; mode=insert/update difieren a un único vaciado final ya que cada ejecución de la tubería produce una única fila.

El escritor emite líneas de progreso periódicas de nivel Info mediante el registrador de PDAL y un resumen final en done(): total de puntos / parches escritos, columna de destino, pcid, compresión y modo. Visible con pdal pipeline -v 5.

Esquemas de compresión soportados

El lector y el escritor admiten los tres tipos de compresión de pgPointCloud: PC_NONE, PC_DIMENSIONAL y PC_LAZPERF. La regresión PC_LAZPERF en contrib/pdal/examples/test_lazperf.sql requiere que la instalación de pgPointCloud en ejecución esté compilada con --with-lazperf=DIR; el fixture SQL aborta con un mensaje claro en caso contrario. Los complementos se mantienen bajo contrib/pdal/ en lugar de en el árbol de compilación principal de MobilityDB para que puedan compilarse y actualizarse de forma independiente.

Limitaciones

  • Endianness de WKB. readers.tpcpatch acepta solo pcpatch WKB little-endian (NDR). Un parche big-endian (primer byte 0x00) se rechaza con un error claro en lugar de decodificarse mal silenciosamente. pgPointCloud emite NDR en toda plataforma común; el soporte XDR sería aditivo.

  • Compresión del tpcpatch almacenado. La opción compression de writers.tpcpatch controla solo la forma de transporte libpq. El tpcpatch de MobilityDB normaliza su almacenamiento de pcpatch en disco a PC_NONE.

  • Escritura en flujo. writers.tpcpatch implementa la interfaz Streamable::processOne de PDAL, por lo que una tubería readers.las → writers.tpcpatch se ejecuta en modo de flujo de PDAL automáticamente y nunca mantiene toda la nube de puntos en memoria. La cola de parches completados está limitada por la opción del escritor flush_threshold (por defecto 1024); en mode=append / mode=upsert cada vaciado activado por umbral emite un lote SQL incremental mediante merge(), mientras que mode=insert / mode=update difieren a un único vaciado final en done() (semántica de fila única). Esta es la ruta que hace tratable la ingesta de LAS de varios GB.