Plugin System#
ACloudViewer features a comprehensive plugin system that allows extending the application’s functionality without modifying the core code.
Overview#
The plugin system is designed to provide:
Extensibility: Add new features without recompiling the core application
Modularity: Plugins are self-contained and can be enabled/disabled independently
Standard API: All plugins follow a common interface defined by the Plugin API
Two Categories: IO plugins and Standard (processing) plugins
Plugin Architecture#
ACloudViewer Application
├── Core Libraries
│ ├── cloudViewer (3D processing)
│ ├── CV_db (database)
│ ├── CV_io (I/O operations)
│ └── PCLEngine (PCL integration)
│
└── Plugin System
├── CVPluginAPI (Plugin interface)
├── CVPluginStub (Plugin base classes)
└── plugins/core/
├── IO Plugins (file format support)
└── Standard Plugins (processing algorithms)
Plugin API#
All plugins must implement the base plugin interface defined in CVPluginAPI:
class ccPluginInterface {
public:
// Plugin metadata
virtual QString getName() const = 0;
virtual QString getDescription() const = 0;
virtual QIcon getIcon() const = 0;
// Plugin lifecycle
virtual void onStartup() = 0;
virtual void onShutdown() = 0;
// Action registration
virtual void registerActions(QMenu* menu) = 0;
};
IO Plugins#
IO plugins extend file format support for point clouds, meshes, and other 3D data.
Available IO Plugins#
Core IO
qCoreIO: Core file format support (PLY, PCD, XYZ, etc.)
qAdditionalIO: Additional formats (OBJ, STL, OFF, etc.)
qMeshIO: Advanced mesh formats (PLY, OBJ, STL, 3DS, etc.)
Point Cloud Formats
qLASIO: LAS/LAZ point cloud format
qLASFWFIO: LAS with full waveform support
qE57IO: ASTM E57 format for terrestrial laser scanning
qPDALIO: PDAL-based format support (multiple formats)
CAD/3D Formats
qDracoIO: Google Draco compressed geometry
qFBXIO: Autodesk FBX format
qStepCADImport: STEP CAD format
qPhotoscanIO: Agisoft Photoscan format
qRDBIO: RIEGL RDB format
Data Exchange
qCSVMatrixIO: CSV matrix data import/export
IO Plugin Interface#
class FileIOFilter : public ccPluginInterface {
public:
// File capabilities
virtual QStringList getFileFilters(bool onImport) const = 0;
virtual QString getDefaultExtension() const = 0;
virtual bool canLoadExtension(const QString& upperCaseExt) const = 0;
virtual bool canSave(CC_CLASS_ENUM type) const = 0;
// Load/Save operations
virtual CC_FILE_ERROR loadFile(
const QString& filename,
ccHObject& container,
LoadParameters& parameters) = 0;
virtual CC_FILE_ERROR saveToFile(
ccHObject* entity,
const QString& filename,
const SaveParameters& parameters) = 0;
};
Example: Using IO Plugins#
#include <FileIOFilter.h>
#include <ccPointCloud.h>
// Load a point cloud using the plugin system
ccHObject* container = new ccHObject("container");
FileIOFilter::LoadParameters params;
CC_FILE_ERROR result = FileIOFilter::LoadFromFile(
"mydata.las",
*container,
params
);
if (result == CC_FERR_NO_ERROR) {
ccPointCloud* cloud = static_cast<ccPointCloud*>(
container->getChild(0)
);
// Process the cloud...
}
Standard Plugins#
Standard plugins provide processing algorithms and analysis tools.
Available Standard Plugins#
Segmentation & Classification
qCSF: Cloth Simulation Filter for ground point filtering
qCanupo: Multi-scale classification plugin
qColorimetricSegmenter: Segmentation based on color information
qCloudLayers: Layer-based point cloud organization
qMasonry: Masonry structure analysis (auto/manual segmentation)
Geometric Analysis
qCompass: Structural geology analysis and compass tools
qFacets: Planar facet extraction and analysis
qHoughNormals: Normal estimation using Hough transform
qM3C2: Multiscale Model to Model Cloud Comparison
qMPlane: Multiple plane detection and fitting
qRANSAC_SD: RANSAC-based shape detection
qSRA: Surface of Revolution Analysis
Reconstruction & Modeling
qPoissonRecon: Poisson surface reconstruction
qCork: Boolean operations on meshes (union, difference, intersection)
q3DMASC: 3D Modeling And Shape Classification
Animation & Visualization
qAnimation: Create animations and camera paths
qG3Point: Geotechnical 3-point problem solver
Advanced Processing
qPCL: Integration with Point Cloud Library (PCL) algorithms
qTreeIso: Tree isolation and individual tree detection
qVoxFall: Voxel-based analysis and processing
Scripting & Automation
qJSonRPCPlugin: JSON-RPC interface for automation
qPythonRuntime: Python scripting support
Standard Plugin Interface#
class ccStdPluginInterface : public ccPluginInterface {
public:
// Plugin actions
virtual QList<QAction*> getActions() = 0;
// Action execution
virtual void onNewSelection(const ccHObject::Container& selectedEntities) = 0;
// Processing
virtual void doAction(QAction* action) = 0;
};
Example: Using Standard Plugins#
#include <ccPluginInterface.h>
#include <ccPointCloud.h>
// Example: Using CSF plugin for ground filtering
ccPluginInterface* csfPlugin = getPluginByName("CSF");
if (csfPlugin) {
ccPointCloud* cloud = loadPointCloud("terrain.las");
// Set input
ccHObject::Container selected;
selected.push_back(cloud);
csfPlugin->onNewSelection(selected);
// Execute ground filtering
QAction* filterAction = csfPlugin->getActions().first();
csfPlugin->doAction(filterAction);
}
Plugin Metadata (info.json)#
Each plugin includes an info.json file with metadata:
{
"type": "Standard",
"name": "CSF",
"icon": ":/CC/plugin/qCSF/icon.png",
"description": "Cloth Simulation Filter for ground point filtering",
"authors": [
{
"name": "Wuming Zhang",
"email": "wumingzh@gmail.com"
}
],
"maintainers": [
{
"name": "ACloudViewer Team",
"email": "support@cloudviewer.org"
}
],
"version": "1.5",
"min_version": "3.0.0",
"max_version": "4.0.0",
"references": [
{
"text": "CSF Algorithm Paper",
"url": "https://doi.org/10.1016/j.isprsjprs.2016.01.011"
}
]
}
Creating a New Plugin#
Step 1: Plugin Structure#
Create the following directory structure:
plugins/core/Standard/qMyPlugin/
├── CMakeLists.txt
├── info.json
├── include/
│ └── qMyPlugin.h
├── src/
│ └── qMyPlugin.cpp
├── ui/
│ └── myPluginDialog.ui (optional)
└── images/
└── icon.png
Step 2: Plugin Header#
// qMyPlugin.h
#ifndef Q_MY_PLUGIN_H
#define Q_MY_PLUGIN_H
#include <ccStdPluginInterface.h>
class qMyPlugin : public QObject, public ccStdPluginInterface {
Q_OBJECT
Q_INTERFACES(ccPluginInterface ccStdPluginInterface)
Q_PLUGIN_METADATA(IID "cccorp.cloudviewer.plugin.qMyPlugin" FILE "info.json")
public:
explicit qMyPlugin(QObject* parent = nullptr);
virtual ~qMyPlugin() = default;
// ccPluginInterface
QString getName() const override { return "My Plugin"; }
QString getDescription() const override { return "My custom plugin"; }
QIcon getIcon() const override;
void onStartup() override;
void onShutdown() override;
void registerActions(QMenu* menu) override;
// ccStdPluginInterface
QList<QAction*> getActions() override;
void onNewSelection(const ccHObject::Container& selectedEntities) override;
void doAction(QAction* action) override;
private slots:
void doMyAction();
private:
QAction* m_action;
};
#endif // Q_MY_PLUGIN_H
Step 3: Plugin Implementation#
// qMyPlugin.cpp
#include "qMyPlugin.h"
#include <ccPointCloud.h>
qMyPlugin::qMyPlugin(QObject* parent)
: QObject(parent)
, ccStdPluginInterface(":/CC/plugin/qMyPlugin/info.json")
, m_action(nullptr)
{
}
QIcon qMyPlugin::getIcon() const {
return QIcon(":/CC/plugin/qMyPlugin/icon.png");
}
void qMyPlugin::onStartup() {
// Plugin initialization
}
void qMyPlugin::onShutdown() {
// Plugin cleanup
}
void qMyPlugin::registerActions(QMenu* menu) {
if (!menu) return;
m_action = new QAction(getName(), this);
m_action->setToolTip(getDescription());
m_action->setIcon(getIcon());
connect(m_action, &QAction::triggered, this, &qMyPlugin::doMyAction);
menu->addAction(m_action);
}
QList<QAction*> qMyPlugin::getActions() {
return QList<QAction*>() << m_action;
}
void qMyPlugin::onNewSelection(const ccHObject::Container& selectedEntities) {
// Update action state based on selection
bool hasPointCloud = false;
for (ccHObject* entity : selectedEntities) {
if (entity->isA(CC_TYPES::POINT_CLOUD)) {
hasPointCloud = true;
break;
}
}
m_action->setEnabled(hasPointCloud);
}
void qMyPlugin::doAction(QAction* action) {
if (action == m_action) {
doMyAction();
}
}
void qMyPlugin::doMyAction() {
// Your plugin logic here
ccPointCloud* cloud = getCurrentPointCloud();
if (!cloud) return;
// Process the cloud...
}
Step 4: CMakeLists.txt#
# CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(qMyPlugin VERSION 1.0)
include(../../cmake/plugin.cmake)
# Source files
set(PLUGIN_SOURCES
src/qMyPlugin.cpp
)
set(PLUGIN_HEADERS
include/qMyPlugin.h
)
# UI files (optional)
set(PLUGIN_UI
ui/myPluginDialog.ui
)
# Resources (optional)
set(PLUGIN_QRC
qMyPlugin.qrc
)
# Create plugin
add_cloudviewer_plugin(
NAME ${PROJECT_NAME}
TYPE STANDARD
SOURCES ${PLUGIN_SOURCES}
HEADERS ${PLUGIN_HEADERS}
UI ${PLUGIN_UI}
QRC ${PLUGIN_QRC}
)
Step 5: Build and Install#
# Configure with plugin enabled
cd build
cmake -DPLUGIN_STANDARD_QMYPLUGIN=ON ..
# Build
make qMyPlugin -j$(nproc)
# The plugin will be installed to:
# - Linux: <install_prefix>/lib/cloudViewer/plugins/
# - macOS: ACloudViewer.app/Contents/PlugIns/
# - Windows: <install_prefix>/plugins/
Plugin Loading#
Plugins are automatically discovered and loaded at application startup:
Plugin Discovery: Application scans plugin directories
Metadata Loading: Reads
info.jsonfor each pluginVersion Checking: Verifies compatibility with application version
Plugin Instantiation: Creates plugin instances
Registration: Registers plugin actions in menus/toolbars
Plugin Directories#
Default plugin search paths:
Linux:
- /usr/lib/cloudViewer/plugins/
- ~/.local/share/cloudViewer/plugins/
- $CLOUDVIEWER_PLUGINS_PATH
macOS:
- ACloudViewer.app/Contents/PlugIns/
- ~/Library/Application Support/cloudViewer/plugins/
- $CLOUDVIEWER_PLUGINS_PATH
Windows:
- C:\Program Files\ACloudViewer\plugins\
- %APPDATA%\cloudViewer\plugins\
- %CLOUDVIEWER_PLUGINS_PATH%
Best Practices#
Thread Safety: Use Qt’s signal/slot mechanism for thread-safe operations
Error Handling: Always check return values and handle errors gracefully
Memory Management: Use Qt’s parent-child relationship for automatic cleanup
Progress Reporting: Use progress dialogs for long-running operations
Undo Support: Implement undo/redo for destructive operations
Documentation: Provide clear documentation and examples
Debugging Plugins#
Enable plugin debugging:
# Set environment variable
export CLOUDVIEWER_PLUGIN_DEBUG=1
# Run application
./ACloudViewer
Debug output will show: - Plugin discovery process - Loading successes/failures - Plugin initialization - Action registration
Further Reading#
Building from Source - Build ACloudViewer with plugins
Overview - C++ API overview
—
See Also:
Complete C++ API: Doxygen Documentation
Plugin source code: plugins/core/