Skip to main content
Some PDAL stages (for instance filters.delaunay) create TIN type mesh data. This data can be accessed in Python using the Pipeline.meshes property.

Accessing mesh data with Pipeline.meshes

The Pipeline.meshes property returns a numpy.ndarray of shape (1,n) where n is the number of triangles in the mesh. If the PointView contains no mesh data, then n = 0.
Like Pipeline.arrays, Pipeline.meshes returns a list of numpy.ndarray to provide for the case where the output from a Pipeline is multiple PointViews.

Triangle structure

Each Triangle is a tuple (A,B,C) where A, B and C are indices into the PointView identifying the point that is the vertex for the Triangle.
import pdal

pipeline = pdal.Reader("input.las") | pdal.Filter.delaunay()
pipeline.execute()

# Access mesh data
mesh = pipeline.meshes[0]
print(f"Number of triangles: {len(mesh)}")

# Each triangle contains three indices
for triangle in mesh[:10]:  # First 10 triangles
    a, b, c = triangle["A"], triangle["B"], triangle["C"]
    print(f"Triangle vertices: {a}, {b}, {c}")

Meshio integration with get_meshio()

The meshes property provides the face data but is not easy to use as a mesh. Therefore, PDAL Python provides optional integration into the Meshio library. The pdal.Pipeline class provides the get_meshio(idx: int) -> meshio.Mesh method. This method creates a Mesh object from the PointView array and mesh properties.
The meshio integration requires that meshio is installed (e.g. pip install meshio). If it is not, then the method fails with an informative RuntimeError.

Simple example

import pdal

pipeline = pdal.Reader("input.las") | pdal.Filter.delaunay()
pipeline.execute()

mesh = pipeline.get_meshio(0)
mesh.write('test.obj')

Advanced mesh use case

The following example demonstrates a real-world use case: Take a LiDAR map, create a mesh from the ground points, split into tiles and store the tiles in PostGIS.
This example uses 1.2-with-color.las and does not perform ground classification for clarity.
import pdal
import psycopg2
import io

pl = (
    pdal.Reader(".../python/test/data/1.2-with-color.las")
    | pdal.Filter.splitter(length=1000)
    | pdal.Filter.delaunay()
)
pl.execute()

conn = psycopg(%CONNNECTION_STRING%)
buffer = io.StringIO

for idx in range(len(pl.meshes)):
    m =  pl.get_meshio(idx)
    if m:
        m.write(buffer,  file_format = "wkt")
        with conn.cursor() as curr:
          curr.execute(
              "INSERT INTO %table-name% (mesh) VALUES (ST_GeomFromEWKT(%(ewkt)s)",
              { "ewkt": buffer.getvalue()}
          )

conn.commit()
conn.close()
buffer.close()
This pipeline:
  1. Reads a LAS file
  2. Splits the point cloud into 1000-unit tiles using filters.splitter
  3. Creates a Delaunay triangulation mesh for each tile
  4. Iterates through each mesh, converts it to WKT format using meshio
  5. Inserts each mesh into a PostGIS database as a geometry

Build docs developers (and LLMs) love