Java

PDAL provides Java bindings to use PDAL on JVM. It is released independently from PDAL itself as of PDAL 1.7. Native binaries are prebuilt for Linux and MacOS and delivered in a jar, so there is no need in building PDAL with a special flag or building JNI binaries manually.

The project consists of the following modules:

  • pdal-native - with packed OS specific libraries to link PDAL to JNI proxy classes. Dependency contains bindings for x86_64-darwin and x86_64-linux, other versions are not supported yet.

  • pdal - with the core bindings functionality.

  • pdal-scala - a Scala API package that simplifies PDAL Pipeline construction.

Versions

PDAL JNI major version usually follows PDAL versioning i.e. pdal-java 1.8.x was built and tested against PDAL 1.8.x and pdal-java 2.1.x against PDAL 2.x.x.

Using PDAL Java bindings

PDAL provides JNI bindings that gives users access to executing pipeline instantiations and capturing the results in Java interfaces. This mode of operation is useful if you are looking to have PDAL simply act as your data format and processing handler.

Users are expected to construct their own PDAL pipeline, execute it, and retrieve points into Java memory:

import io.pdal._

val json =
"""
  |{
  |  "pipeline":[
  |    {
  |      "filename":"1.2-with-color.las",
  |      "spatialreference":"EPSG:2993"
  |    },
  |    {
  |      "type": "filters.reprojection",
  |      "out_srs": "EPSG:3857"
  |    },
  |    {
  |       "type": "filters.delaunay"
  |    }
  |  ]
  |}
""".stripMargin

val pipeline = Pipeline(json)
pipeline.validate() // check if our JSON and options were good
pipeline.setLogLevel(8) // make it really noisy
pipeline.execute() // execute the pipeline
val metadata: String       = pipeline.getMetadata() // retrieve metadata
val pvs: PointViewIterator = pipeline.getPointViews() // iterator over PointViews
val pv: PointView          = pvs.next() // let's take the first PointView

// load all points into JVM memory
// PointCloud provides operations on PDAL points that
// are loaded in this case into JVM memory as a single Array[Byte]
val pointCloud: PointCloud = pv.getPointCloud()
val x: Double = pointCloud.getDouble(0, DimType.X) // get a point with PointId = 0 and only a single dimensions

// in some cases it is not neccesary to load everything into JVM memory
// so it is possible to get only required points directly from the PointView
val y: Double = pv.getDouble(0, DimType.Y)

// it is also possible to get access to the triangular mesh generated via PDAL
val mesh: TriangularMesh       = pv.getTriangularMesh()
// the output is an Array of Triangles
// Each Triangle contains PointIds from the PDAL point table
val triangles: Array[Triangle] = mesh.asArray

pv.close()
pipeline.close()

Using PDAL Scala

PDAL Scala project introduces a DSL to simplify PDAL Pipeline construction (this is the same pipeline from the section above):

import io.pdal._
import io.pdal.pipeline._

val expression =
  ReadLas("1.2-with-color.las", spatialreference = Some("EPSG:2993")) ~
  FilterReprojection("EPSG:3857") ~
  FilterDelaunay()

val pipeline = expression.toPipeline
pipeline.validate() // check if our JSON and options were good
pipeline.setLogLevel(8) // make it really noisy
pipeline.execute() // execute the pipeline
val metadata: String       = pipeline.getMetadata() // retrieve metadata
val pvs: PointViewIterator = pipeline.getPointViews() // iterator over PointViews
val pv: PointView          = pvs.next() // let's take the first PointView

// load all points into JVM memory
// PointCloud provides operations on PDAL points that
// are loaded in this case into JVM memory as a single Array[Byte]
val pointCloud: PointCloud = pv.getPointCloud()
val x: Double = pointCloud.getDouble(0, DimType.X) // get a point with PointId = 0 and only a single dimensions

// in some cases it is not neccesary to load everything into JVM memory
// so it is possible to get only required points directly from the PointView
val y: Double = pv.getDouble(0, DimType.Y)

// it is also possible to get access to the triangular mesh generated via PDAL
val mesh: TriangularMesh       = pv.getTriangularMesh()
// the output is an Array of Triangles
// Each Triangle contains PointIds from the PDAL point table
val triangles: Array[Triangle] = mesh.asArray

pv.close()
pipeline.close()

It covers PDAL 2.0.x, but to use any custom DSL that is not covered by the current Scala API you can use RawExpr type to build a Pipeline Expression:

import io.pdal._
import io.pdal.pipeline._
import io.circe.syntax._

val pipelineWithRawExpr =
  ReadLas("1.2-with-color.las") ~
  RawExpr(Map("type" -> "filters.crop").asJson) ~
  WriteLas("1.2-with-color-out.las")

Installation

PDAL Java artifacts are cross published for Scala 2.13, 2.12 and 2.11. However, if it is not required, a separate artifact that has no Scala specific artifact postfix is published as well.

// pdal is published to maven central, but you can use following repos in addition
resolvers ++= Seq(
  Resolver.sonatypeRepo("releases"),
  Resolver.sonatypeRepo("snapshots") // for snaphots
)

libraryDependencies ++= Seq(
  "io.pdal" %% "pdal" % "x.x.x",        // core library
  "io.pdal" %  "pdal-native" % "x.x.x", // jni binaries
  "io.pdal" %% "pdal-scala" % "x.x.x"   // if scala core library (if required)
)

The latest version is: https://search.maven.org/search?q=g:io.pdal

There is also an example SBT PDAL Demo project in the bindings repository, that can be used for a quick start.

Compilation

Development purposes (including binaries) compilation:
  1. Install PDAL (using brew / package managers (unix) / build from sources / etc)

  2. Build native libs ./sbt native/nativeCompile (optionally, binaries would be built during tests run)

  3. Run ./sbt core/test to run PDAL tests

Only Java development purposes compilation:
  1. Provide $LD_LIBRARY_PATH or $DYLD_LIBRARY_PATH

  2. If you don’t want to provide global variable you can pass -Djava.library.path=<path> into sbt:

./sbt -Djava.library.path=<path>

  1. Set PDAL_DEPEND_ON_NATIVE=false (to disable native project build)

  2. Run PDAL_DEPEND_ON_NATIVE=false ./sbt

If you would like to use your own bindings binary, it is necessary to set java.library.path:

// Mac OS X example with manual JNI installation
// cp -f native/target/resource_managed/main/native/x86_64-darwin/libpdaljni.2.1.dylib /usr/local/lib/libpdaljni.2.1.dylib
// place built binary into /usr/local/lib, and pass java.library.path to your JVM
javaOptions += "-Djava.library.path=/usr/local/lib"

You can use pdal-native dep in case you don’t have installed JNI bindings and to avoid steps described above. Dependency contains bindings for x86_64-darwin and x86_64-linux, other versions are not supported yet.