TerraLib and TerraView Wiki Page

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()