Plugin Creation: Difference between revisions
No edit summary |
|||
Line 14: | Line 14: | ||
In LabRPS, a plugin is a dynamic library that is discovered and loaded at run time as opposed to a dynamic library that an application is linked against at build time. LabRPS Plugins can therefore be written by users, using the well-defined plugin API that LabRPS provides. This allows the users to extend the functionality of the API in designated ways. | In LabRPS, a plugin is a dynamic library that is discovered and loaded at run time as opposed to a dynamic library that an application is linked against at build time. LabRPS Plugins can therefore be written by users, using the well-defined plugin API that LabRPS provides. This allows the users to extend the functionality of the API in designated ways. | ||
LabRPS plugin system consists of | LabRPS plugin system consists of three major features: The [[Plugin_API|Plugin API]] which is the API that users must compile and link against in order to create a plugin, the Plugin Manager which is an object (a singleton) in the LabRPS code that manages the life cycle of all plugins, that is, loading, registration, and unloading. This object can also be called the Plugin Registry and finally the [[Std_DlgRPSFeatures|Feature Manager]] which allows the user to manage, install and uninstall the RPS features contained inside the plugins. | ||
== The plugin structure, required files, and locations == | == The plugin structure, required files, and locations == |
Latest revision as of 17:57, 29 October 2024
Introduction
Plugins are used to extend the functionality of LabRPS. LabRPS has several types of plugins. For example, WindLab plugin, SeismicLab plugin, SeaLab plugin, and many others. LabRPS is already distributed with many different plugins. You can also search various plugins on the LabRPS official site or the LabRPS Addons GitHub repository to see if someone has already created a plugin that suits your needs. If not, this article will guide you through the process of creating your plugin. This page will show you how to add a new plugin to LabRPS. Plugins are containers for LabRPS features. They can be coded in C++, or in a mix of C++ and Python, which has the advantage to ally the speed of C++ to the flexibility of Python. They can be installed from the Addon Manager or installed manually by downloading from some online repository. For now, plugins cannot be developed in Python-only. If this is your first coding contribution to LabRPS, make sure you download and compile the LabRPS source code first.
LabRPS Plugins
In LabRPS, a plugin is a dynamic library that is discovered and loaded at run time as opposed to a dynamic library that an application is linked against at build time. LabRPS Plugins can therefore be written by users, using the well-defined plugin API that LabRPS provides. This allows the users to extend the functionality of the API in designated ways. LabRPS plugin system consists of three major features: The Plugin API which is the API that users must compile and link against in order to create a plugin, the Plugin Manager which is an object (a singleton) in the LabRPS code that manages the life cycle of all plugins, that is, loading, registration, and unloading. This object can also be called the Plugin Registry and finally the Feature Manager which allows the user to manage, install and uninstall the RPS features contained inside the plugins.
The plugin structure, required files, and locations
You need a folder, with any name you like, placed in the user Mod directory. it is recommended to give this folder the name of the plugin. The location you place your plugin folder under the Mod directory depends on the type of plugin you are developing. If your plugin is a WindLab plugin, you should put your plugin folder under /Mod/WindLabPlugins. This folder should contain a MyFirstPlugin.txt
text file. This file contains meta-information describing your plugin. Just copy this file from any other existing plugin and modify it for your needs. The MyFirstPlugin.txt
file is executed when LabRPS scans the directory to discover available plugins. That's all it needs for LabRPS to find your plugin. Until now, the file that represents your plugin have not been created yet. A plugin in LabRPS is a dynamic library such as a .dll file on Windows, or a .dylib on Mac, or .so on Linux. In order to create thise library you need to add a .cpp (MyFirstPlugin.cpp
) file to your folder. LabRPS uses CMake as its main build system, as it's available on all major operating systems. Compiling with CMake is usually very simple. So, you need to add the CMakeLists.txt
to the folder.
The user Mod directory is a sub-directory of the user application data directory (you can find the latter by typing App.getUserAppDataDir()
in the Python console):
- On Linux it is usually /home/<username>/.local/share/LabRPS/Mod/.
- On Windows it is %APPDATA%\LabRPS\Mod\, which is usually C:\Users\<username>\Appdata\Roaming\LabRPS\Mod\.
- On macOS it is usually /Users/<username>/Library/Application Support/LabRPS/Mod/.
Your plugin folder should look like this on windows:
/Mod/ +-- WindLabPlugins/ +-- MyFirstPlugin/ +-- MyFirstPlugin.txt +-- MyFirstPlugin.cpp +-- CMakeLists.txt
The MyFirstPlugin.txt file
# -*- coding: utf-8 -*- # (c) My Name 2080 __Name__ = "MyFirstPlugin" __Comment__ = "This plugin adds great functionalities to LabRPS" __License__ = "LGPL v 2.1" __Web__ = "" __Wiki__ = "https://wiki.labrps.com/Plugin_MyFirst" __Icon__ = "" __Help__ = "" __Author__ = "My Name" __Version__ = "1.0" __Status__ = "" __Requires__ = "" __Files__ = "MyFirstPlugin.dll" __Date__ = "25-08-2024" __Phenomenon__ = "Wind Velocity" __RPSVersion__ = "0.1"
You can choose any license you like for your plugin, but be aware that if you wish to see your plugin integrated into and distributed with the LabRPS source code at some point, it needs to be LGPL2+ like the example above. See License.
The MyFirstPlugin.cpp file
#include <Mod/WindLabAPI/App/RPSWindLabPluginAPI.h> PLUGIN_NAME("MyFirstPlugin"); RANDOM_PHENOMENON("Wind Velocity"); PLUGIN_AUTHOR("My Name"); PLUGIN_DESCRIPTION("This plugin adds a great feature for the simulation of random wind velocity"); PLUGIN_VERSION("1.00"); LABRPS_VERSION("0.1"); API_VERSION("0.1"); PLUGIN_RELEASE_DATE("15/06/2080"); PLUGIN_INIT_TYPE() { return 1; } PLUGIN_INIT() { return 1; } INSTALL_PLUGIN() { return 1; } UNINSTALL_PLUGIN() { return 1; }
The CMakeLists.txt file
include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src ${CMAKE_CURRENT_BINARY_DIR} ) set(MyFirstPlugin_LIBS LabRPSGui WindLabAPI GeneralTools WindLabTools ) SET(MyFirstPlugin_SRCS MyFirstPlugin.cpp ) SET(Metadata_Files MyFirstPlugin.txt ) add_library(MyFirstPlugin SHARED ${MyFirstPlugin_SRCS} ${Metadata_Files}) target_link_libraries(MyFirstPlugin ${MyFirstPlugin_LIBS}) SET_BIN_DIR(MyFirstPlugin MyFirstPlugin /Plugins/WindLabWorkbench/MyFirstPlugin) rps_copy_sources(MyFirstPlugin "${CMAKE_BINARY_DIR}/Plugins/WindLabWorkbench/MyFirstPlugin" ${Metadata_Files}) INSTALL(TARGETS MyFirstPlugin DESTINATION "${CMAKE_INSTALL_PREFIX}/Plugins/WindLabWorkbench/MyFirstPlugin") INSTALL(FILES MyFirstPlugin.txt DESTINATION "${CMAKE_INSTALL_PREFIX}/Plugins/WindLabWorkbench/MyFirstPlugin")
Now, your plugin is almost ready. if you run cmake, your dynamic library project will be generated depending on your system and the IDE you use. After you successfully build the project, a .dll file on Windows, or a .dylib on Mac, or .so on Linux will be generated under your plugin folder and will also be copied to /Plugins/WindLabWorkbench/MyFirstPlugin/. This file is your plugin file. For now, it can be discovered by LabRPS Plugin Manager, it can be loaded, initialized, installed and uninstalled. But it does not add any feature to LabRPS yet. If you want your plugin to add some features to LabRPS, then you need to implement some of the interfaces provided by the corresponding plugin API. The following section will show how to add new feature to LabRPS through your plugin.
Adding new feature
There are two main types of object in LabRPS: geometrical representation and 3D visualization object (GeoFeature) and random phenomenon simulation object (RPSFeature). An object that is created for example to add some functionalities to LabRPS for the simulation of random wind velocity is called WindLabFeature which is a class derived from RPSFeature. A WindLabFeature must belong to a feature group and must have a feature type. We can also say that, a feature type of a given feature group is required to create a feature. Multiple features of same feature group and feature type can be created.
Feature | Feature Group | Feature Type |
---|---|---|
MyFirstSpectrum | Along Wind Spectrum | Kaimal Spectrum |
MySecondSpectrum | Along Wind Spectrum | Kaimal Spectrum |
MyThirdSpectrum | Along Wind Spectrum | Davenport Spectrum |
MyFirstSpectrum and MySecondFeature from the same feature group and type but may have different properties and parameters values. In fact, your plugin adds new feature type. In order to do this, you need to implement the corresponding API interface based on your feature group. Meaning your have to derive a C++ class from an API interface as follows assuming that your feature group is Location Distribution.
// MyLocations.h #ifndef WINDLAB_PLUGIN_MYLOCATIONS_H #define WINDLAB_PLUGIN_MYLOCATIONS_H #include <Mod/WindLabAPI/App/IrpsWLLocationDistribution.h> namespace WindLab { class MyLocations: public WindLabAPI::IrpsWLLocationDistribution { public: MyLocations(); ~MyLocations() {}; bool ComputeLocationCoordinateMatrixP3(const WindLabAPI::WindLabSimuData &Data, mat &dLocCoord); bool OnInitialSetting(const WindLabAPI::WindLabSimuData &Data); }; } // namespace App #endif // WINDLAB_PLUGIN_GENERALSD_H
// MyLocations.cpp #include "MyLocations.h" #include <Mod/WindLabAPI/App/WindLabSimuData.h> using namespace std; using namespace WindLab; using namespace WindLabAPI; MyLocations::MyLocations() { } bool MyLocations::ComputeLocationCoordinateMatrixP3(const WindLabAPI::WindLabSimuData &Data, mat &dLocCoord) { for (int loop = 0; loop < Data.numberOfSpatialPosition.getValue(); loop++) { dLocCoord(loop, 0) = loop + 1; dLocCoord(loop, 1) = 5 * loop; dLocCoord(loop, 2) = 0; dLocCoord(loop, 3) = 0; } return true; } bool MyLocations::OnInitialSetting(const WindLabAPI::WindLabSimuData &Data) { return true; }
Object Initialization and registration
You have a new feature type but its initialization and registration mechanism is not implemented yet. You need to modify the four functions PLUGIN_INIT_TYPE(), PLUGIN_INIT(), INSTALL_PLUGIN() and UNINSTALL_PLUGIN() of your plugin file (MyFirstPlugin.cpp
) as follows:
#include <Mod/WindLabAPI/App/RPSWindLabPluginAPI.h> #include "MyLocations.h" std::string strPluginName = "MyFirstPlugin"; bool stationarity = true; PLUGIN_NAME("MyFirstPlugin"); RANDOM_PHENOMENON("Wind Velocity"); PLUGIN_AUTHOR("My Name"); PLUGIN_DESCRIPTION("This plugin adds a great feature for the simulation of random wind velocity"); PLUGIN_VERSION("1.00"); LABRPS_VERSION("0.1"); API_VERSION("0.1"); PLUGIN_RELEASE_DATE("15/06/2080"); std::string objFeatureTypeName = "MyLocationsFeatureType"; std::string objDescription = "This feature allows the user to add simulation points to WindLab simulation by points coordinates"; std::string objTile = "Title the publication where the feature type has been published"; std::string objLink = "Link to the publication where the feature type has been published or https://wiki.labrps.com"; std::string objAuthors = "Author of the publication where the feature type has been published"; std::string objDate = "15/06/2080"; std::string objVersion = "1.0"; RPS_PLUGIN_FUNC IrpsWLLocationDistribution* BuildMyLocations() { return new MyLocations; } RPS_PLUGIN_FUNC void DestroyMyLocations(WindLabAPI::IrpsWLLocationDistribution* r) { delete r; } PLUGIN_INIT_TYPE() { if (WindLab::MyLocations::getClassTypeId() == Base::Type::badType()) { WindLab::MyLocations::init(); } return 1; } PLUGIN_INIT() { InitializeLocationDistribution(objFeatureTypeName , strPluginName, objTile, objLink, objAuthors, objDate, objVersion, stationarity); return 1; } INSTALL_PLUGIN() { RegisterLocationDistribution(objFeatureTypeName , strPluginName, objDescription, BuildMyLocations, DestroyMyLocations); return 1; } UNINSTALL_PLUGIN() { UnregisterLocationDistribution(objFeatureTypeName , strPluginName); return 1; }
- LabRPS scripting: Python, Introduction to Python, Python scripting tutorial, LabRPS Scripting Basics
- Modules: Units, Quantity
- Workbenches: Gui Commands, Commands
- Parametric objects: Scripted objects, Viewproviders
- Graphical interface: Interface creation, Interface creation completely in Python, PySide, PySide examples beginner, intermediate, advanced
- Macros: Macros, How to install macros
- Other: Expressions
- Hubs: User hub, Power users hub, Developer hub