Writing a kernel¶
Author: | Bradley Chambers |
---|---|
Contact: | brad.chambers@gmail.com |
Date: | 10/16/2016 |
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 <pdal/Kernel.hpp>
#include <pdal/plugin.hpp>
#include <string>
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 58 | // MyKernel.cpp
#include "MyKernel.hpp"
#include <pdal/Filter.hpp>
#include <pdal/Kernel.hpp>
#include <pdal/KernelFactory.hpp>
#include <pdal/Options.hpp>
#include <pdal/pdal_macros.hpp>
#include <pdal/StageFactory.hpp>
#include <pdal/PointTable.hpp>
#include <memory>
#include <string>
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.
CREATE_SHARED_PLUGIN(1, 0, MyKernel, Kernel, s_info);
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.
PointTable table;
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.
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
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.
Options filterOptions;
filterOptions.add("step", 10);
Stage& filter = makeFilter("filters.decimation", reader, filterOptions);
Stage& writer = makeWriter(m_output_file, filter, "writers.text");
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.
writer.execute(table);
return 0;
}
The final two steps are to prepare and execute the pipeline. This is achieved by calling prepare and execute on the final stage.
} // namespace pdal
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>
.