Table of Contents
Tutorial de Criação de Novos Módulos da TerraLib
Autor: Gilberto Ribeiro de Queiroz
Data: 16 de Abril, 2015
Objetivo: Este documento ensina de maneira rápida e prática como incluir novos módulos na plataforma TerraLib, incluindo a criação de plugins que possam ser disponibilizados na família de aplicativos TerraLib.
Status: Em desenvolvimento
Organizando os Fontes do Novo Módulo
Todos os módulos da TerraLib encontram-se na pasta src/terralib
. Neste exemplo iremos criar um novo módulo hipotético que lide com a extração de redes de drenagem. Nosso novo módulo será chamado de Network Drainage e será armazenado na pasta src/terralib/netdrain
.
Este novo módulo será formado por sua vez por outros três sub-módulos:
- core: contendo o código fonte das estruturas de dados e algoritmos que realizam a extração das redes de drenagem. Este módulo dará origem a uma biblioteca compartilhada, que pode ser utilizada de forma independente de uma aplicação específica.
- qt: contendo componentes gráficos desenvolvidos em Qt, que possibilite ao usuário selecionar camadas de informação e informar parâmetros para execução do algoritmo de extração de drenagem.
- plugin: implementará um conector com o framework de aplicação Qt da TerraLib que irá adicionar entradas na barra de menu e barra de botões das aplicações da família TerraLib. Este plugin será responsável, entre outras coisas, por preencher a lista de camadas de informação dos nossos componentes gráficos do outro módulo (netdrain::qt).
O código de cada um dos sub-módulos será colocado em uma pasta própria. Supondo que você esteja em um shell na raiz do repositório da TerraLib, vamos criar as seguintes pastas:
$ mkdir src/terralib/netdrain $ mkdir src/terralib/netdrain/core $ mkdir src/terralib/netdrain/qt $ mkdir src/terralib/netdrain/plugin
Na pasta src/terralib/netdrain/core
iremos colocar os arquivos: FlowAlg1.h
, FlowAlg1.cpp
, FlowAlg2.h
, FlowAlg2.cpp
, FlowUtils.h
e FlowUtils.cpp
.
Na pasta src/terralib/netdrain/qt
iremos incluir arquivos de código fonte para componentes Qt: FlowDialog.ui
, FlowDialog.h
e FlowDialog.cpp
.
Na pasta src/terralib/netdrain/plugin
iremos concentrar os códigos relativos a ligação dos nossos outros dois módulos à família de aplicativos. Neste exemplo, apenas o arquivo Plugin.cpp
será necessário.
Registrando o Módulo netdrain::core no Build da TerraLib
Agora, precisamos criar um projeto de build para o módulo netdrain::core. Para isso, precisamos escrever um arquivo CMakeLists.txt
como mostrado abaixo:
# # Include path to all dependent libraries # include_directories(${Boost_INCLUDE_DIR}) # # Export as DLL on Microsoft Windows # if(WIN32) add_definitions(-DTENETDRAINCOREDLL) endif() # # Select all the files for this project. # file(GLOB TERRALIB_SRC_FILES ${TERRALIB_ABSOLUTE_ROOT_DIR}/src/terralib/netdrain/core/*.cpp) file(GLOB TERRALIB_HDR_FILES ${TERRALIB_ABSOLUTE_ROOT_DIR}/src/terralib/netdrain/core/*.h) # # Group files in specific folders for some IDEs (VC++, Xcode, Eclipse). # source_group("Source Files" FILES ${TERRALIB_SRC_FILES}) source_group("Header Files" FILES ${TERRALIB_HDR_FILES}) # # Define the core module as a shared library. # add_library(terralib_mod_netdrain_core SHARED ${TERRALIB_SRC_FILES} ${TERRALIB_HDR_FILES}) # # Link with dependent libraries and modules. # target_link_libraries(terralib_mod_netdrain_core terralib_mod_common terralib_mod_raster terralib_mod_geometry) # # Versioning the new module library on Unix-like systems. # set_target_properties(terralib_mod_netdrain_core PROPERTIES VERSION ${TERRALIB_VERSION_MAJOR}.${TERRALIB_VERSION_MINOR} SOVERSION ${TERRALIB_VERSION_MAJOR}.${TERRALIB_VERSION_MINOR} INSTALL_NAME_DIR "@executable_path/../lib") # # Register module stuffs for installation. # install(TARGETS terralib_mod_netdrain_core EXPORT terralib-targets RUNTIME DESTINATION ${TERRALIB_DESTINATION_RUNTIME} COMPONENT runtime LIBRARY DESTINATION ${TERRALIB_DESTINATION_LIBRARY} COMPONENT runtime ARCHIVE DESTINATION ${TERRALIB_DESTINATION_ARCHIVE} COMPONENT runtime) install(FILES ${TERRALIB_HDR_FILES} DESTINATION ${TERRALIB_DESTINATION_HEADERS}/terralib/netdrain/core COMPONENT devel) # # Register module in CMake export file. # export(TARGETS terralib_mod_netdrain_core APPEND FILE ${CMAKE_BINARY_DIR}/terralib-exports.cmake)
Os texto iniciados com uma hash-tag (#
) são comentários que explicam as partes importantes de um arquivo de build para um módulo.
Como o projeto de build da TerraLib encontra-se na pasta build/cmake
, crie uma pasta denominada de terralib_mod_netdrain_core
neste local (build/cmake/terralib_mod_netdrain_core
) e inclua o arquivo CMakeLists.txt
nesta pasta.
Agora, precisamos registrar este novo módulo no arquivo principal do projeto de build. No arquivo build/cmake/CMakeLists.txt
, indique que o novo módulo deve ser usado pelo sistema de build, como mostrado abaixo:
... CMAKE_DEPENDENT_OPTION(TERRALIB_MOD_EDIT_QT_ENABLED "Build Edit Qt module?" ON "TERRALIB_MOD_EDIT_CORE_ENABLED;TERRALIB_MOD_QT_WIDGETS_ENABLED" OFF) CMAKE_DEPENDENT_OPTION(TERRALIB_MOD_QT_PLUGINS_EDIT_ENABLED "Build Edit Qt plugin?" ON "TERRALIB_MOD_PLUGIN_ENABLED;TERRALIB_MOD_QT_APF_ENABLED;TERRALIB_MOD_EDIT_QT_ENABLED" OFF) if(QT_QCOLLECTIONGENERATOR_EXECUTABLE) CMAKE_DEPENDENT_OPTION(TERRALIB_QHELP_ENABLED "Enable Qt-Help build?" ON "TERRALIB_QT_ENABLED;TERRALIB_MOD_QT_WIDGETS_ENABLED" OFF) endif() option(TERRALIB_MOD_NETWORK_DRAINAGE_CORE_ENABLED "Build Network Dranage Core module?" ON) # # build options for the TerraLib examples # CMAKE_DEPENDENT_OPTION(TERRALIB_EXAMPLE_ADO_ENABLED "Build the ADO example?" ON "WIN32;TERRALIB_BUILD_EXAMPLES_ENABLED;TERRALIB_MOD_DATAACCESS_ENABLED;TERRALIB_MOD_PLUGIN_ENABLED" OFF) ... if(TERRALIB_MOD_QT_PLUGINS_EDIT_ENABLED) add_subdirectory(terralib_mod_qt_plugins_edit) endif() if(TERRALIB_TERRAVIEW_ENABLED) add_subdirectory(terraview) endif() if(TERRALIB_MOD_NETWORK_DRAINAGE_CORE_ENABLED) add_subdirectory(terralib_mod_netdrain_core) endif() # # build examples # if(TERRALIB_EXAMPLE_ADO_ENABLED) add_subdirectory(terralib_example_ado) endif() ...
No trecho acima incluímos duas instruções. A primeira:
option(TERRALIB_MOD_NETWORK_DRAINAGE_CORE_ENABLED "Build Network Dranage Core module?" ON)
irá criar a variável TERRALIB_MOD_NETWORK_DRAINAGE_CORE_ENABLED
que será apresentada ao usuário do CMake-GUI com a mensagem informada. Esta variável irá nos dizer se o usuário irá ou não gerar o módulo.
A segunda instrução:
if(TERRALIB_MOD_NETWORK_DRAINAGE_CORE_ENABLED) add_subdirectory(terralib_mod_netdrain_core) endif()
irá adicionar o projeto de build.
Criando e Registrando o Módulo netdrain::plugin no Build da TerraLib
OBS: tem um erro nesta seção que classes derivadas do Object precisam de um .h para não ser necessário soluções ADOC!
Agora vamos criar um módulo denominado netdrain::plugin que conterá a interface do conector do nosso código aos aplicativos da família TerraLib por meio de um plugin.
Para criar um plugin em C++ precisamos criar e registar uma classe que deriva da classe base te::plugin::Plugin
. Podemos colocar a definição e registro desta classe em um arquivo C++ como o abaixo:
Arquivo: src/terralib/netdrain/plugin/Plugin.cpp
// TerraLib #include "../../../../common/Translator.h" #include "../../../../common/Logger.h" #include "../../../../plugin/Plugin.h" #include "../../../af/ApplicationController.h" // Qt #include <QAction> #include <QObject> #include <QMenu> #include <QMenuBar> class Plugin : public QObject, public te::plugin::Plugin { Q_OBJECT public: Plugin(const te::plugin::PluginInfo& pluginInfo); ~Plugin(); void startup(); void shutdown(); protected slots: void showWindow(); protected: QAction* m_showWindow; }; Plugin::Plugin(const te::plugin::PluginInfo& pluginInfo) : QObject(), te::plugin::Plugin(pluginInfo), m_showWindow(0) { } Plugin::~Plugin() { } void Plugin::startup() { if(m_initialized) return; m_initialized = true; } void Plugin::shutdown() { if(!m_initialized) return; m_initialized = false; } void Plugin::showWindow() { } PLUGIN_CALL_BACK_DECLARATION(TEQTPLUGINNETDRAINEXPORT); PLUGIN_CALL_BACK_IMPL(Plugin)
Agora precisamos criar um arquivo contendo a descrição deste plugin. Este arquivo será usado pelas aplicações da TerraLib para carregar e apresentar informações sobre o plugin criado.
Arquivo: share/terralib/plugins/te.netdrain.teplg
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <PluginInfo xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.terralib.org/schemas/plugin" xsd:schemaLocation="http://www.terralib.org/schemas/plugin ../schemas/terralib/plugin/plugin_info.xsd" version="5.0.0-alpha.1" release="2013-01-01" engine="C++"> <Name>te.netdrain</Name> <DisplayName>Network Drainage</DisplayName> <Description>This plugin enables TerraLib 5 applications to process.... </Description> <TerraLibVersion>5.0.0-alpha.1</TerraLibVersion> <License xlink:href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html">GNU Lesser General Public License v 3.0</License> <Category>Data Access</Category> <Site xlink:href="http://www.dpi.inpe.br/terralib5/wiki/doku.php?id=wiki:designimplementation:dataaccess:terralib4"></Site> <Provider> <Name>Terralib Team</Name> <Site xlink:href="http://www.terralib.org/"></Site> <Email>terralib-team@terralib.org</Email> </Provider> <Resources> <Resource name="SharedLibraryName" xlink:href="terralib_mod_cg_network_drainage_plugin"/> </Resources> </PluginInfo>
mkdir build/cmake/terralib_mod_netdrain_plugin
Agora precisamos criar o arquivo CMakeLists.txt
para registrar este plugin no sistema de build.
include_directories(${Boost_INCLUDE_DIR}) if(WIN32) add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS -DTEQTPLUGINNETDRAINDLL) endif() file(GLOB TERRALIB_SRC_FILES ${TERRALIB_ABSOLUTE_ROOT_DIR}/src/terralib/netdrain/plugin/*.cpp) file(GLOB TERRALIB_HDR_FILES ${TERRALIB_ABSOLUTE_ROOT_DIR}/src/terralib/netdrain/plugin/*.h) if(Qt5_FOUND) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(TERRALIB_FILES ${TERRALIB_SRC_FILES} ${TERRALIB_HDR_FILES}) add_library(terralib_mod_netdrain_plugin SHARED ${TERRALIB_FILES}) target_link_libraries(terralib_mod_netdrain_plugin terralib_mod_qt_widgets terralib_mod_qt_apf) qt5_use_modules(terralib_mod_netdrain_plugin Widgets) else() include_directories(${CMAKE_CURRENT_BINARY_DIR}) include(${QT_USE_FILE}) include_directories(${QT_INCLUDE_DIR}) add_definitions(${QT_DEFINITIONS}) # moc'ing set(TERRALIB_HDRS_TO_MOC_FILES ${TERRALIB_ABSOLUTE_ROOT_DIR}/src/terralib/netdrain/plugin/Plugin.h) QT4_WRAP_CPP(TERRALIB_GEN_SRC_FILES ${TERRALIB_HDRS_TO_MOC_FILES}) set(TERRALIB_FILES ${TERRALIB_SRC_FILES} ${TERRALIB_HDR_FILES} ${TERRALIB_GEN_SRC_FILES}) add_library(terralib_mod_netdrain_plugin SHARED ${TERRALIB_FILES}) target_link_libraries(terralib_mod_netdrain_plugin terralib_mod_qt_widgets terralib_mod_qt_apf ${QT_LIBRARIES}) endif() set_target_properties(terralib_mod_netdrain_plugin PROPERTIES VERSION ${TERRALIB_VERSION_MAJOR}.${TERRALIB_VERSION_MINOR} SOVERSION ${TERRALIB_VERSION_MAJOR}.${TERRALIB_VERSION_MINOR} INSTALL_NAME_DIR "@executable_path/../lib") install(TARGETS terralib_mod_netdrain_plugin EXPORT terralib-targets RUNTIME DESTINATION ${TERRALIB_DESTINATION_RUNTIME} COMPONENT runtime LIBRARY DESTINATION ${TERRALIB_DESTINATION_LIBRARY} COMPONENT runtime ARCHIVE DESTINATION ${TERRALIB_DESTINATION_ARCHIVE} COMPONENT runtime) install(FILES ${TERRALIB_HDR_FILES} ${TERRALIB_GEN_HDR_FILES} DESTINATION ${TERRALIB_DESTINATION_HEADERS}/terralib/netdrain/plugin COMPONENT devel) install(FILES ${TERRALIB_ABSOLUTE_ROOT_DIR}/share/terralib/plugins/te.netdrain.teplg DESTINATION ${TERRALIB_DESTINATION_PLUGINS} COMPONENT runtime) export(TARGETS terralib_mod_netdrain_plugin APPEND FILE ${CMAKE_BINARY_DIR}/terralib-exports.cmake)
Agora podemos registrar este script de build no CMakeLists.txt
…
option(TERRALIB_MOD_NETWORK_DRAINAGE_CORE_ENABLED "Build Network Dranage module?" ON) CMAKE_DEPENDENT_OPTION(TERRALIB_MOD_NETWORK_DRAINAGE_PLUGIN_ENABLED "Build Network Dranage Plugin?" ON "TERRALIB_MOD_NETWORK_DRAINAGE_CORE_ENABLED" OFF)
if(TERRALIB_MOD_NETWORK_DRAINAGE_CORE_ENABLED) add_subdirectory(terralib_mod_netdrain_core) endif() if(TERRALIB_MOD_NETWORK_DRAINAGE_PLUGIN_ENABLED) add_subdirectory(terralib_mod_netdrain_plugin) endif()