# Writing a kernel¶

Author: Bradley Chambers brad.chambers@gmail.com 11/02/2017

PDAL’s command-line application can be extended through the development of kernel functions. In this tutorial, we will give a brief example.

## The header¶

First, we provide a full listing of the kernel header.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // MyKernel.hpp #pragma once #include #include #include namespace pdal { class PDAL_DLL MyKernel : public Kernel { public: static void * create(); static int32_t destroy(void *); std::string getName() const; int execute(); // override private: MyKernel(); void addSwitches(ProgramArgs& args); std::string m_input_file; std::string m_output_file; }; } // namespace pdal 

As with other plugins, the MyKernel class needs to have the following three methods declared for the plugin interface to be satisfied:

    static void * create();
static int32_t destroy(void *);
std::string getName() const;


## The source¶

Again, we start with a full listing of the kernel source.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 // MyKernel.cpp #include "MyKernel.hpp" #include #include #include #include #include #include #include #include namespace pdal { static PluginInfo const s_info { "kernels.mykernel", "MyKernel", "http://link/to/documentation" }; CREATE_SHARED_PLUGIN(1, 0, MyKernel, Kernel, s_info); std::string MyKernel::getName() const { return s_info.name; } MyKernel::MyKernel() : Kernel() {} void MyKernel::addSwitches(ProgramArgs& args) { args.add("input,i", "Input filename", m_input_file).setPositional(); args.add("output,o", "Output filename", m_output_file).setPositional(); } int MyKernel::execute() { PointTable table; StageFactory f; Stage& reader = makeReader(m_input_file, "readers.las"); // Options should be added in the call to makeFilter, makeReader, // or makeWriter so that the system can override them with those // provided on the command line when applicable. Options filterOptions; filterOptions.add("step", 10); Stage& filter = makeFilter("filters.decimation", reader, filterOptions); Stage& writer = makeWriter(m_output_file, filter, "writers.text"); writer.prepare(table); writer.execute(table); return 0; } } // namespace pdal 

In your kernel implementation, you will use a macro defined in pdal_macros. This macro registers the plugin with the Kernel factory. It is only required by plugins.

  std::string MyKernel::getName() const { return s_info.name; }


Note

A static plugin macro can also be used to integrate the kernel with the main code. This will not be described here. Using this as a shared plugin will be described later.

To build up a processing pipeline in this example, we need to create two objects: the pdal::PointTable and the pdal::StageFactory. The latter is used to create the various stages that will be used within the kernel.

    StageFactory f;


The pdal::Reader is created from the pdal::StageFactory, and is specified by the stage name, in this case an LAS reader. For brevity, we provide the reader a single option, the filename of the file to be read.

    // Options should be added in the call to makeFilter, makeReader,
// or makeWriter so that the system can override them with those
// provided on the command line when applicable.


The pdal::Filter is also created from the pdal::StageFactory. Here, we create a decimation filter that will pass every tenth point to subsequent stages. We also specify the input to this stage, which is the reader.

    filterOptions.add("step", 10);
Stage& filter = makeFilter("filters.decimation", reader, filterOptions);

Stage& writer = makeWriter(m_output_file, filter, "writers.text");
writer.prepare(table);


Finally, the pdal::Writer is created from the pdal::StageFactory. This writers.text, takes as input the previous stage (the filters.decimation) and the output filename as its sole option.

    return 0;
}

} // namespace pdal


The final two steps are to prepare and execute the pipeline. This is achieved by calling prepare and execute on the final stage.

When compiled, a dynamic library file will be created; in this case, libpdal_plugin_kernel_mykernel.dylib

Put this file in whatever directory PDAL_DRIVER_PATH is pointing to. Then, if you run pdal --help, you should see mykernel listed in the possible commands.

To run this kernel, you would use pdal mykernel -i <input las file> -o <output text file>.

### Compilation¶

Set up a CMakeLists.txt file to compile your kernel against PDAL:

 1 2 3 4 5 6 7 8 9 cmake_minimum_required(VERSION 2.8.12) project(KernelTutorial) find_package(PDAL 1.6.0 REQUIRED CONFIG) add_library(pdal_plugin_kernel_mykernel SHARED MyKernel.cpp) target_link_libraries(pdal_plugin_kernel_mykernel PRIVATE ${PDAL_LIBRARIES}) target_include_directories(pdal_plugin_kernel_mykernel PRIVATE${PDAL_INCLUDE_DIRS})