Awesome
PDAL Java Bindings
Java bindings to use PDAL on JVM (supports PDAL >= 2.0). macOS users can experience some issues with bindings that were build against a different PDAL version, so try to use a consistent PDAL version.
It is released independently from PDAL itself as of PDAL 1.7.
See https://pdal.io/java.html for more info.
Table of Contents
Usage
You can use pdal-native
dep published into maven central in case you don't have installed JNI bindings and to avoid steps described below.
Dependency contains bindings for arm64-darwin
, and x86_64-linux
, other versions are not supported yet. We dropped x86_64-darwin
as of the PDAL Java 2.8.0
release.
Versioning scheme
Given a {major}.{minor}.{patch}
version:
{major}.{minor}
- matches the PDAL version it is published for- e.g. pdal-java of version
2.6.1
is suitable for all PDAL versions2.6.x
(2.6.0
, ...,2.6.3
, etc) major =2
, minor =6
- e.g. pdal-java of version
{patch}
- this portion of the version corresponds to updates within pdal-java and should remain compatible with PDAL library{major}.{minor}
versions- This implies that there may be multiple pdal-java releases for the same PDAL library version. All releases are compatible with the matching PDAL library
{major}.{minor}
version. Thus, higher patch versions are to be preferred.
- This implies that there may be multiple pdal-java releases for the same PDAL library version. All releases are compatible with the matching PDAL library
Using PDAL JNI With SBT
// pdal is published to maven central, but you can use the following repos in addition
resolvers ++=
Resolver.sonatypeOssRepos("releases") ++
Resolver.sonatypeOssRepos("snapshots") // for snaphots
// `<latest version>` refers to the version indicated by the badge above
libraryDependencies ++= Seq(
"io.pdal" %% "pdal" % "<latest version>", // core library
"io.pdal" % "pdal-native" % "<latest version>" // jni bindings
)
If you would like to use your own bindings, it is necessary to set java.library.path
:
// macOS X example with manual JNI installation
// cp -f native/target/resource_managed/main/native/arm64-darwin/libpdaljni.2.8.dylib /usr/local/lib/libpdaljni.2.8.dylib
// place built binary into /usr/local/lib, and pass java.library.path to your JVM
javaOptions += "-Djava.library.path=/usr/local/lib"
PDAL-Scala (Scala 2.x)
Scala API allows to build pipeline expressions instead of writing a raw JSON.
// `<latest version>` refers to the version indicated by the badge above
libraryDependencies ++= Seq(
"io.pdal" %% "pdal-scala" % "<latest version>", // scala core library
"io.pdal" % "pdal-native" % "<latest version>" // jni bindings
)
Scala API covers PDAL 2.0.x, to use any custom DSL that is not covered by the
current Scala API you can use RawExpr
type to build Pipeline Expression
.
Examples
Demo project with examples
JNI bindings basic usage examples can be found here.
PDAL Core (Scala 2.x / 3.x)
import io.pdal._
// pipeline definition
val json =
"""
|{
| "pipeline" : [
| {
| "filename" : "/path/to/las",
| "type" : "readers.las"
| },
| {
| "type" : "filters.crop"
| },
| {
| "filename" : "/path/to/new/las",
| "type" : "writers.las"
| }
| ]
|}
""".stripMargin
val pipeline = Pipeline(json, LogLevel.Debug5) // initialize and make it really noisy
pipeline.execute() // execute the pipeline
val metadata = pipeline.getMetadata() // retrieve metadata
val pvs = pipeline.getPointViews() // iterator over PointViews
val pv = 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 = pv.getPointCloud()
val x = 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 = pv.getDouble(0, DimType.Y)
// it is also possible to get access to the triangular mesh generated via PDAL
val mesh = pv.getTriangularMesh()
// the output is an Array of Triangles
// Each Triangle contains PointIds from the PDAL point table
val triangles = mesh.asArray
pv.close()
pvs.close()
pipeline.close()
PDAL Core (Java)
import io.pdal.*;
// pipeline definition
String json =
"""
{
"pipeline" : [
{
"filename" : "/path/to/las",
"type" : "readers.las"
},
{
"type" : "filters.crop"
},
{
"filename" : "/path/to/new/las",
"type" : "writers.las"
}
]
}
""";
var pipeline = new Pipeline(json, LogLevel.Debug5()); // initialize and make it really noisy
pipeline.execute(); // execute the pipeline
var metadata = pipeline.getMetadata(); // retrieve metadata
var pvs = pipeline.getPointViews(); // iterator over PointViews
var pv = 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]
var pointCloud = pv.getPointCloud();
var x = 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
var y = pv.getDouble(0, DimType.Y());
// it is also possible to get access to the triangular mesh generated via PDAL
var mesh = pv.getTriangularMesh();
// the output is an Array of Triangles
// Each Triangle contains PointIds from the PDAL point table
var triangles = mesh.asArray();
pv.close();
pvs.close();
pipeline.close();
PDAL Scala
import io.pdal._
import io.pdal.pipeline._
// To construct the expected json
val expected =
"""
|{
| "pipeline" : [
| {
| "filename" : "/path/to/las",
| "type" : "readers.las"
| },
| {
| "type" : "filters.crop"
| },
| {
| "filename" : "/path/to/new/las",
| "type" : "writers.las"
| }
| ]
|}
""".stripMargin
// The same, but using scala DSL
val pc = ReadLas("/path/to/las") ~ FilterCrop() ~ WriteLas("/path/to/new/las")
// The same, but using RawExpr, to support not implemented PDAL Pipeline API features
// RawExpr accepts a circe.Json type, which can be a json object of any desired complexity
val pcWithRawExpr = ReadLas("/path/to/las") ~ RawExpr(Map("type" -> "filters.crop").asJson) ~ WriteLas("/path/to/new/las")
// Create Pipelines from the constructed expressions
val pipeline = pc.toPipeline
val pipelineRaw = pcWithRawExpr.toPipline
Build
Development purposes (including binaries) compilation:
- Install PDAL (using brew / package managers (unix) / build from sources / Conda / etc)
- Install sbt (using brew / package managers (unix)) (only after
v2.4.x
) - Build native libs
sbt native/nativeCompile
(optionally, binaries would be built during tests run) orsbt native/publishLocal
for the built jar only - Run
sbt core/test
to run PDAL tests
Only Java development purposes compilation:
- Provide
$LD_LIBRARY_PATH
or$DYLD_FALLBACK_LIBRARY_PATH
- If you don't want to provide global variable you can pass
-Djava.library.path=<path>
into sbt:./sbt -Djava.library.path=<path>
- Set
PDAL_DEPEND_ON_NATIVE=false
(to disablenative
project build) - Run
PDAL_DEPEND_ON_NATIVE=false sbt
Finally the possible command to launch and build PDAL JNI bindings could be:
# Including binaries build
sbt
# Java side development without binaries build
PDAL_DEPEND_ON_NATIVE=false sbt -Djava.library.path=<path>
Possible issues and solutions
- In case of not installed as global PDAL change this line to:
set(CMAKE_CXX_FLAGS "$ENV{PDAL_LD_FLAGS} $ENV{PDAL_CXX_FLAGS} -std=c++11")
In this case sbt launch would be the following:
PDAL_LD_FLAGS=`pdal-config --libs` PDAL_CXX_FLAGS=`pdal-config --includes` sbt
- Sometimes can happen a bad dynamic linking issue (somehow spoiled environment),
the quick workaround would be to replace this line to:
set(CMAKE_CXX_FLAGS "-L<path to dynamic libs> -std=c++11")
- On macOS could be difficult to install PDAL sometimes (near new releases). You have three options
-
Install PDAL with conda
Here the PDAL conda guide
-
Install PDAL with brew
Just run
brew install pdal
-
Build PDAL from sources
Follow the official guide
- When using the Maven Central JARs on macOS, I get Library not loaded: @rpath/libpdalcpp.16.dylib
error
If you are sure PDAL is correctly installed, you can run pdal-config --libs
and take the path after the -L
argument
and assign it to the DYLD_FALLBACK_LIBRARY_PATH
:
❯ pdal-config --libs
-L/opt/homebrew/Cellar/pdal/2.6.3/lib -lpdalcpp
❯ export DYLD_FALLBACK_LIBRARY_PATH=/opt/homebrew/Cellar/pdal/2.6.3/lib
❯ java -jar my-pdal-proj.jar
How To Release
All the instructions related to the local / maven release process are documented in the HOWTORELEASE.txt file.
For the local publish it is possible to use the following commands:
scripts/publish-local.sh
- to publish Scala artifactsscripts/publish-local-native.sh
- to compile and publish artifact with native binaries For the additional information checkout the HOWTORELEASE.txt file and the scripts directory.