Goal

In this tutorial you will learn how to pre-process your point cloud data into a tiled and multi-leveled version. This allows to:

  • Combine multiple point cloud files into a single data set

  • Allows to visualize huge point cloud data sets by dividing the data into tiles, and providing multiple levels of detail

  • The tiled, multi-leveled version can be streamed using the OGC 3D Tiles protocol, making it suitable to be shown in a web client like LuciadRIA.

Pre-process point cloud data

Pre-processing point cloud data is done by creating a TLfnPointCloudPreprocessor instance.

//Use one or more las files as input files
List<String> sourceNames = Arrays.asList("Data/LAS/terrain_with_buildings.las");

//Create the preprocessor
TLfnPointCloudPreprocessor preprocessor =
    TLfnPointCloudPreprocessor.newBuilder()
                              .sources(sourceNames)
                              .targetDirectory(new File(System.getProperty("java.io.tmpdir"), "pointCloudStore").getAbsolutePath())
                              .name("Example Store")
                              .pointCloudCompression(ELcdOGC3DTilesPointCloudCompressionType.DRACO)
                              .build();

The pre-processor is created using a Builder class. Once the pre-processor is created, it can be started using the start() method:

preprocessor.start();

The pre-processor provides a getProgress() method which you can use to query it for its progress. You can for example call this method periodically, or attach a status listener to it.

In this tutorial, we opt for the listener which we attach to it before calling the start() method:

//Attach a listener to the preprocessor to keep track of the progress
preprocessor.addStatusListener(x -> {
  TLfnPointCloudPreprocessor.Progress progress = preprocessor.getProgress();
  System.out.println(String.format("Overall progress: %.2f%%", progress.getProgress() * 100));
  System.out.println("Details:");
  for (String source : sourceNames) {
    TLfnPointCloudPreprocessor.Progress.SourceDetails sourceDetails = progress.getSourceDetails(source);
    TLfnPointCloudPreprocessor.Progress.SourceDetails.Status status = sourceDetails.getStatus();
    System.out.println(String.format("%s: %s", source, status));
  }
  System.out.println();
});

This outputs

Overall progress: 0.00%
Details:
Data/LAS/terrain_with_buildings.las: PENDING

Overall progress: 95.00%
Details:
Data/LAS/terrain_with_buildings.las: SKIPPED

Visualizing the pre-processed point cloud

There are multiple options to visualize the pre-processed result:

  • The result is data in the LPC format which can directly be opened in LuciadLightspeed. See the LPC documentation for more information.

  • Use LuciadFusion Studio to serve the data using the OGC 3D Tiles protocol. Both LuciadLightspeed and LuciadRIA can visualize point clouds served using this protocol.

    This also allows to visualize the data in third party frameworks like Cesium.

Full code

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import com.luciad.format.tiled3d.ogc3dtiles.ELcdOGC3DTilesPointCloudCompressionType;
import com.luciad.fusion.pointcloud.TLfnPointCloudPreprocessor;

public class FusePointCloudTutorial {
  public static void main(String[] args) throws IOException {
    //Use one or more las files as input files
    List<String> sourceNames = Arrays.asList("Data/LAS/terrain_with_buildings.las");

    //Create the preprocessor
    TLfnPointCloudPreprocessor preprocessor =
        TLfnPointCloudPreprocessor.newBuilder()
                                  .sources(sourceNames)
                                  .targetDirectory(new File(System.getProperty("java.io.tmpdir"), "pointCloudStore").getAbsolutePath())
                                  .name("Example Store")
                                  .pointCloudCompression(ELcdOGC3DTilesPointCloudCompressionType.DRACO)
                                  .build();

    //Attach a listener to the preprocessor to keep track of the progress
    preprocessor.addStatusListener(x -> {
      TLfnPointCloudPreprocessor.Progress progress = preprocessor.getProgress();
      System.out.println(String.format("Overall progress: %.2f%%", progress.getProgress() * 100));
      System.out.println("Details:");
      for (String source : sourceNames) {
        TLfnPointCloudPreprocessor.Progress.SourceDetails sourceDetails = progress.getSourceDetails(source);
        TLfnPointCloudPreprocessor.Progress.SourceDetails.Status status = sourceDetails.getStatus();
        System.out.println(String.format("%s: %s", source, status));
      }
      System.out.println();
    });

    preprocessor.start();
  }
}