Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
#
# $Id$
# $HeadURL$
# $Author$
#
ADD_SUBDIRECTORY(SituationMap)
ADD_SUBDIRECTORY(LtsDataView)
ADD_SUBDIRECTORY(LtsFileDialog)
ADD_SUBDIRECTORY(LtsReportDisplay)
+64
View File
@@ -0,0 +1,64 @@
#
# CMakeLists.txt for Data View
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-06-15
#
SET(ltsDataView_SRCS
lts_data_view_export.h
lts_data_view.h
lts_data_view.cpp
abstract_display_widget.h
abstract_display_widget.cpp
search_model.cpp
search_model.h
tree_view.cpp
tree_view.h
check_state_proxy_model.h
check_state_proxy_model.cpp
tree_view_delegate.cpp
tree_view_delegate.h
icon_view_delegate.cpp
icon_view_delegate.h
data_delegate.cpp
data_delegate.h
lts_columns_setting.cpp
lts_columns_setting.h
lts_columns_setting.cpp
lts_columns_setting.h
)
NGL_WRAP_UI(ltsDataView_SRCS
lts_data_view.ui
lts_columns_setting.ui
lts_columns_setting.ui
)
NGL_ADD_LIBRARY(WS LtsDataView SHARED ${ltsDataView_SRCS})
NGL_TARGET_LINK_LIBRARIES(LtsDataView
PRIVATE
LtsWidgets
LtsUtilsSettings
ngltools
PUBLIC
Qt5::Core
Qt5::Widgets
)
NGL_TARGET_INCLUDE_DIRECTORIES(LtsDataView
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_INSTALL_TARGET(LtsDataView)
# Test-Executable
NGL_ADD_EXECUTABLE(WS NO_TRANSLATION LtsDataViewTest test.h test.cpp)
NGL_TARGET_LINK_LIBRARIES(LtsDataViewTest
Qt5::Widgets
LtsDataView
LtsWidgets
)
+29
View File
@@ -0,0 +1,29 @@
/**
* @RDE_HEADER@
* Abstract Display Widget is an Abstract class to create Custom Display Widgets for the Custom View
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-06-15
*/
#include "abstract_display_widget.h"
#include <QModelIndex>
namespace LtsDataView
{
AbstractDisplayWidget::AbstractDisplayWidget(QWidget *parent)
: QWidget(parent)
{
setAutoFillBackground(true);
}
QVariant AbstractDisplayWidget::rowData(const QModelIndex &idx, int column, int role) const
{
const QModelIndex rowIdx(idx.column() == column ? idx : idx.model()->index(idx.row(), column));
return idx.model()->data(rowIdx, role);
}
} // namespace LtsDataView
+30
View File
@@ -0,0 +1,30 @@
/**
* @RDE_HEADER@
* Abstract Display Widget is an Abstract class to create Custom Display Widgets for the Custom View
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-06-15
*/
#pragma once
#include "lts_data_view_export.h"
#include <QWidget>
class QModelIndex;
namespace LtsDataView
{
class LTSDATAVIEW_EXPORT AbstractDisplayWidget : public QWidget
{
Q_OBJECT
public:
explicit AbstractDisplayWidget(QWidget *parent = nullptr);
virtual bool init(const QModelIndex &idx) = 0;
protected:
QVariant rowData(const QModelIndex &idx, int column, int role = Qt::DisplayRole) const;
};
} // namespace LtsDataView
+118
View File
@@ -0,0 +1,118 @@
/**
* @RDE_HEADER@
* Implementation of CheckStateProxyModel
* $Id$
* $HeadURL$
* $Author$
* Created by hjl/Christian Froebel, NLE, 2019-05-10
*/
#include "check_state_proxy_model.h"
namespace LtsDataView
{
Qt::ItemFlags CheckStateProxyModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return sourceModel()->flags(index); // delegate to source model for further processing if necessary
// Sets only the checkbox nodes on user checkable,
// checkbox leaves must be handled in source model.
QModelIndex sourceIndex = mapToSource(index);
Qt::ItemFlags fl = sourceModel()->flags(sourceIndex);
if (index.column() == 0)
return fl | Qt::ItemIsUserCheckable;
return fl;
}
QVariant CheckStateProxyModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
QModelIndex sourceIndex = mapToSource(index);
// delegate everything except CheckStateRole to source model
if (role != Qt::CheckStateRole)
return sourceModel()->data(sourceIndex, role);
// delegate a leaf too with CheckStateRole to source model
if (isLeaf(index))
return sourceModel()->data(sourceIndex, role);
// delegate to source model for further processing of further columns if necessary
if (index.column() != 0)
return sourceModel()->data(sourceIndex, role);
// sets the node checkboxes and decoration depending on the entries in the tree structure
int checkedCount = 0;
int childCount = rowCount(index);
for (int childRow = 0; childRow < childCount; ++childRow)
{
QModelIndex childIndex = this->index(childRow, 0, index);
Qt::CheckState checkState = data(childIndex, Qt::CheckStateRole).value<Qt::CheckState>();
if (checkState == Qt::PartiallyChecked)
return Qt::PartiallyChecked;
if (checkState == Qt::Checked)
++checkedCount;
}
if (checkedCount == childCount)
return Qt::Checked;
else if (checkedCount == 0)
return Qt::Unchecked;
else
return Qt::PartiallyChecked;
}
bool CheckStateProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
QModelIndex sourceIndex = mapToSource(index);
// delegate to source model for further processing of further columns if necessary
if (index.column() != 0)
return sourceModel()->setData(sourceIndex, value, role);
// delegate everything except CheckStateRole to source mode
if (role != Qt::CheckStateRole)
return sourceModel()->setData(sourceIndex, value, role);
if (isLeaf(index))
{
// delegate a leaf to source model
sourceModel()->setData(sourceIndex, value, role);
// update parents recursively here
QModelIndex idx = index.parent();
do
{
emit dataChanged(idx, idx, {Qt::CheckStateRole});
idx = idx.parent();
}
while (idx.isValid());
return true;
}
// update underlying children recursively (Additional nodes with leaves may also exist)
int childCount = rowCount(index);
for (int childRow = 0; childRow < childCount; ++childRow)
{
QModelIndex childIndex = this->index(childRow, 0, index);
setData(childIndex, value, Qt::CheckStateRole);
}
return true;
}
bool CheckStateProxyModel::isLeaf(const QModelIndex &index) const
{
QModelIndex sourceIndex = mapToSource(index);
return sourceModel()->flags(sourceIndex).testFlag(Qt::ItemIsUserCheckable);
}
} // namespace InfrastructureManagement
+60
View File
@@ -0,0 +1,60 @@
/**
* @RDE_HEADER@
* The model is used to handle CheckState Boxes in an LtsDataView (QTreeModel).
* Only the nodes of a TreeView are handled in this model. Leaves are forwarded to the transferred model and must be edited there.
* $Id$
* $HeadURL$
* $Author$
* Created by hjl/Christian Froebel, NLE, 2019-05-10
*/
#pragma once
#include <QIdentityProxyModel>
#include "lts_data_view_export.h"
namespace LtsDataView
{
class LTSDATAVIEW_EXPORT CheckStateProxyModel : public QIdentityProxyModel
{
public:
using QIdentityProxyModel::QIdentityProxyModel;
/**
* Handles the 'ItemIsUserCheckable' flags
* @param[in] sourceModel index
*
*/
Qt::ItemFlags flags(const QModelIndex &index) const override;
/**
* Handles the representation of data
* @param[in] sourceModel index
* @param[in] role role to which the data relates
*
*/
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
/**
* Handles the storage of data
* @param[in] index index
* @param[in] value value to be set
* @param[in] role role to which the data relates
*
*/
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
private:
/**
* Returns true if the item with the given index is an leaf
* @param[in] index item index whose information is requested
* will be internally mapped to source model data
*/
bool isLeaf(const QModelIndex &index) const;
}; // class CheckStateProxyModel
} // namespace LtsDataView
+31
View File
@@ -0,0 +1,31 @@
/**
* @RDE_HEADER@
* Renders complex types from model data to text for views
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, NLE, 2020-09-09
*/
#include "data_delegate.h"
#include <ngltools/ngltools_dtg.h>
#include <QDateTime>
namespace LtsDataView
{
DataDelegate::DataDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{}
QString DataDelegate::displayText(const QVariant &value, const QLocale &locale) const
{
if (value.type() == QVariant::Type::DateTime)
return DTG::toString(value.toDateTime());
return QStyledItemDelegate::displayText(value, locale);
}
} // namespace LtsDataView
+24
View File
@@ -0,0 +1,24 @@
#pragma once
/**
* @RDE_HEADER@
* Renders complex types from model data to text for views
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, NLE, 2020-09-09
*/
#include <QStyledItemDelegate>
namespace LtsDataView
{
class DataDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
DataDelegate(QObject *parent);
QString displayText(const QVariant &value, const QLocale &locale) const override;
};
} // namespace LtsDataView
+78
View File
@@ -0,0 +1,78 @@
#include "icon_view_delegate.h"
#include <QGraphicsDropShadowEffect>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QPainter>
#include <QDebug>
namespace LtsDataView
{
static constexpr int s_shadowRadius = 22;
void IconViewDelegate::setDisplayWidgetCreator(const std::function<AbstractDisplayWidget*()> &customDisplayWidgetCreator)
{
m_customDisplayWidgetCreator = customDisplayWidgetCreator;
QScopedPointer<AbstractDisplayWidget> dw(m_customDisplayWidgetCreator());
if (!dw)
{
qWarning() << "IconViewDelegate::setDisplayWidgetCreator: delegate is not a base of AbstractDisplayWidget!";
Q_ASSERT(false);
return;
}
m_displayWidgetSize = dw->size() + QSize(s_shadowRadius * 2, s_shadowRadius * 2);
}
QSize IconViewDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
{
return m_displayWidgetSize;
}
void IconViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QScopedPointer<AbstractDisplayWidget> dw(m_customDisplayWidgetCreator());
if (!dw)
{
qWarning() << "IconViewDelegate::paint: delegate is not a base of AbstractDisplayWidget!";
Q_ASSERT(false);
return;
}
if (!dw->init(index))
{
qWarning() << "IconViewDelegate::paint: delegate could not create ui";
return;
}
const auto dpr = dw->devicePixelRatioF();
QPixmap p(dw->size() * dpr);
p.setDevicePixelRatio(dpr);
QPainter myPainter(&p);
dw->render(&myPainter);
myPainter.end();
// drop shadow
QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect();
shadowEffect->setBlurRadius(s_shadowRadius);
shadowEffect->setOffset(0, 0); // center (shadow on all sides)
if (option.state & QStyle::State_Selected)
shadowEffect->setColor(dw->palette().light().color());
else
shadowEffect->setColor(dw->palette().shadow().color());
// draw pixmap & shadow
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(p);
item->setGraphicsEffect(shadowEffect);
// TODO: avoid creating a QGraphicsScene by using QGraphicsItem::paint()
QGraphicsScene scene;
scene.addItem(item);
scene.render(painter, option.rect, QRectF(-s_shadowRadius, -s_shadowRadius, option.rect.width(), option.rect.height()));
}
} // namespace LtsDataView
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include "abstract_display_widget.h"
#include <QStyledItemDelegate>
namespace LtsDataView
{
class IconViewDelegate final : public QStyledItemDelegate
{
Q_OBJECT
public:
using QStyledItemDelegate::QStyledItemDelegate;
void setDisplayWidgetCreator(const std::function<AbstractDisplayWidget*()> &customDisplayWidgetCreator);
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
private:
std::function<AbstractDisplayWidget*()> m_customDisplayWidgetCreator;
QSize m_displayWidgetSize;
};
} // namespace LtsDataView
+231
View File
@@ -0,0 +1,231 @@
/**
* @RDE_HEADER@
* LtsColumnsSettingWidget Organise table columns
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-03-19
*/
#include "lts_columns_setting.h"
#include "ui_lts_columns_setting.h"
#include<QDebug>
namespace LtsDataView
{
LtsColumnsSettingWidget::LtsColumnsSettingWidget(const QVector<ColumnOrganiserInfo> &columnInfoVec, QWidget *parent)
: LtsWidgets::LtsFramelessDialog(parent)
, m_ui(new Ui::LtsColumnsSetting)
{
m_ui->setupUi(this);
m_model = new ColumnOrganiserModel(this);
m_model->setModelData(columnInfoVec);
m_ui->tableView->setModel(m_model);
for(const auto &ci : columnInfoVec)
{
if (ci.debugOnly){
qDebug()<<">>>[LtsColumnsSettingWidgets] column to hide: id: "<<ci.logicalIndex;
m_ui->tableView->hideRow(ci.logicalIndex);
}
}
connect(m_ui->applyBtn, &QPushButton::clicked, this, &LtsColumnsSettingWidget::onApplyClicked);
connect(m_ui->cancelBtn, &QPushButton::clicked, this, &LtsColumnsSettingWidget::onAbortClicked);
connect(m_ui->resetBtn, &QPushButton::clicked, this, &LtsColumnsSettingWidget::onResetClicked);
}
LtsColumnsSettingWidget::~LtsColumnsSettingWidget()
{
delete m_ui;
}
void LtsColumnsSettingWidget::onResetClicked()
{
emit columnsResetted();
accept();
}
/*!
* \brief LtsColumnsSettingWidget::onApplyClicked
* send columns settings
*/
void LtsColumnsSettingWidget::onApplyClicked()
{
QVector<LtsDataView::ColumnOrganiserInfo> colInfoVec;
const int rowCount = m_ui->tableView->model()->rowCount();
colInfoVec.reserve(rowCount);
for(int row = 0; row < rowCount; ++row)
{
const ColumnOrganiserInfo ci = m_ui->tableView->model()->data(m_model->index(row,0),Qt::UserRole).value<ColumnOrganiserInfo>();
colInfoVec.push_back(ci);
}
emit columnVisibilityChanged(colInfoVec);
accept();
}
/*!
* \brief LtsColumnsSettingWidget::onAbortClicked
*/
void LtsColumnsSettingWidget::onAbortClicked()
{
reject();
}
/// TABLE MODEL FOR COLUMN SETTINGS
/*!
* \brief ColumnOrganiserModel::ColumnOrganiserModel
* \param parent
*/
ColumnOrganiserModel::ColumnOrganiserModel(QObject *parent)
:QAbstractTableModel(parent)
{
beginResetModel();
m_vecData.clear();
endResetModel();
}
/*!
* \brief ColumnOrganiserModel::setModelData
* \param infos
*/
void ColumnOrganiserModel::setModelData(const QVector<ColumnOrganiserInfo> &infos)
{
for(const auto &data : infos)
insertRow(data);
}
/*!
* \brief ColumnOrganiserModel::insertRow
* \param info
*/
void ColumnOrganiserModel::insertRow(const ColumnOrganiserInfo &info)
{
beginInsertRows(QModelIndex(), m_vecData.size(), m_vecData.size());
m_vecData.append(info);
endInsertRows();
}
/*!
* \brief ColumnOrganiserModel::columnCount
* \param parent
* \return
*/
int ColumnOrganiserModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return 1; // list of Column header as rows with on column
}
/*!
* \brief ColumnOrganiserModel::rowCount
* \param parent
* \return
*/
int ColumnOrganiserModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_vecData.count();
}
/*!
* \brief ColumnOrganiserModel::data
* \param index
* \param role
* \return
*/
QVariant ColumnOrganiserModel::data(const QModelIndex &index, int role) const
{
if ((role != Qt::DisplayRole &&
role != Qt::DecorationRole &&
role != Qt::EditRole &&
role != Qt::CheckStateRole &&
role != Qt::UserRole) || !index.isValid() || index.row() >= m_vecData.size())
return QVariant();
const ColumnOrganiserInfo ci = m_vecData.at(index.row());
if (role == Qt::CheckStateRole)
{
return ci.show;
}
if (role == Qt::DisplayRole)
return ci.name;
if (role == Qt::UserRole)
return QVariant::fromValue(ci);
return QVariant();
}
/*!
* \brief ColumnOrganiserModel::setData
* \param index
* \param value
* \param role
* \return
*/
bool ColumnOrganiserModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
Q_UNUSED(value)
if (role != Qt::EditRole && role != Qt::CheckStateRole)
return false;
ColumnOrganiserInfo &ci = m_vecData[index.row()];
if (role == Qt::CheckStateRole)
{
ci.show = !ci.show;
return true;
}
switch (index.column())
{
case 0:
return false;
}
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
return true;
}
/*!
* \brief ColumnOrganiserModel::flags
* \param index
* \return
*/
Qt::ItemFlags ColumnOrganiserModel::flags(const QModelIndex &index) const
{
auto f = QAbstractTableModel::flags(index);
if (!index.isValid())
return f;
if (index.column() == 0)
{
f.setFlag(Qt::ItemIsUserCheckable);
}
return f;
}
/*!
* \brief ColumnOrganiserModel::headerData
* \param section
* \param orientation
* \param role
* \return
*/
QVariant ColumnOrganiserModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal
&& role == Qt::DisplayRole)
{
if (section == 0)
return tr("Column Visibility");
}
return QAbstractTableModel::headerData(section, orientation, role);
}
}
+84
View File
@@ -0,0 +1,84 @@
/**
* @RDE_HEADER@
* LtsColumnsSetting Organise table columns
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-03-19
*/
#pragma once
#include <LtsDataView/lts_data_view_export.h>
#include "LtsWidgets/lts_frameless_dialog.h"
#include <QWidget>
#include <QDialog>
#include <QAbstractTableModel>
namespace Ui {
class LtsColumnsSetting;
}
namespace LtsDataView
{
struct ColumnOrganiserInfo
{
int logicalIndex; // logicalIndex
QString name;
bool show;
bool debugOnly = false; // column is only displayed in debug mode
bool hide() const {return !show;}
};
class ColumnOrganiserModel;
class LTSDATAVIEW_EXPORT LtsColumnsSettingWidget : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
explicit LtsColumnsSettingWidget(const QVector<ColumnOrganiserInfo> &columnInfoVec, QWidget *parent = nullptr);
~LtsColumnsSettingWidget();
signals:
void columnVisibilityChanged(const QVector<ColumnOrganiserInfo> &data);
void columnsResetted();
private slots:
void onResetClicked();
void onApplyClicked();
void onAbortClicked();
private:
Ui::LtsColumnsSetting *m_ui;
ColumnOrganiserModel *m_model;
};
class ColumnOrganiserModel final : public QAbstractTableModel
{
Q_OBJECT
public:
explicit ColumnOrganiserModel(QObject *parent = nullptr);
~ ColumnOrganiserModel(){}
void setModelData(const QVector<ColumnOrganiserInfo> &infos);
protected:
void insertRow(const ColumnOrganiserInfo &info);
int columnCount(const QModelIndex &parent = QModelIndex())const override;
int rowCount(const QModelIndex &parent = QModelIndex() ) const override;
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole)const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
private:
QVector<ColumnOrganiserInfo> m_vecData;
};
} // namespace LtsDataView
Q_DECLARE_METATYPE(LtsDataView::ColumnOrganiserInfo)
+71
View File
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LtsColumnsSetting</class>
<widget class="QWidget" name="LtsColumnsSetting">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="4">
<widget class="QTableView" name="tableView">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>121</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="resetBtn">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="applyBtn">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="cancelBtn">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
File diff suppressed because it is too large. Load diff
+225
View File
@@ -0,0 +1,225 @@
/**
* @RDE_HEADER@
* LtsDataView is the exported View, which contains and manages a Custom View and a Table View
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-06-15
*/
#pragma once
#include <LtsDataView/lts_data_view_export.h>
#include <LtsDataView/lts_columns_setting.h>
#include <QWidget>
#include <QAbstractItemView>
#include <QLineEdit>
#include <functional>
class QListView;
class QTreeView;
namespace Ui
{
class LtsDataView;
}
namespace LtsWidgets
{
class LtsColumnFilterProxyModel;
struct ColumnOrganiserInfo;
}
// TODO: doxy doku
namespace LtsDataView
{
class AbstractDisplayWidget;
class SearchModel;
class SearchLineEdit final : public QLineEdit
{
Q_OBJECT
public:
explicit SearchLineEdit(QWidget *parent)
: QLineEdit(parent)
{
setProperty("isSearchLineEdit", true);
}
};
class LTSDATAVIEW_EXPORT LtsDataView : public QWidget
{
Q_OBJECT
Q_PROPERTY(bool rootIsDecorated READ rootIsDecorated WRITE setRootIsDecorated)
Q_PROPERTY(bool showColumnCount READ showColumnCount WRITE setColumnCountVisible)
Q_PROPERTY(bool toolButtonsVisible READ toolButtonsVisible WRITE setToolButtonsVisible)
Q_PROPERTY(bool alternatingRowColors READ alternatingRowColors WRITE setAlternatingRowColors)
Q_PROPERTY(bool allColumnsShowFocus READ allColumnsShowFocus WRITE setAllColumnsShowFocus)
Q_PROPERTY(bool autoResizeToContent READ autoResizeToContent WRITE setAutoResizeToContent)
Q_PROPERTY(QAbstractItemView::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
public:
enum Page
{
TABLE = 0,
CUSTOM = 1,
};
explicit LtsDataView(QWidget *parent = nullptr);
~LtsDataView();
/** once you set the model without a ADW, the view cannot switch back to double-view mode!
*
*/
void setModel(QAbstractItemModel *model, const std::function<AbstractDisplayWidget*()> &customDisplayWidgetCreator = nullptr);
QAbstractItemModel *sourceModel() const;
LtsWidgets::LtsColumnFilterProxyModel *proxyModel() const;
QItemSelectionModel *selectionModel() const;
SearchModel *searchModel() const;
QTreeView *treeView();
const QTreeView *treeView() const;
QTreeView *searchView();
const QTreeView *searchView() const;
QListView *getCustomView();
QWidget *customWidget() const;
void setCustomWidget(QWidget *customWidget); // not visible in seamless mode
QModelIndexList selectedRows(int column = 0) const; // TODO: returns indexes instead of rows if in custom view ... change naming?
void selectRow(const QModelIndex &idxSource);
void clearSelection();
void setSelectionMode(QAbstractItemView::SelectionMode selectionMode);
QAbstractItemView::SelectionMode selectionMode() const;
QModelIndex currentIndex() const;
void setCurrentIndex(const QModelIndex &idx); // also makes sure that the current index is visible (QAIV::scrollTo())
void scrollTo(const QModelIndex &idxSource);
void moveSection(int from, int to);
void seamless();
void setViewHeaderMovable(bool state);
void moveSections(const QMap<int, int> &list); /// logicalIndex (key) visualIndex(value)
void saveTableSettings(bool defaultSetting = false);/// if defaultSetting true, the default order of the table will be restore and save
bool restoreTableSettings();
QString getOperatorColIdentifier() const;
QVector<ColumnOrganiserInfo> getColumnOrganiserSetting();
QString columnOrganiserGroup() const;
void setColumnViewFromSetting();
void setColumnsOrganiserEnabled(const QString &tableIdentifier, bool enable = false);
void setRootIsDecorated(bool isDecorated);
bool rootIsDecorated() const;
void setAlternatingRowColors(bool enable);
bool alternatingRowColors() const;
void setColumnCountVisible(bool bVisible);
bool showColumnCount() const;
void setToolButtonsVisible(bool bVisible);
bool toolButtonsVisible() const;
void setAllColumnsShowFocus(bool enable);
bool allColumnsShowFocus() const;
void hideColumn(int column, bool debugMode = false);
void showColumn(int column);
bool isColumnHidden(int column) const;
void setColumnHidden(int column, bool hide);
void setAutoResizeToContent(bool enable);
bool autoResizeToContent() const;
void resizeSection(int logicalIndex, int size);
void resizeHeadersByContent();
void resizeColumnsToContent();
void syncSearchHeaderAndTableContentColumnSize();
void setRootIndex(const QModelIndex &srcIndex);
/**
* @brief See QHeaderview::setSortIndicator
*/
void setSortIndicator(int logicalIndex, Qt::SortOrder order);
void setSortIndicatorShown(bool show = true);
Qt::ContextMenuPolicy contextMenuPolicyPerView(Page page) const;
void setContextMenuPolicyPerView(Page page, Qt::ContextMenuPolicy policy);
QModelIndex mapFromSource(const QModelIndex &mi) const;
QModelIndex mapToSource(const QModelIndex &mi) const;
QModelIndexList mapToSource(const QModelIndexList &mil) const;
QItemSelection mapSelectionToSource(const QItemSelection &is) const;
bool setInitialSearchContent(int section, const QVariant &filterData);
void setIconSize(const QSize &size);
QByteArray saveState() const;
bool restoreState(const QByteArray &headerState);
private:
Ui::LtsDataView *m_ui;
LtsWidgets::LtsColumnFilterProxyModel *m_columnFilterProxy;
SearchModel *m_searchModel;
bool m_bOwnProxy;
bool m_autoResizeToConent{true};
QString m_tableObjIdentifier; // identifier for column Organiser
bool m_userChangedColumnPos = false;
QSet<int> m_DebugModeColIds; /// column which are only visible in debug mode
QString createCsv() const;
void addTouchScroll(QWidget *widget);
QAbstractItemView *currentView() const;
protected:
void keyPressEvent(QKeyEvent *event) override;
public slots:
void selectTableView();
void selectCustomView();
void selectView(Page page);
void slotCopyToClipboard();
void collapseAll();
void expandAll();
void expand(const QModelIndex &index);
void setSortingEnabled(bool enable);
void slotSetHorizontalRange(int, int);
void updateColumnsVisibility(const QVector<ColumnOrganiserInfo> &data);
void slotSetColumnsDefaultOrder();
private slots:
void slotSetSortIndicator(int logicalIndex, Qt::SortOrder order);
void slotRowCountChanged();
void slotSetHorizontalValue(int);
void slotSetVerticalRange(int x = 0, int y = 0);
void slotSetVerticalValue(int);
void slotSectionResized(int, int, int);
void slotHeaderMoved(int, int, int);
void slotCsvExport();
void slotResizeColumn(int columnIndex);
void onCustomContextMenuRequested(const QPoint &pos);
void slotColumnOrganiserDialog();
signals:
void signalEnterPressed();
void signalEntered(const QModelIndex &index);
// These are only emitted from the TableView
void clicked(const QModelIndex &index);
void doubleClicked(const QModelIndex &index);
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void activated(const QModelIndex &index);
// These are emitted from both
void signalSelectionChanged();
void signalDoubleClicked();
// signalContextMenuRequested requires setContextMenuPolicyPerView to be set
void signalContextMenuRequested(const QPoint &globalPos, const QModelIndex &indexSrc);
// custom signals (@Filip)
void filterChanged();
void sortOrderChanged(const int &column, const Qt::SortOrder &order);
};
} // namespace LtsDataView
+367
View File
@@ -0,0 +1,367 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LtsDataView</class>
<widget class="QWidget" name="LtsDataView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>556</width>
<height>350</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lblRows">
<property name="text">
<string>Rows:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbRows">
<property name="text">
<string notr="true">0</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="customWidget" native="true"/>
</item>
<item>
<widget class="QPushButton" name="tbColumnOrganiser">
<property name="whatsThis">
<string>Save selected line(s) as csv to a selected file with headers</string>
</property>
<property name="text">
<string>Column Setting</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tbCsvExport">
<property name="whatsThis">
<string>Save selected line(s) as csv to a selected file with headers</string>
</property>
<property name="text">
<string>CSV Export</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tbCopy">
<property name="whatsThis">
<string>Copy selected line(s) as csv to clipboard without headers</string>
</property>
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tbTable">
<property name="text">
<string>Table</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tbCustom">
<property name="text">
<string>Custom</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="oneTableLayout" stretch="1,0">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="LtsDataView::TreeView" name="searchView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="autoScroll">
<bool>true</bool>
</property>
<property name="autoScrollMargin">
<number>16</number>
</property>
<property name="editTriggers">
<set>QAbstractItemView::CurrentChanged|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
<property name="alternatingRowColors">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectItems</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>true</bool>
</attribute>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>255</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="TableView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="LtsDataView::TreeView" name="tableView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="CustomView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListView" name="customView">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="movement">
<enum>QListView::Free</enum>
</property>
<property name="flow">
<enum>QListView::LeftToRight</enum>
</property>
<property name="spacing">
<number>0</number>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="QScrollBar" name="verticalScrollBar">
<property name="maximum">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QScrollBar" name="horizontalScrollBar">
<property name="maximum">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="nullWidget" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::TreeView</class>
<extends>QTreeView</extends>
<header location="global">tree_view.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>tableView</tabstop>
<tabstop>searchView</tabstop>
<tabstop>tbCsvExport</tabstop>
<tabstop>tbCopy</tabstop>
<tabstop>tbTable</tabstop>
<tabstop>tbCustom</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
+22
View File
@@ -0,0 +1,22 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/qglobal.h>
#ifndef LTSDATAVIEW_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define LTSDATAVIEW_EXPORT
# else
# if defined(MAKE_LTSDATAVIEW_LIB)
# define LTSDATAVIEW_EXPORT Q_DECL_EXPORT
# else
# define LTSDATAVIEW_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
+156
View File
@@ -0,0 +1,156 @@
/**
* @RDE_HEADER@
* Search Model for TableViews (has the ability to give the user a row for searching data)
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-03-14
*/
#include "search_model.h"
#include <QFont>
#include <QGuiApplication>
#include <QIcon>
#include <QPalette>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
namespace LtsDataView
{
SearchModel::SearchModel(QObject *parent)
: QAbstractItemModel(parent)
, m_searchIcon(QIcon(QStringLiteral("icon:show.svg")))
{
}
int SearchModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid()) return 0;
if (!m_sourceModel) return 0;
// no parent here - the given model index has nothing to do with the source model
return m_sourceModel->columnCount(QModelIndex());
}
int SearchModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) return 0;
if (!m_sourceModel) return 0;
return 1; // the search row
}
QVariant SearchModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
switch (role)
{
case Qt::DisplayRole: // Text
return m_displayData.value(index.column());
case Qt::EditRole: // Editor Text
return m_columnFilters.value(index.column());
case Qt::TextColorRole: // Text-Color
if (!m_columnFilters.contains(index.column()))
return QGuiApplication::palette().color(QPalette::Disabled, QPalette::ButtonText);
break;
case Qt::DecorationRole:
return m_hideDecorationColumns.contains(index.column()) ? QVariant() : m_searchIcon;
case Qt::BackgroundRole:
return QGuiApplication::palette().color(QPalette::Disabled, QPalette::AlternateBase);
case LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole:
return m_comboBoxData.value(index.column());
default:
break;
}
return QVariant();
}
QVariant SearchModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::FontRole)
{
QFont boldFont;
boldFont.setBold(true);
return boldFont;
}
return m_sourceModel ? m_sourceModel->headerData(section, orientation, role) : QVariant();
}
bool SearchModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!m_sourceModel || !index.isValid())
return false;
if (role == Qt::EditRole) // add / replace column filter when edited and in search row (row 0)
{
if (value.isNull())
m_columnFilters.remove(index.column());
else
m_columnFilters[index.column()] = value;
emit stringFilterForColumnChanged(value.toString(), index.column());
emit signalFilterChanged(); // must be called at last
emit dataChanged(index, index, {role});
return true; // done! (report a change, so that text keeps showing on search row)
}
if (role == Qt::DisplayRole)
{
if (value.isNull())
m_displayData.remove(index.column());
else
m_displayData[index.column()] = value;
emit dataChanged(index, index, {role});
return true;
}
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
{
if (value.isNull())
m_comboBoxData.remove(index.column());
else
m_comboBoxData[index.column()] = value;
emit dataFilterForColumnChanged(value, index.column());
emit signalFilterChanged(); // must be called at last
emit dataChanged(index, index, {role});
return true;
}
if (role == Qt::DecorationRole)
{
if (value.isNull())
m_hideDecorationColumns.remove(index.column());
else
m_hideDecorationColumns.insert(index.column());
emit dataChanged(index, index, {role});
}
return false;
}
void SearchModel::setSourceModel(QAbstractItemModel* sourceModel)
{
m_sourceModel = sourceModel;
m_columnFilters.clear();
emit dataChanged(QModelIndex(), QModelIndex()); // update view
}
Qt::ItemFlags SearchModel::flags(const QModelIndex &index) const
{
Q_UNUSED(index);
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
}
QModelIndex SearchModel::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid())
return QModelIndex();
return createIndex(row, column);
}
} // namespace LtsDataView
+53
View File
@@ -0,0 +1,53 @@
/**
* @RDE_HEADER@
* Search Model for TableViews (has the ability to give the user a row for searching data)
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-03-14
*/
#pragma once
#include <LtsDataView/lts_data_view_export.h>
#include <QAbstractItemModel>
#include <QSet>
#include <QString>
#include <QPointer>
namespace LtsDataView
{
class LTSDATAVIEW_EXPORT SearchModel final : public QAbstractItemModel
{
Q_OBJECT
public:
explicit SearchModel(QObject *parent = nullptr);
void setSourceModel(QAbstractItemModel* sourceModel);
QAbstractItemModel *sourceModel() const { return m_sourceModel; }
QVariant data(const QModelIndex &index, int role) const override final;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
int columnCount(const QModelIndex &parent = QModelIndex()) const override final;
int rowCount(const QModelIndex &parent) const override final;
bool setData(const QModelIndex &index, const QVariant &value, int role) override final;
Qt::ItemFlags flags(const QModelIndex &index) const override final;
QModelIndex index(int row, int column, const QModelIndex &parent) const override final;
QModelIndex parent(const QModelIndex &child) const override final { (void)child; return QModelIndex(); }
signals:
void stringFilterForColumnChanged(const QString &newFilterString, int column);
void dataFilterForColumnChanged(const QVariant &newFilterData, int column);
void signalFilterChanged();
private:
QVariant m_searchIcon;
QPointer<QAbstractItemModel> m_sourceModel;
QHash<int, QVariant> m_columnFilters;
QHash<int, QVariant> m_displayData;
QHash<int, QVariant> m_comboBoxData;
QSet<int> m_hideDecorationColumns;
};
} // namespace LtsDataView
+103
View File
@@ -0,0 +1,103 @@
/**
* @RDE_HEADER@
* Test for LtsDataView and their AbstractDisplayWidgets
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-03-14
*/
#include "test.h"
#include <lts_data_view.h>
#include <QApplication>
#include <QDebug>
#include <QLabel>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QElapsedTimer>
#include <QScrollArea>
#include <QScroller>
Disp::Disp()
: LtsDataView::AbstractDisplayWidget(nullptr)
, m_label(new QLabel(this))
{
}
bool Disp::init(const QModelIndex &idx)
{
if (!idx.isValid())
return false;
m_label->setText(rowData(idx, 0).toString());
return true;
}
int main(int argc, char **argv)
{
QApplication app(argc,argv);
int rows = 20;
int cols = 7;
QElapsedTimer et;
et.start();
qWarning() << "creating" << rows << "items";
qWarning() << "wait..";
LtsDataView::LtsDataView *view = new LtsDataView::LtsDataView();
QStandardItemModel model;
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
{
QStandardItem *item = new QStandardItem(QStringLiteral("Item %1/%2").arg(r).arg(c));
model.setItem(r,c,item);
}
}
view->setModel(&model, [](){ return new Disp(); });
view->show();
#ifdef TABLET_MODE
auto widget = view;
if (widget)
{
widget->setAttribute(Qt::WA_AcceptTouchEvents);
{
QScrollArea *sca = qobject_cast<QScrollArea *>(widget);
if (sca)
{
qWarning() << widget << "is scroll area";
QScroller::grabGesture(sca->viewport(), QScroller::LeftMouseButtonGesture);
QScroller::grabGesture(sca, QScroller::LeftMouseButtonGesture);
}
else
{
QAbstractItemView *aiv = qobject_cast<QAbstractItemView *>(widget);
if (aiv)
{
qWarning() << widget << "is abst. item view";
QScroller::grabGesture(aiv->viewport(), QScroller::LeftMouseButtonGesture);
QScroller::grabGesture(aiv, QScroller::LeftMouseButtonGesture);
aiv->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
aiv->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
}
}
}
}
#endif
qWarning() << "took" << et.elapsed() << "ms";
return app.exec();
}
+28
View File
@@ -0,0 +1,28 @@
/**
* @RDE_HEADER@
* Search Model for TableViews (has the ability to give the user a row for searching data)
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-03-14
*/
#pragma once
#include "abstract_display_widget.h"
class QLabel;
class Disp : public LtsDataView::AbstractDisplayWidget
{
Q_OBJECT
public:
Disp();
bool init(const QModelIndex &idx) override;
private:
QLabel *m_label;
};
+82
View File
@@ -0,0 +1,82 @@
/**
* @RDE_HEADER@
* A QTreeView with some events catched
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-10-07
*/
#include "tree_view.h"
#include <QGuiApplication>
#include <QKeyEvent>
namespace LtsDataView
{
// needed until QTBUG-78726 is fixed
void TreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QVector<int> &roles)
{
QTreeView::dataChanged(topLeft, bottomRight, roles);
if (!m_toolTipPos.isNull() && (roles.isEmpty() || roles.contains(Qt::ToolTipRole)))
{
if (viewport()->mapToGlobal(m_toolTipPos) != QCursor::pos())
{
m_toolTipPos = QPoint();
return;
}
const QModelIndex index = indexAt(m_toolTipPos);
if (index.row() >= topLeft.row() && index.row() <= bottomRight.row() &&
index.column() >= topLeft.column() && index.column() <= bottomRight.column())
{
QHelpEvent he(QEvent::ToolTip, m_toolTipPos, viewport()->mapToGlobal(m_toolTipPos));
QTreeView::viewportEvent(&he);
m_toolTipPos = QPoint();
}
}
}
void TreeView::keyPressEvent(QKeyEvent *event)
{
if (QGuiApplication::keyboardModifiers() == Qt::ControlModifier
&& event->key() == Qt::Key_C)
emit signalCopyToClipBoard(); // queue !
QTreeView::keyPressEvent(event);
}
bool TreeView::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
{
if (trigger == QAbstractItemView::NoEditTriggers)
{
const QMouseEvent *me = dynamic_cast<QMouseEvent*>(event);
if (me && me->buttons().testFlag(Qt::LeftButton))
trigger = QAbstractItemView::AllEditTriggers;
}
return QTreeView::edit(index, trigger, event);
}
// needed until QTBUG-78726 is fixed
bool TreeView::viewportEvent(QEvent *event)
{
bool ret = QTreeView::viewportEvent(event);
if (event->type() == QEvent::ToolTip)
{
if (!ret)
{
QHelpEvent *he = static_cast<QHelpEvent*>(event);
m_toolTipPos = he->pos();
}
else
m_toolTipPos = QPoint();
}
return ret;
}
} // namespace LtsDataView
+37
View File
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* A QTreeView with some events catched
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-10-07
*/
#pragma once
#include <QTreeView>
namespace LtsDataView
{
class TreeView final : public QTreeView
{
Q_OBJECT
public:
using QTreeView::QTreeView;
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QVector<int> &roles) override;
protected:
void keyPressEvent(QKeyEvent *event) override;
bool edit(const QModelIndex &index, EditTrigger trigger, QEvent *event) override;
bool viewportEvent(QEvent *event) override;
signals:
void signalCopyToClipBoard();
private:
QPoint m_toolTipPos;
};
} // namespace LtsDataView
+152
View File
@@ -0,0 +1,152 @@
#include "lts_data_view.h"
#include "tree_view_delegate.h"
#include "search_model.h"
#include <QApplication>
#include <QComboBox>
#include <QTimer>
//#include <QDebug>
namespace LtsDataView
{
TreeViewDelegate::ComboBoxData TreeViewDelegate::comboBoxData(const QModelIndex &index)
{
const SearchModel *sm = qobject_cast<const SearchModel *>(index.model());
if (!sm)
return {};
const QAbstractItemModel *aim = sm->sourceModel();
if (!aim)
return {};
const QVariant val = aim->headerData(index.column(), Qt::Horizontal, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
return LtsWidgets::ComboboxFilterContent::fromVariant(val);
}
void TreeViewDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const ComboBoxData cbd = comboBoxData(index);
if (!cbd.isValid())
return QStyledItemDelegate::paint(painter, option, index);
const QWidget *const widget = option.widget;
QStyle* const style = widget ? widget->style() : QApplication::style();
QStyleOptionComboBox cbOption;
cbOption.rect = option.rect;
cbOption.direction = option.direction;
const auto currentData = index.data(LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
for (const auto &content : cbd.data)
{
if (content.data == currentData)
{
cbOption.currentIcon = content.icon;
break;
}
}
cbOption.currentText = index.data(Qt::DisplayRole).toString();
cbOption.fontMetrics = option.fontMetrics;
const int iconWidth = style->pixelMetric(QStyle::PM_SmallIconSize, nullptr, widget);
cbOption.iconSize = QSize(iconWidth, iconWidth);
cbOption.palette = option.palette;
cbOption.state = option.state;
cbOption.styleObject = option.styleObject;
style->drawComplexControl(QStyle::CC_ComboBox, &cbOption, painter, widget);
style->drawControl(QStyle::CE_ComboBoxLabel, &cbOption, painter, widget);
}
QWidget *TreeViewDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
Q_UNUSED(option);
const ComboBoxData cbd = comboBoxData(index);
if (cbd.isValid())
{
QComboBox *cbx = new QComboBox(parent);
for (const auto &content : cbd.data)
cbx->addItem(content.icon, content.text, content.data);
if (cbd.sortItems)
cbx->model()->sort(0);
cbx->insertItem(0, noFilterString());
connect(cbx, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &TreeViewDelegate::slotFinished);
QTimer::singleShot(0, cbx, &QComboBox::showPopup);
return cbx;
}
else
{
#ifdef TABLET_MODE
//qWarning() << "TABLET MODE !!!!!!!!";
// no line edit as it crashes
return nullptr;
#else
//qWarning() << "****NO**** TABLET MODE !!!!!!!!!!!!!!!!";
SearchLineEdit *edit = new SearchLineEdit(parent);
edit->setFrame(false);
connect(edit, &SearchLineEdit::editingFinished,
this, &TreeViewDelegate::slotFinished);
return edit;
#endif
}
}
void TreeViewDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
const ComboBoxData cbd = comboBoxData(index);
if (cbd.isValid())
{
QComboBox *cbx = qobject_cast<QComboBox *>(editor);
if (cbx)
{
// save the current data since it may change within setData() due to dataChanged() signals
const QString curTxt = cbx->currentText();
const QVariant curData = cbx->currentData();
model->setData(index, curData, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
model->setData(index, curTxt, Qt::DisplayRole);
}
}
else
{
SearchLineEdit *edit = qobject_cast<SearchLineEdit *>(editor);
if (edit)
{
model->setData(index, edit->text(), Qt::DisplayRole);
model->setData(index, edit->text(), Qt::EditRole);
}
}
}
void TreeViewDelegate::slotFinished()
{
QWidget *w = qobject_cast<QWidget *>(sender());
if (!w)
return;
emit commitData(w);
emit closeEditor(w);
}
void TreeViewDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
const ComboBoxData cbd = comboBoxData(index);
if (cbd.isValid())
{
QComboBox *cbx = qobject_cast<QComboBox *>(editor);
if (cbx)
{
const auto currentData = index.data(LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
cbx->setCurrentIndex(cbx->findData(currentData));
}
}
else
{
SearchLineEdit *edit = qobject_cast<SearchLineEdit *>(editor);
if (edit)
edit->setText(index.data().toString());
}
}
} // namespace LtsDataView
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <QStyledItemDelegate>
#include <QStyle>
namespace LtsDataView
{
class TreeViewDelegate final : public QStyledItemDelegate // needed to tell the QLineEdit to be as compact as possible while editing
{
Q_OBJECT
public:
using ComboBoxData = LtsWidgets::ComboboxFilterContent;
using QStyledItemDelegate::QStyledItemDelegate;
void paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const override;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const override;
static QString noFilterString() { return tr("<No filter>"); }
private:
static ComboBoxData comboBoxData(const QModelIndex &index);
private slots:
void slotFinished();
};
} // namespace LtsDataView
+68
View File
@@ -0,0 +1,68 @@
#
# CMakeLists.txt for File Dialog
#
# $Id$
# $HeadURL$
# $Author$
# Created by Iuliana Ojog, SLSE, 2017-07-12
#
SET(ltsFileDialog_SRCS
lts_file_dialog_widget.h
lts_file_dialog_widget.cpp
lts_file_dialog.h
lts_file_dialog.cpp
lts_dialog_model_folder.h
lts_dialog_model_folder.cpp
lts_dialog_model_file.h
lts_dialog_model_file.cpp
)
NGL_WRAP_UI(ltsFileDialog_SRCS
lts_file_dialog.ui
)
NGL_ADD_LIBRARY2(WS LtsFileDialog SHARED ${ltsFileDialog_SRCS})
NGL_TARGET_LINK_LIBRARIES(LtsFileDialog
PRIVATE
LtsWidgets
LtsDataView
LtsSession
LtsSessionData
nglwidgets
ngltools
svcFlmCommon
svcOpmCommon
svcExmCommon
LtsUtilsCoreHeaderOnly
LtsUtilsGuiConnectDialog
PUBLIC
Qt5::Core
Qt5::Widgets
)
NGL_TARGET_INCLUDE_DIRECTORIES(LtsFileDialog
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
# Test-Executable
NGL_ADD_EXECUTABLE(WS NO_TRANSLATION LtsFileDialogTest test.cpp)
NGL_TARGET_LINK_LIBRARIES(LtsFileDialogTest
PRIVATE
LtsFileDialog
LtsWidgets
LtsDataView
LtsSession
LtsSessionData
nglwidgets
ngltools
nglcoreapplication
svcFlmClient
svcOpmClient
svcExmClient
# RTI::nddscpp2
ddsconnector
PUBLIC
Qt5::Core
Qt5::Widgets
)
+205
View File
@@ -0,0 +1,205 @@
/**
* @RDE_HEADER@
* from FileManagement - FileContent model
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2017-07-11
*/
#include "lts_dialog_model_file.h"
#include <ngltools/ngltools_dtg.h>
#include <QGuiApplication>
#include <QPalette>
#include <QMimeData>
#include <Services/FileManagement/flm_translation.h>
using namespace LtsWidgets;
//-------------------------------------------------------------------------------------
// DialogModelFile
//-------------------------------------------------------------------------------------
DialogModelFile::DialogModelFile(QObject *parent)
: LtsWidgets::LtsAbstractTableModel<FileManagement::FileContent>({tr("Name"),
tr("Template"),
tr("Type"),
tr("Category"),
tr("Status"),
tr("Exercise"),
tr("Phase"),
tr("Operator"),
tr("Used"),
tr("Uses"),
tr("Last modified"),
tr("Properties")},
parent)
, m_flmDtc(nullptr)
, m_opmDtc(nullptr)
{
}
//-------------------------------------------------------------------------------------
bool DialogModelFile::initModel(const std::shared_ptr<FileManagement::Interface::Dtc> &dtc,
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
const QString &xmlType,
const std::function<bool(const FileManagement::FileContent &, const QString &)> &predicate)
{
m_flmDtc = dtc;
m_opmDtc = opmDtc;
clear();
// insert Model
auto files = [this, xmlType, predicate](const FileManagement::FileContent & fc)
{
if (!predicate(fc, xmlType))
return;
insertRow(fc);
};
m_flmDtc->fileContents(files);
return true;
}
//-------------------------------------------------------------------------------------
QVariant DialogModelFile::data(const QModelIndex &index, int role) const
{
if (!indexIsValid(index))
return {};
const FileManagement::FileContent &fl = getRowData(index.row());
switch(role)
{
case Qt::BackgroundRole:
{
if (fl.fileStatus() == FileManagement::FileStatus::Deleted)
return QGuiApplication::palette().color(QPalette::Disabled, QPalette::AlternateBase);
return QGuiApplication::palette().color(QPalette::Active, QPalette::Base);
}
case Qt::DisplayRole:
{
switch (index.column())
{
case NAME:
return QString::fromStdString(fl.name());
case ISTEMPLATE:
return fl.isTemplate() ? tr("Yes") : tr("No");
case FOLDER:
return fl.folderId();
case FILETYPE:
return FileManagement::toString(fl.fileType());
case FILECATEGORY:
return FileManagement::toString(fl.fileCategory());
case FILESTATUS:
return FileManagement::toString(fl.fileStatus());
case OPERATOR:
return QString::fromStdString(m_opmDtc->user(fl.operatorId()).name());
case EXERCISE:
return fl.exerciseId().is_set() ? fl.exerciseId().get() : QVariant();
case PHASE:
return fl.phaseId().is_set() ? fl.phaseId().get() : QVariant();
case USEDBY:
return fl.isUsedBy() ? tr("Yes") : tr("No");
case USES:
return fl.usedBy();
case LASTMODIFIED:
return DTG::toStringMSec(fl.lastModified());
case PROPERTIES:
return QString::fromStdString(fl.properties());
default:
break;
}
}
case Qt::DecorationRole:
{
if (index.column() == NAME && fl.isHidden())
return QIcon(QLatin1String(":/style/lock.svg"));
break;
}
default:
break;
}
return {};
}
//-------------------------------------------------------------------------------------
int DialogModelFile::findFileIdFromName(const QString &fileName) const
{
const int rc = rowCount();
for (int row = 0; row < rc; ++row)
{
const FileManagement::FileContent &fl = getRowData(row);
if (QString::fromStdString(fl.name()) == fileName)
{
return fl.id();
}
}
return 0;
}
//-------------------------------------------------------------------------------------
const QLatin1String MIMETYPE("application/LtsDialogModelFile/FileId");
//-------------------------------------------------------------------------------------
QStringList DialogModelFile::mimeTypes() const { return QStringList() << MIMETYPE; }
//-------------------------------------------------------------------------------------
QMimeData * DialogModelFile::mimeData(const QModelIndexList &indexes) const
{
if (indexes.isEmpty()) return nullptr;
if (indexes.size() > 1) return nullptr;
const QModelIndex & index = indexes.first();
const FileManagement::FileContent & fl = getRowData(index.row());
int id = fl.id();
if (id <= 0) return nullptr;
QMimeData * mimeData = new QMimeData();
QByteArray encodedData;
mimeData->setData( MIMETYPE, encodedData.setNum(id) );
return mimeData;
}
void DialogFileProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<DialogModelFile*>(sourceModel);
LtsWidgets::LtsColumnFilterProxyModel::setSourceModel(sourceModel);
}
bool DialogFileProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (!m_sourceModel ||
source_left.column() != source_right.column() ||
!source_left.isValid() ||
!source_right.isValid())
return LtsWidgets::LtsColumnFilterProxyModel::lessThan(source_left, source_right);
const auto &dataLeft = m_sourceModel->m_vecData.at(source_left.row());
const auto dataRight = m_sourceModel->m_vecData.at(source_right.row());
switch (source_left.column())
{
case LASTMODIFIED:
return dataLeft.lastModified() < dataRight.lastModified();
case NAME:
case ISTEMPLATE:
case FILETYPE:
case FILECATEGORY:
case FILESTATUS:
case EXERCISE:
case PHASE:
case OPERATOR:
case USEDBY:
case USES:
case PROPERTIES:
case FOLDER:
case COUNT:
break;
}
return LtsWidgets::LtsColumnFilterProxyModel::lessThan(source_left, source_right);
}
+88
View File
@@ -0,0 +1,88 @@
/**
* @RDE_HEADER@
* from FileManagement - FileContent model
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2017-07-11
*/
#pragma once
#include <Services/FileManagement/flm_dtc.h>
#include <Services/OperatorManagement/opm_dtc.h>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
// --------------------------------------------------------
namespace LtsWidgets
{
// --------------------------------------------------------
enum Columns
{
NAME = 0,
ISTEMPLATE,
FILETYPE,
FILECATEGORY,
FILESTATUS,
EXERCISE,
PHASE,
OPERATOR,
USEDBY,
USES,
LASTMODIFIED,
PROPERTIES,
FOLDER,
COUNT,
};
// --------------------------------------------------------
class DialogModelFile : public LtsWidgets::LtsAbstractTableModel<FileManagement::FileContent>
{
Q_OBJECT
public:
explicit DialogModelFile(QObject *parent = nullptr);
bool initModel(const std::shared_ptr<FileManagement::Interface::Dtc> &dtc,
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
const QString &xmlType,
const std::function<bool(const FileManagement::FileContent &, const QString &)> &predicate);
QVariant data(const QModelIndex &, int) const override final;
int findFileIdFromName(const QString &fileName) const;
QStringList mimeTypes() const override;
QMimeData *mimeData(const QModelIndexList &indexes) const override;
Qt::DropActions supportedDragActions() const override
{
return Qt::CopyAction | Qt::MoveAction;
}
Qt::ItemFlags flags(const QModelIndex &modelIndex) const override
{
return LtsWidgets::LtsAbstractTableModel<FileManagement::FileContent>::flags(modelIndex) | Qt::ItemIsDragEnabled;
}
private:
std::shared_ptr<FileManagement::Interface::Dtc> m_flmDtc;
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc;
friend class DialogFileProxyModel;
};
class DialogFileProxyModel final : public LtsWidgets::LtsColumnFilterProxyModel
{
Q_OBJECT
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
void setSourceModel(QAbstractItemModel *sourceModel) override;
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
private:
DialogModelFile *m_sourceModel = nullptr;
};
}
+344
View File
@@ -0,0 +1,344 @@
/**
* @RDE_HEADER@
* from FileManangement - Folder model
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2017-07-11
*/
#include "lts_dialog_model_folder.h"
#include <nglwidgets/ngltreeitem.h>
#include <FileManagement/flm_translation.h>
//#include <QDebug>
namespace LtsWidgets
{
//-----------------------------------------------------------------------------------------------------------
// DialogModelFolder
//-----------------------------------------------------------------------------------------------------------
DialogModelFolder::DialogModelFolder(QObject *parent
, NGLTreeItem *rootItem
, const std::shared_ptr<FileManagement::Interface::Dtc> &dtc
, const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc
, const QStringList &header)
: NGLTreeModel(parent, rootItem, header)
, m_flmDtc(dtc)
, m_exmDtc(exmDtc)
{
}
//-----------------------------------------------------------------------------------------------------------
QVariant DialogModelFolder::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
switch (section)
{
case ID:
return tr("Id");
case NAME:
return tr("Folder");
default:
break;
}
}
return NGLTreeModel::headerData(section, orientation, role);
}
//-----------------------------------------------------------------------------------------------------------
QVariant DialogModelFolder::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return {};
NGLTreeItem *item = privateData(index);
if (item->data().canConvert<FileManagement::Folder>())
{
FileManagement::Folder folderData = item->data().value<FileManagement::Folder>();
switch(role)
{
case Qt::DisplayRole:
{
switch (index.column())
{
case NAME:
return getFolderName(folderData);
case ID:
return folderData.id();
default:
break;
}
}
case Qt::UserRole:
return folderData.id();
case Qt::DecorationRole:
{
if (folderData.isHidden())
return item->icon();
break;
}
default:
break;
}
}
return {};
}
//-----------------------------------------------------------------------------------------------------------
FileManagement::Folder DialogModelFolder::getFolder(const QModelIndex &idx) const
{
return privateData(idx)->data().value<FileManagement::Folder>();
}
//-----------------------------------------------------------------------------------------------------------
QString DialogModelFolder::getFolderName(const FileManagement::Folder &folderData) const
{
QString folderName = QString::fromStdString(folderData.name());
if (folderName.startsWith(QStringLiteral("$")))
{
folderName.remove(0,1);
if (folderName.startsWith(QStringLiteral("EX_")))
{
int exId = folderName.remove(0,3).toInt();
return QString::fromStdString(m_exmDtc->exercise(exId).name());
}
if (folderName.startsWith(QStringLiteral("PH_")))
{
int phId = folderName.remove(0,3).toInt();
return QString::fromStdString(m_exmDtc->exercisePhase(phId).name());
}
return FileManagement::trFolderName(folderName.toStdString());
}
return FileManagement::trFolderName(folderName.toStdString());
}
//-----------------------------------------------------------------------------------------------------------
bool DialogModelFolder::isRowRemovable(NGLTreeItem *parentItem) const
{
if (!parentItem)
return false;
FileManagement::Folder folderData = parentItem->data().value<FileManagement::Folder>();
return folderData.isEditable();
}
//-----------------------------------------------------------------------------------------------------------
bool DialogModelFolder::initModel(int exerciseId, const QVector<FileManagement::MainFolder> &mainFolders)
{
NGLTreeModel::resetModel();
QMap<qint32,FileManagement::Folder> tmap;
QHash<int, QModelIndex> parentItemIndexCache;
QVector<int> idsToExclude;
auto cbFolders = [exerciseId, &tmap, &idsToExclude, &mainFolders] (const FileManagement::Folder &data)
{
if (data.isDeleted())
return;
if (exerciseId > 0)
{
QString folderName = QString::fromStdString(data.name());
if (folderName.startsWith(QStringLiteral("$EX_")))
{
int exId = folderName.remove(0, 4).toInt();
if (exId != exerciseId)
idsToExclude.append(data.id());
}
}
FileManagement::MainFolder mainFolder = static_cast<FileManagement::MainFolder::type>(data.path()[0]);
//qCritical() << "Folder = " << QString::fromStdString(data.name()) << ", mainFolder = " << mainFolder.underlying();
if (!mainFolders.contains(mainFolder))
{
// qCritical() << "Excluded id = " << data.id();
idsToExclude.append(data.id());
}
tmap.insert(data.id(), data);
};
m_flmDtc->folders(cbFolders);
parentItemIndexCache.insert(0, QModelIndex()); //root
for (QMap<qint32, FileManagement::Folder>::const_iterator iter = tmap.constBegin();
iter != tmap.constEnd(); ++iter)
{
int folderId = iter.key();
int parentId = 0;
FileManagement::Folder fld = iter.value();
if (fld.path().size() > 1)
{
parentId = fld.path().at(fld.path().size() - 2);
int idPos2 = fld.path().at(1);
if (idsToExclude.contains(idPos2))
continue;
}
else // main Folders
{
if (idsToExclude.contains(fld.id()))
continue;
}
QVariant data;
data.setValue(fld);
if (!parentItemIndexCache.contains(parentId))
{
return false;
}
else
{
QModelIndex pIndex = parentItemIndexCache.value(parentId);
int rowPos = -1;
onInsertRow(rowPos, pIndex, fld);
parentItemIndexCache.insert(folderId, index(rowPos, 0, pIndex));
}
}
return true;
}
//----------------------------------------------------------------------------
bool DialogModelFolder::onInsertRow(int &row, const QModelIndex &parent, const FileManagement::Folder &folderData)
{
row = rowCount(parent);
QVariant data;
data.setValue(folderData);
QIcon icon;
if (folderData.isHidden())
icon = QIcon(QLatin1String(":/style/lock.svg"));
NGLTreeItem *item = new NGLTreeItem(data, icon);
item->setModified(true);
return NGLTreeModel::insertRow(row, parent, item);
}
//----------------------------------------------------------------------------
bool DialogModelFolder::onUpdateRow(const QModelIndex &index, const FileManagement::Folder &folderData)
{
QVariant data;
data.setValue(folderData);
QIcon icon;
if (folderData.isHidden())
icon = QIcon(QLatin1String(":/style/lock.svg"));
return setItemData(index, data, icon);
}
//----------------------------------------------------------------------------
bool DialogModelFolder::onDeleteRow(const QModelIndex &idx, bool isFirstItem)
{
while(rowCount(idx) > 0)
{
onDeleteRow(NGLTreeModel::index(0, 0, idx),false);
}
if (isFirstItem) //edit mode
{
NGLTreeItem *item = privateData(idx);
FileManagement::Folder data = item->data().value<FileManagement::Folder>();
data.isDeleted(true);
}
removeRow(idx.row(), idx.parent());
return true;
}
//----------------------------------------------------------------------------
QModelIndex DialogModelFolder::getIndex(int folderId) const
{
QModelIndexList list = match(index(0, 0), Qt::UserRole, QVariant::fromValue(folderId), 1, Qt::MatchRecursive);
if (!list.isEmpty())
return list.first();
return {};
}
//----------------------------------------------------------------------------
void DialogModelProxyFolder::setSourceModel(QAbstractItemModel *model)
{
m_sourceModel = qobject_cast<DialogModelFolder*>(model);
QSortFilterProxyModel::setSourceModel(model);
}
//----------------------------------------------------------------------------
bool DialogModelProxyFolder::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (!m_sourceModel || source_left.column() != source_right.column())
return QSortFilterProxyModel::lessThan(source_left, source_right);
const NGLTreeItem *itemLeft = m_sourceModel->privateData(source_left);
const NGLTreeItem *itemRight = m_sourceModel->privateData(source_right);
if (!itemLeft || !itemRight)
return QSortFilterProxyModel::lessThan(source_left, source_right);
const FileManagement::Folder left = itemLeft->data().value<FileManagement::Folder>();
const FileManagement::Folder right = itemRight->data().value<FileManagement::Folder>();
if (left.id() == FileManagement::MainFolder::GlobalDocuments || right.id() == FileManagement::MainFolder::GlobalDocuments ||
left.id() == FileManagement::MainFolder::UserDocuments || right.id() == FileManagement::MainFolder::UserDocuments ||
left.id() == FileManagement::MainFolder::ExerciseDocuments || right.id() == FileManagement::MainFolder::ExerciseDocuments)
{
return left.id() < right.id();
}
if (QString::fromStdString(left.name()) != QString::fromStdString(right.name()))
{
return (QString::fromStdString(left.name()) < QString::fromStdString(right.name()));
}
return left.id() < right.id();
}
//----------------------------------------------------------------------------
void DialogModelProxyFolder::sort(int column, Qt::SortOrder order)
{
Qt::SortOrder myOrder = order;
if (column == 0)
myOrder = Qt::AscendingOrder;
QSortFilterProxyModel::sort(column, myOrder);
}
//----------------------------------------------------------------------------
bool DialogModelProxyFolder::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!m_sourceModel || !source_parent.isValid())
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
if (m_operatorId == 0) // no filter for admin
return true;
NGLTreeItem *parent = m_sourceModel->privateData(source_parent);
if (!parent)
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
NGLTreeItem *child = parent->child(source_row);
if (!child)
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
const FileManagement::Folder data = child->data().value<FileManagement::Folder>();
if (data.operatorId() != m_operatorId)
{
// it's user folder -> check if it's in user documents and hide if it's not for the current operator
for (int p : data.path())
{
if (p == FileManagement::MainFolder::UserDocuments)
return false;
}
}
return true;
}
//----------------------------------------------------------------------------
void DialogModelProxyFolder::setOperatorId(int operatorId)
{
if (m_operatorId == operatorId)
return;
m_operatorId = operatorId;
invalidateFilter();
}
} // namespace LtsWidgets
+82
View File
@@ -0,0 +1,82 @@
/**
* @RDE_HEADER@
* from FileManangement - Folder Model
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2017-07-11
*/
#pragma once
#include <Services/FileManagement/flm_dtc.h>
#include <Services/ExerciseManagement/exm_dtc.h>
#include <QSortFilterProxyModel>
#include <nglwidgets/ngltreemodel.h>
class QTableWidget;
// -------------------------------------------------------------------------------------
namespace LtsWidgets
{
class DialogModelFolder : public NGLTreeModel
{
Q_OBJECT
public:
enum Columns
{
NAME,
ID
};
explicit DialogModelFolder(QObject *parent
, NGLTreeItem *rootItem
, const std::shared_ptr<FileManagement::Interface::Dtc> &dtc
, const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc
, const QStringList &header);
bool initModel(int exerciseId, const QVector<FileManagement::MainFolder> &mainFolders);
bool isRowRemovable(NGLTreeItem *parentItem) const;
FileManagement::Folder getFolder(const QModelIndex &idx) const;
QModelIndex getIndex(int folderId) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override final;
QVariant data(const QModelIndex &, int) const override final;
QString getFolderName(const FileManagement::Folder &folderData) const;
public Q_SLOTS :
bool onInsertRow(int &row, const QModelIndex &parent, const FileManagement::Folder &folderData);
bool onUpdateRow(const QModelIndex &index, const FileManagement::Folder &folderData);
bool onDeleteRow(const QModelIndex &idx, bool isFirstItem = true);
private:
std::shared_ptr<FileManagement::Interface::Dtc> m_flmDtc;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
};
// -------------------------------------------------------------------------------------
class DialogModelProxyFolder : public QSortFilterProxyModel
{
Q_OBJECT
public:
using QSortFilterProxyModel::QSortFilterProxyModel;
void setOperatorId(int operatorId);
void setSourceModel(QAbstractItemModel *model) override;
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
DialogModelFolder *m_sourceModel = nullptr;
int m_operatorId = 0;
};
} // namespace
// -------------------------------------------------------------------------------------
Q_DECLARE_METATYPE(FileManagement::Folder)
+131
View File
@@ -0,0 +1,131 @@
/**
* @RDE_HEADER@
* LtsFileDialogWidget and LtsFileDialog - custom widgets
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2017-07-11
*/
#include "lts_file_dialog.h"
#include "ui_lts_file_dialog.h"
#include "lts_file_dialog_widget.h"
#include "lts_dialog_model_folder.h"
#include "lts_dialog_model_file.h"
#include <Services/FileManagement/flm_translation.h>
#include <Viewer/LtsDataView/lts_data_view.h>
namespace LtsWidgets
{
//-----------------------------------------------------------------------------------------------------------
// LtsFileDialog
//-----------------------------------------------------------------------------------------------------------
LtsFileDialog::LtsFileDialog(QWidget *parent)
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
, m_editItemWidget(new LtsFileDialogWidget(this))
, m_buttonBox (new LtsWidgets::LtsDialogButtonBox(this))
{
LtsWidgets::DialogButton btnSelectFile = LtsWidgets::DialogButton::Load;
m_buttonBox->setText(btnSelectFile, tr("Select File"));
m_buttonBox->setToolTip(btnSelectFile, tr("Select file from library"));
m_buttonBox->setButtonEnabled(btnSelectFile, false);
m_buttonBox->setButtonVisible(btnSelectFile, true);
connect(m_buttonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, this, &LtsFileDialog::close);
//hide ok and apply
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->hide();
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->hide();
}
//-----------------------------------------------------------------------------------------------------------
LtsFileDialog::~LtsFileDialog()
{
delete m_editItemWidget;
}
//-----------------------------------------------------------------------------------------------------------
bool LtsFileDialog::init(LtsSession::LtsSession *session,
const std::shared_ptr<FileManagement::Interface::Dtc> &dtc,
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
const FileDialogMode &dlgMode,
const QVector<FileManagement::MainFolder> &mainFolders,
const QVector<FileManagement::FileType> &fileTypes,
const int &folderId,
const QString &buttonName,
const QString &xmlType)
{
if (!m_editItemWidget->init(session, dtc, opmDtc, exmDtc, dlgMode, mainFolders, fileTypes, folderId, xmlType))
return false;
m_dialogMode = dlgMode;
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(m_editItemWidget);
layout->addWidget(m_buttonBox);
this->setLayout(layout);
if (!buttonName.isEmpty())
{
m_buttonBox->setText(LtsWidgets::DialogButton::Load, buttonName);
m_buttonBox->setToolTip(LtsWidgets::DialogButton::Load, buttonName);
}
if (m_dialogMode == FileDialogMode::modeSaveFile)
m_buttonBox->connectButton(LtsWidgets::DialogButton::Load, m_editItemWidget, &LtsFileDialogWidget::onChooseFileName);
else if (m_dialogMode == FileDialogMode::modeOpenFile)
m_buttonBox->connectButton(LtsWidgets::DialogButton::Load, m_editItemWidget, &LtsFileDialogWidget::onSelectFile);
connect(m_editItemWidget, &LtsFileDialogWidget::enableButtons, this, &LtsFileDialog::enaDisa);
connect(m_editItemWidget, &LtsFileDialogWidget::accepted, this, &LtsFileDialog::accept);
connect(m_buttonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, this, &LtsFileDialog::reject);
enaDisa();
return true;
}
//-----------------------------------------------------------------------------------------------------------
int LtsFileDialog::getSelectedFileId() const
{
return m_editItemWidget->m_selectedFileContent.id();
}
//-----------------------------------------------------------------------------------------------------------
FileManagement::FileContent LtsFileDialog::getSelectedFile() const
{
return m_editItemWidget->m_selectedFileContent;
}
//-----------------------------------------------------------------------------------------------------------
int LtsFileDialog::getSelectedFolder() const
{
return m_editItemWidget->m_selectedFolderId;
}
//-----------------------------------------------------------------------------------------------------------
QString LtsFileDialog::getFileName() const
{
return m_editItemWidget->m_fileName;
}
//-----------------------------------------------------------------------------------------------------------
void LtsFileDialog::enaDisa()
{
LtsWidgets::DialogButton btnSelectFile = LtsWidgets::DialogButton::Load;
m_buttonBox->setButtonEnabled(btnSelectFile, false);
QModelIndex idxFile = m_editItemWidget->m_ui->widgetFiles->currentIndex();
if (m_dialogMode == FileDialogMode::modeOpenFile && idxFile.isValid())
m_buttonBox->setButtonEnabled(btnSelectFile, true);
if (m_dialogMode == FileDialogMode::modeSaveFile && !m_editItemWidget->m_fileName.isEmpty())
m_buttonBox->setButtonEnabled(btnSelectFile, true);
}
//-----------------------------------------------------------------------------------------------------------
} // namespace LtsWidgets
+78
View File
@@ -0,0 +1,78 @@
/**
* @RDE_HEADER@
* LtsFileDialogWidget and LtsFileDialog - custom widgets
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2017-07-11
*/
#pragma once
#include <Plugins/FileManagement/flm_data_plugin_interface.h>
#include <Services/OperatorManagement/opm_dtc.h>
#include <Services/ExerciseManagement/exm_dtc.h>
#include <LtsWidgets/lts_dialog_button_box.h>
#include <LtsWidgets/lts_frameless_dialog.h>
#include <LtsFileDialog/ltsfiledialog_export.h>
namespace Ui
{
class LtsFileDialogWidget;
}
namespace LtsSession
{
class LtsSession;
}
//----------------------------------------------------------------------------------------------------
// LtsFileDialog
//----------------------------------------------------------------------------------------------------
namespace LtsWidgets
{
enum FileDialogMode
{
modeOpenFile = 0, // used as modal select file to open
modeSaveFile = 1 // used as modal select folder to save file
};
class LtsFileDialogWidget;
//----------------------------------------------------------------------------------------------------
class LTSFILEDIALOG_EXPORT LtsFileDialog : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
friend class LtsFileDialogWidget;
public:
explicit LtsFileDialog(QWidget *parent = nullptr);
~LtsFileDialog();
bool init(LtsSession::LtsSession *session,
const std::shared_ptr<FileManagement::Interface::Dtc> &dtc,
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
const FileDialogMode &dlgMode = FileDialogMode::modeOpenFile,
const QVector<FileManagement::MainFolder> &mainFolders = {},
const QVector<FileManagement::FileType> &fileTypes = {FileManagement::FileType::Unknown},
const int &folderId = 0,
const QString &buttonName = QString(),
const QString &xmlType = QString());
int getSelectedFileId() const;
FileManagement::FileContent getSelectedFile() const;
int getSelectedFolder() const;
QString getFileName() const;
private:
void enaDisa();
private:
LtsFileDialogWidget *m_editItemWidget{nullptr};
LtsWidgets::LtsDialogButtonBox *m_buttonBox{nullptr};
FileDialogMode m_dialogMode{FileDialogMode::modeOpenFile};
};
} // namespace LtsWidgets
+149
View File
@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LtsFileDialogWidget</class>
<widget class="QWidget" name="LtsFileDialogWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>925</width>
<height>559</height>
</rect>
</property>
<property name="windowTitle">
<string>Exercise Management</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lblFolder">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Selected Folder:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblSelectedFolder">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTreeView" name="tvFolder">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::CurrentChanged|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="LtsDataView::LtsDataView" name="widgetFiles">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>500</width>
<height>0</height>
</size>
</property>
<property name="showColumnCount" stdset="0">
<bool>false</bool>
</property>
<property name="toolButtonsVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="lblFilter">
<property name="text">
<string>Filtering:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="lblFile">
<property name="text">
<string>Selected File:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="leFile">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
+391
View File
@@ -0,0 +1,391 @@
/**
* @RDE_HEADER@
* LtsFileDialogWidget and LtsFileDialog - custom widgets
* $Id$
* $HeadURL$
* $Author$
*
* Created by Iuliana Ojog & Mike Wille, SLSE, 2017-09-15
*/
#include "lts_file_dialog_widget.h"
#include "lts_file_dialog.h"
#include "lts_dialog_model_file.h"
#include "lts_dialog_model_folder.h"
#include "ui_lts_file_dialog.h"
#include <LtsSession/lts_session.h>
#include <LtsSession/lts_session_data.h>
#include <nglwidgets/ngltreeitem.h>
#include <Services/FileManagement/flm_translation.h>
#include <ConnectDialog/connect_dialog_nt.h>
#include <LtsUtilsCore/dds_vector.h>
#include <QItemSelectionModel>
namespace LtsWidgets
{
//-----------------------------------------------------------------------------------------------------------
LtsFileDialogWidget::LtsFileDialogWidget(QWidget *parent)
: QWidget(parent)
, m_ui(new Ui::LtsFileDialogWidget)
, m_selectedFileContent(FileManagement::FileContent())
{
m_ui->setupUi(this);
}
//-----------------------------------------------------------------------------------------------------------
LtsFileDialogWidget::~LtsFileDialogWidget()
{
delete m_ui;
}
//-----------------------------------------------------------------------------------------------------------
bool LtsFileDialogWidget::init(LtsSession::LtsSession *session,
const std::shared_ptr<FileManagement::Interface::Dtc> &dtc,
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
const FileDialogMode &dlgMode,
const QVector<FileManagement::MainFolder> &mainFolders,
const QVector<FileManagement::FileType> &fileTypes,
const int &folderId,
const QString &xmlType)
{
m_session = session;
m_dtc = dtc;
m_opmDtc = opmDtc;
m_exmDtc = exmDtc;
m_dialogMode = dlgMode;
m_fileTypes = fileTypes;
m_selectedFolderId = folderId;
m_xmlType = xmlType;
m_mainFolders = mainFolders;
if ((dtc.get() == nullptr) || (opmDtc.get() == nullptr))
return false;
m_dtc->enableFolder();
m_dtc->waitForHistoricalDataFolder();
m_dtc->enableFileContent();
m_dtc->waitForHistoricalDataFileContent();
m_opmDtc->enableUser();
m_opmDtc->waitForHistoricalDataUser();
m_exmDtc->enableExercise();
m_exmDtc->waitForHistoricalDataExercise();
m_exmDtc->enableExercisePhase();
m_exmDtc->waitForHistoricalDataExercisePhase();
// DDS connects
connect(m_dtc.get(), &FileManagement::Interface::Dtc::folderChanged, this, &LtsFileDialogWidget::onFolderChanged);
connect(m_dtc.get(), &FileManagement::Interface::Dtc::fileContentChanged, this, &LtsFileDialogWidget::onFileChanged);
// model folder
QVariant data;
FileManagement::Folder dummyFolder;
data.setValue(dummyFolder);
NGLTreeItem *rootItem = new NGLTreeItem(data, QIcon());
m_modelFolder = new DialogModelFolder(this, rootItem, m_dtc, m_exmDtc,
QStringList()
<< tr("Name") << tr("Id"));
m_modelFolder->initModel(m_session->exerciseId(), m_mainFolders);
m_proxyModelFolder = new DialogModelProxyFolder(this);
m_proxyModelFolder->setOperatorId(LtsSessionData::LtsSessionData::getInstance()->getOperatorId());
m_proxyModelFolder->setSourceModel(m_modelFolder);
m_proxyModelFolder->sort(DialogModelFolder::Columns::ID, Qt::AscendingOrder);
// UI
m_ui->tvFolder->setModel(m_proxyModelFolder);
m_ui->tvFolder->expandAll();
m_ui->tvFolder->setExpanded(m_proxyModelFolder->index(0,0),true);
m_ui->tvFolder->hideColumn(DialogModelFolder::Columns::ID);
// SelectionModel Folder
QItemSelectionModel *selectionModelFolder = m_ui->tvFolder->selectionModel();
connect(selectionModelFolder, &QItemSelectionModel::selectionChanged, this, &LtsFileDialogWidget::onFolderSelectionChanged);
// model file
m_modelFile = new DialogModelFile(this);
// initial all valid, not-deleted files
auto predicate = [](const FileManagement::FileContent &fc, const QString &xmlType)
{
return (!fc.isDeleted() && fc.fileStatus() == FileManagement::FileStatus::Valid &&
(xmlType.isEmpty() || fc.properties().find(xmlType.toStdString()) != std::string::npos));
};
m_modelFile->initModel(m_dtc, m_opmDtc, xmlType, predicate);
// auto predicate = [](const FileManagement::FileContent &fc)
// {
// return (!fc.isDeleted() && fc.fileStatus() == FileManagement::FileStatus::Valid);
// };
// m_modelFile->initModel(m_dtc, m_opmDtc, m_xmlType, predicate);
// UI file
m_ui->widgetFiles->seamless();
m_proxyModelFile = new DialogFileProxyModel(this);
m_proxyModelFile->setSourceModel(m_modelFile);
m_ui->widgetFiles->setModel(m_proxyModelFile);
m_ui->widgetFiles->hideColumn(FOLDER);
// double click to select file
connect(m_ui->widgetFiles, &LtsDataView::LtsDataView::signalDoubleClicked, this, &LtsFileDialogWidget::onSelectFile);
// initial folder selection
selectFolder();
// selection changed File
connect(m_ui->widgetFiles, &LtsDataView::LtsDataView::signalSelectionChanged, this, &LtsFileDialogWidget::enaDisa);
// enable filename edit
if (m_dialogMode == FileDialogMode::modeSaveFile)
{
m_ui->leFile->setEnabled(true);
connect(m_ui->leFile, &QLineEdit::textChanged, this, &LtsFileDialogWidget::saveFileName);
}
// filtering on fileTypes
if (m_fileTypes.contains(FileManagement::FileType::Unknown)) // no filtering
m_ui->lblFilter->setVisible(false);
else
{
QString labelFilter = tr("Filtering:") + QLatin1String(" <b>");
QStringList types;
types.reserve(m_fileTypes.size());
for (auto &ft : m_fileTypes)
types << toString(ft);
labelFilter += types.join(QLatin1String(", "));
labelFilter += QLatin1String("</b>");
m_ui->lblFilter->setText(labelFilter);
}
enaDisa();
return true;
}
//-----------------------------------------------------------------------------------------------------------
void LtsFileDialogWidget::selectFolder()
{
QModelIndex idx;
QItemSelectionModel *selectionModelFolder = m_ui->tvFolder->selectionModel();
if (m_selectedFolderId > 0)
idx = m_proxyModelFolder->mapFromSource(m_modelFolder->getIndex(m_selectedFolderId));
if (idx.isValid())
selectionModelFolder->setCurrentIndex(idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
else
selectionModelFolder->setCurrentIndex(m_modelFolder->index(0,0), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}
//-----------------------------------------------------------------------------------------------------------
void LtsFileDialogWidget::onFolderSelectionChanged(const QItemSelection& /*selected*/,
const QItemSelection& /*deselected*/)
{
enaDisa();
auto predicate = [this](const FileManagement::FileContent & fc, const QString &xmlType)
{
return showFile(fc, xmlType);
};
m_modelFile->initModel(m_dtc, m_opmDtc, m_xmlType, predicate);
}
//-----------------------------------------------------------------------------------------------------------
void LtsFileDialogWidget::requestReadingSelectedFile()
{
emit readSelectedFile(m_selectedFileContent.id());
}
//-----------------------------------------------------------------------------------------------------------
FileManagement::FileContent LtsFileDialogWidget::onSelectFile()
{
QModelIndex selIndex = m_ui->widgetFiles->currentIndex();
if (!selIndex.isValid())
return FileManagement::FileContent();
m_selectedFileContent = m_modelFile->getRowData(selIndex.row());
emit accepted();
return m_selectedFileContent;
}
//-----------------------------------------------------------------------------------------------------------
void LtsFileDialogWidget::onChooseFileName()
{
if ((m_dialogMode == FileDialogMode::modeSaveFile) && (!m_fileName.isEmpty()))
{
emit accepted();
}
}
//----------------------------------------------------------------------------
void LtsFileDialogWidget::onFolderChanged(const FileManagement::Folder &data, DataModification modType)
{
Q_UNUSED(data);
Q_UNUSED(modType);
m_modelFolder->initModel(m_session->exerciseId(), m_mainFolders);
m_ui->tvFolder->expandAll();
m_ui->tvFolder->setExpanded(m_proxyModelFolder->index(0,0),true);
// select last selected folder
selectFolder();
}
//----------------------------------------------------------------------------
void LtsFileDialogWidget::onFileChanged(const FileManagement::FileContent &data, DataModification modType)
{
bool condition = showFile(data, m_xmlType);
int row = 0;
QModelIndex selIndex = m_ui->widgetFiles->currentIndex();
if (selIndex.isValid())
row = selIndex.row();
if (modType == DataModification::eRemoved)
{
m_modelFile->removeRow(row);
return;
}
if (modType == DataModification::eAdded && condition)
{
m_modelFile->insertRow(data);
return;
}
if (modType == DataModification::eModified && condition)
{
m_modelFile->setRowData(row, data);
return;
}
}
//-----------------------------------------------------------------------------------------------------------
QString LtsFileDialogWidget::dragMimeType() const
{
return (m_modelFile) ? m_modelFile->mimeTypes().value(0) : QString();
}
//-----------------------------------------------------------------------------------------------------------
void LtsFileDialogWidget::saveFileName(const QString &name)
{
m_fileName = name;
m_selectedFileContent = FileManagement::FileContent();
emit enableButtons();
}
//-----------------------------------------------------------------------------------------------------------
QModelIndex LtsFileDialogWidget::selectedIndexViewFolder()
{
QItemSelectionModel *selectionModel = m_ui->tvFolder->selectionModel();
QModelIndexList indexL = selectionModel->selectedRows(0);
if(indexL.size() == 0)
return {};
return m_proxyModelFolder->mapToSource(indexL.at(0));
}
//-----------------------------------------------------------------------------------------------------------
void LtsFileDialogWidget::enaDisa()
{
QModelIndex idxFolder = selectedIndexViewFolder();
if (idxFolder.isValid())
{
QString folderName = m_modelFolder->getFolderName(m_modelFolder->getFolder(idxFolder));
m_ui->lblSelectedFolder->setText(folderName);
m_selectedFolderId = m_modelFolder->getFolder(idxFolder).id();
}
else
{
m_ui->lblSelectedFolder->setText(tr("None"));
m_selectedFolderId = 0;
}
// files
QModelIndex idxFile = m_ui->widgetFiles->currentIndex();
if (idxFile.isValid())
{
m_selectedFileContent = m_modelFile->getRowData(m_ui->widgetFiles->currentIndex().row());
m_fileName = QString::fromStdString(m_selectedFileContent.name());
m_ui->leFile->setText(m_fileName);
}
else
{
m_selectedFileContent = FileManagement::FileContent();
if (m_dialogMode != FileDialogMode::modeSaveFile)
{
m_fileName = QString();
m_ui->leFile->setText(m_fileName);
}
}
emit enableButtons();
}
//--------------------------------------------------------------------------
bool LtsFileDialogWidget::showFile(const FileManagement::FileContent &fc, const QString &xmlType)
{
if (fc.isDeleted())
return false;
if (fc.folderId() != m_selectedFolderId)
return false;
if (!m_fileTypes.isEmpty() && !m_fileTypes.contains(fc.fileType()))
return false;
if (fc.fileStatus() != FileManagement::FileStatus::Valid)
return false;
// get folder selected
const QModelIndex selIndex = selectedIndexViewFolder();
const NGLTreeItem *item = m_modelFolder->privateData(selIndex);
const FileManagement::Folder fld = item->data().value<FileManagement::Folder>();
const auto &fldPath = fld.path();
// filter in USER DOCUMENTS folder and subfolders
if (LtsUtils::isInVector(fldPath, FileManagement::MainFolder::UserDocuments))
{
const int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
// filter on User Category and OperatorId
if (fc.fileCategory() == FileManagement::FileCategory::User &&
fc.operatorId() != operatorId)
return false;
}
// filter in EXERCISE DOCUMENTS folder and subfolders
if (LtsUtils::isInVector(fldPath, FileManagement::MainFolder::ExerciseDocuments))
{
// filter on Category = Exercise
if (fc.fileCategory() != FileManagement::FileCategory::Exercise)
return false;
if (m_session->exerciseId() > 0)
{
// filter on exact exerciseId
if (fc.exerciseId() != m_session->exerciseId())
return false;
}
}
// filter on XmlType
if (fc.fileType() == FileManagement::FileType::Xml && !xmlType.isEmpty() && fc.properties().size() > 0)
{
const QString &prop = QString::fromStdString(fc.properties());
if (!prop.contains(xmlType, Qt::CaseSensitive))
{
return false;
}
}
return true;
}
} // namespace LtsWidgets
+98
View File
@@ -0,0 +1,98 @@
/**
* @RDE_HEADER@
* LtsFileDialogWidget and LtsFileDialog - custom widgets
* $Id$
* $HeadURL$
* $Author$
*
* Created by Iuliana Ojog & Mike Wille, SLSE, 2017-09-15
*/
#pragma once
#include "lts_file_dialog.h"
#include <LtsFileDialog/ltsfiledialog_export.h>
#include <Plugins/FileManagement/flm_data_plugin_interface.h>
#include <Plugins/OperatorManagement/opm_data_plugin_interface.h>
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
#include <QWidget>
namespace LtsWidgets
{
class DialogModelFile;
class DialogModelFolder;
class DialogModelProxyFolder;
class DialogFileProxyModel;
class LTSFILEDIALOG_EXPORT LtsFileDialogWidget : public QWidget
{
friend class LtsFileDialog;
Q_OBJECT
public:
explicit LtsFileDialogWidget(QWidget *parent = nullptr);
~LtsFileDialogWidget();
bool init(LtsSession::LtsSession *session,
const std::shared_ptr<FileManagement::Interface::Dtc> &dtc,
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
const FileDialogMode &dlgMode = FileDialogMode::modeOpenFile,
const QVector<FileManagement::MainFolder> &mainFolders = {},
const QVector<FileManagement::FileType> &fileTypes = {FileManagement::FileType::Unknown},
const int &folderId = 0,
const QString &xmlType = QString());
void requestReadingSelectedFile();
QString dragMimeType() const;
signals:
void enableButtons();
void accepted();
void readSelectedFile(int fileId);
private:
void enaDisa();
void saveFileName(const QString &name);
QModelIndex selectedIndexViewFolder();
void selectFolder();
protected slots:
// folders
void onFolderSelectionChanged(const QItemSelection & /*selected*/,
const QItemSelection& /*deselected*/);
void onFolderChanged(const FileManagement::Folder &data, DataModification modType);
// files
FileManagement::FileContent onSelectFile();
void onChooseFileName();
void onFileChanged(const FileManagement::FileContent &data, DataModification modType);
bool showFile(const FileManagement::FileContent &fc, const QString &xmlType);
private:
DialogModelFolder *m_modelFolder{nullptr};
DialogModelProxyFolder *m_proxyModelFolder{nullptr};
DialogModelFile *m_modelFile{nullptr};
DialogFileProxyModel *m_proxyModelFile{nullptr};
std::shared_ptr<FileManagement::Interface::Dtc> m_dtc;
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
Ui::LtsFileDialogWidget *m_ui{nullptr};
LtsSession::LtsSession *m_session{nullptr};
int m_selectedFolderId{-1};
FileManagement::FileContent m_selectedFileContent;
QString m_fileName;
QVector<FileManagement::FileType> m_fileTypes;
QString m_xmlType;
FileDialogMode m_dialogMode;
QVector<FileManagement::MainFolder> m_mainFolders;
};
} // namespace LtsWidgets
+72
View File
@@ -0,0 +1,72 @@
/**
* @RDE_HEADER@
* Test for LtsDataView and their AbstractDisplayWidgets
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-03-14
*/
#include "lts_file_dialog.h"
#include <QApplication>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <DDS/DDSConnector/dds_connector.h>
// ------------------------------------------------------------------
int main(int argc, char **argv)
{
QApplication app(argc, argv);
// Init the logger
NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx.props", true);
NGL::INGLLogger &m_logger = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("Test");
STARTUP_LOG(m_logger);
// init dds
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
std::shared_ptr<FileManagement::Interface::Dtc> m_dtc;
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
m_ddsConnector.reset(new DDSConnector::DdsConnector(74, IDL::PartitionType::Global));
if (!m_ddsConnector->init())
return -1;
m_ddsConnector->initPublisherSubscriber();
INFO_LOG(m_logger) << "create FLM dtc";
m_dtc = FileManagement::Interface::Dtc::create(m_ddsConnector);
bool bRet = m_dtc->enableAll();
INFO_LOG(m_logger) << "create OPM dtc";
m_opmDtc = OperatorManagement::Interface::Dtc::create(m_ddsConnector);
bRet &= m_opmDtc->enableUser();
INFO_LOG(m_logger) << "create EXM dtc";
m_exmDtc = ExerciseManagement::Interface::Dtc::create(m_ddsConnector);
bRet &= m_exmDtc->enableExercise();
bRet &= m_exmDtc->enableExercisePhase();
INFO_LOG(m_logger) << "bRet = " << bRet;
// create dialog
LtsWidgets::LtsFileDialog *view = new LtsWidgets::LtsFileDialog();
// init dialog
view->init(nullptr, m_dtc, m_opmDtc, m_exmDtc, LtsWidgets::FileDialogMode::modeOpenFile, {FileManagement::MainFolder::GlobalDocuments}, {FileManagement::FileType::Jpg}, 6, QStringLiteral("Select") );
view->setMinimumWidth(800);
view->setMinimumHeight(600);
view->resize(view->sizeHint());
view->show();
int ret = app.exec();
view->deleteLater();
SHUTDOWN_LOG(m_logger);
return ret;
}
+28
View File
@@ -0,0 +1,28 @@
#
# CMakeLists.txt for File Dialog
#
# $Id$
# $HeadURL$
# $Author$
# Created by Iuliana Ojog, SLSE, 2017-07-12
#
FIND_PACKAGE(KDReports REQUIRED)
SET(ltsReportDisplay_SRCS
lts_report_display_widget.h
lts_report_display_widget.cpp
)
NGL_ADD_LIBRARY2(WS LtsReportDisplay SHARED ${ltsReportDisplay_SRCS})
NGL_TARGET_LINK_LIBRARIES(LtsReportDisplay
PRIVATE
LtsWidgets
PUBLIC
Qt5::Widgets
KDReports::KDReports
)
NGL_TARGET_INCLUDE_DIRECTORIES(LtsReportDisplay
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
+96
View File
@@ -0,0 +1,96 @@
/**
* @RDE_HEADER@
* Shows a report of combat power in form of curves
* $Id$
* $HeadURL$
* $Author$
*/
#include "lts_report_display_widget.h"
#include <QResizeEvent>
#include <QPainter>
#include <QPaintEvent>
#include <QTimer>
// Taken from KDReportsLayoutHelper.cpp START
// (WebCMS-TES-UAE-RP 2953 Falsche Positionierung im AAR)
QT_BEGIN_NAMESPACE
Q_GUI_EXPORT extern int qt_defaultDpi(); // This is what QTextDocument uses...
QT_END_NAMESPACE
// Taken from KDReportsLayoutHelper.cpp END
namespace LtsWidgets
{
LtsReportDisplayWidget::LtsReportDisplayWidget(QWidget *parent)
: QWidget(parent)
{
// setAttribute(Qt::WA_OpaquePaintEvent);
// minimale Breite, danach sollte die ScrollArea einen horizontalen Scrollbar darstellen
setMinimumWidth(400);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
}
void LtsReportDisplayWidget::setReport(KDReports::Report *report)
{
m_report = report;
update();
}
void LtsReportDisplayWidget::paintEvent(QPaintEvent *event)
{
if (!m_report)
{
QWidget::paintEvent(event);
return;
}
if (m_pixmap.size() != size())
{
QImage img(size(), QImage::Format_ARGB32);
QPainter p(&img);
p.fillRect(rect(), Qt::white);
m_report->paintPage(0, p);
p.end();
m_pixmap = QPixmap::fromImage(img);
}
QPainter p(this);
p.drawPixmap(0, 0, m_pixmap);
p.end();
}
void LtsReportDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
if (!m_report)
return;
qreal withPixel = size().width();
// qreal withMM = withPixel / physicalDpiX() * 25.4;
qreal withMM = withPixel / qt_defaultDpi() * 25.4;
m_report->setWidthForEndlessPrinter(withMM);
if (!m_bNewMinSizeSlotCalled)
{
m_bNewMinSizeSlotCalled = true;
QTimer::singleShot(10, this, &LtsReportDisplayWidget::setNewMinimumSize);
}
}
void LtsReportDisplayWidget::setNewMinimumSize()
{
m_bNewMinSizeSlotCalled = false;
if (!m_report)
return;
// die neue minimale Höhe festlegen um ggf. einen vertikalen Scrollbar anzuzeigen
QSize newSize = m_report->paperSize().toSize();
// DEBUG_LOG(m_logger) << "old min height: " << minimumHeight() << " - new min height: " << newSize.height() << END_LOG;
// Zur Erklärung: es kann passieren, dass die ScrollArea entscheidet, dass der vertikale Scrollbar jetzt nicht mehr nötig ist
// dies triggert ein resize Event und demnach eine neue Breite. Dadurch verändert sich dann natürlich auch die
// neue minimale Höhe was widerrum dazu führt, dass der Scrollbar wieder nötig ist usw.
// deshalb eine kleine hysterese, hoffentlich reicht es so
if (minimumHeight() >= newSize.height() && minimumHeight() - 20 <= newSize.height())
return;
setMinimumHeight(newSize.height());
}
} // namespace LtsWidgets
+42
View File
@@ -0,0 +1,42 @@
/**
* @RDE_HEADER@
* Shows a report of combat power in form of curves
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QWidget>
#include <QPixmap>
#include <KDReports/KDReportsReport>
#include <LtsReportDisplay/ltsreportdisplay_export.h>
namespace LtsWidgets
{
class LTSREPORTDISPLAY_EXPORT LtsReportDisplayWidget : public QWidget
{
Q_OBJECT
public:
explicit LtsReportDisplayWidget(QWidget *parent = nullptr);
~LtsReportDisplayWidget() = default;
void setReport(KDReports::Report *report);
public slots:
void setNewMinimumSize();
protected:
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private:
bool m_bNewMinSizeSlotCalled{false};
QPixmap m_pixmap;
KDReports::Report *m_report{nullptr};
};
}
+15
View File
@@ -0,0 +1,15 @@
#
# @RDE_HEADER@
# Small hack to provide the missing smybol to 'typeinfo for std::bad_array_new_length@Qt_5'
# $Id$
# $HeadURL$
# $Author$
#
IF(UNIX)
NGL_ADD_LIBRARY(WS SV AAR ArcGISQt5Hack SHARED arcgisqt5hack.cpp arcgisqt5hack.version) # SV,AAR for CES - expand polygon
NGL_TARGET_LINK_LIBRARIES(ArcGISQt5Hack PRIVATE "-Wl,--version-script,${CMAKE_CURRENT_SOURCE_DIR}/arcgisqt5hack.version")
ELSE()
NGL_ADD_LIBRARY(WS SV AAR ArcGISQt5Hack STATIC arcgisqt5hack.cpp) # SV,AAR for CES - expand polygon
ENDIF()
NGL_INSTALL_TARGET(ArcGISQt5Hack)
+21
View File
@@ -0,0 +1,21 @@
/**
* @RDE_HEADER@
* Small hack to provide the missing smybol to 'typeinfo for std::bad_array_new_length@Qt_5'
* $Id$
* $HeadURL$
* $Author$
*/
#ifdef WIN32
__declspec(dllexport) int foo42(int) { return 42;} // just a dummy to get windows build running
#else
#include <new>
extern "C++"
{
__attribute__((visibility("default"))) void operator delete(void* ptr, std::size_t) noexcept
{
::operator delete(ptr);
}
}
#endif
@@ -0,0 +1,3 @@
Qt_5 {
*;
};
+587
View File
@@ -0,0 +1,587 @@
#
# $Id$
# $HeadURL$
# $Author$
#
FIND_PACKAGE(ArcGIS REQUIRED)
ADD_SUBDIRECTORY(ArcGISQt5Hack)
# During development: (instead top CMakeLists.txt"
IF(NOT MSVC)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
ENDIF()
OPTION(BUILD_SITMAP_UNIT_TESTS "Build situation map unit tests" ON)
SET(GraphicalObjects_SRCS
GraphicalObjects/abstract_graphical_object.cpp
GraphicalObjects/ellipse_parameters.cpp
GraphicalObjects/graphical_object_attributes.h
GraphicalObjects/graphical_object_attributes.cpp
GraphicalObjects/graphical_object_ellipse.cpp
GraphicalObjects/graphical_object_multi_path.cpp
GraphicalObjects/graphical_object_path.cpp
GraphicalObjects/graphical_object_picture_marker.cpp
GraphicalObjects/graphical_object_range.cpp
GraphicalObjects/graphical_object_text.cpp
GraphicalObjects/tactical_appearance.cpp
GraphicalObjects/graphical_object_cube.cpp
GraphicalObjects/graphical_object_scene_marker.cpp
GraphicalObjects/graphical_object_model_scene_marker.cpp
GraphicalObjects/graphical_object_renderer_attributes.cpp
)
SET(GraphicalObjects_HDRS
GraphicalObjects/abstract_graphical_object.h
GraphicalObjects/ellipse_parameters.h
GraphicalObjects/graphical_object_ellipse.h
GraphicalObjects/graphical_object_multi_path.h
GraphicalObjects/graphical_object_picture_marker.h
GraphicalObjects/graphical_object_path.h
GraphicalObjects/graphical_object_range.h
GraphicalObjects/graphical_object_text.h
GraphicalObjects/stub_graphical_object.h
GraphicalObjects/tactical_appearance.h
GraphicalObjects/graphical_object_cube.h
GraphicalObjects/graphical_object_scene_marker.h
GraphicalObjects/graphical_object_model_scene_marker.h
GraphicalObjects/graphical_object_renderer_attributes.cpp
)
QT5_ADD_RESOURCES(GraphicalObjects_SRCS Resources/situation_map.qrc)
SET(Map_SRCS
Map/bounding_box.cpp
Map/fill_style.cpp
Map/line_style.cpp
Map/map.cpp
Map/map_notifier.cpp
Map/map_settings.cpp
Map/map_initializer.cpp
Map/object_container.cpp
Map/object_factory.cpp
Map/operator_map_settings.cpp
# Map/point3D.cpp
Map/party_id_to_color_functor.cpp
# Map/scene_marker_data.cpp
Map/situation_map_utils.cpp
Map/terrain_profile_parameter.cpp
Map/text_style.cpp
Map/geometry_model_renderer.cpp
Map/viewshed_parameter.cpp
)
SET(Map_HDRS
Map/situation_map_ahtc.ini
Map/situation_map_defaults.ini
Map/situation_map_guez.ini
Map/situation_map_qatar.ini
Map/situation_map_guez_tablet.ini
Map/situation_map_ahtc_tablet.ini
Map/abstract_effect_simulation.h
Map/abstract_map_object.h
Map/bounding_box.h
Map/camera.h
Map/camera.cpp
Map/coord_translation_functor.h
# Map/drop_event_manager.h
Map/fill_style.h
Map/generic_object_factory.h
Map/grid.h
Map/map.h
Map/map_notifier.h
Map/map_settings.h
Map/map_initializer.h
Map/measurement.h
Map/layer_factory.h
Map/layer_parameter.h
Map/layer_parameter.cpp
Map/location_display.h
Map/line_style.h
Map/object_container.h
Map/object_factory.h
Map/object_indicator.h
Map/operator_map_settings.h
Map/overview_map_handler.h
Map/party_id_to_color_functor.h
Map/pixel_based_textbox_handler.h
Map/point3D.h
# Map/scene_marker_data.cpp
Map/sidc_symbol.h
Map/sight_fan.h
Map/situation_map_utils.h
Map/situation_map_types.h
Map/terrain_profile_parameter.h
Map/terrain_profile.h
Map/text_style.h
Map/viewpoint2D.h
Map/viewpoint2D.cpp
Map/viewshed_parameter.h
Map/viewshed.h
Map/camera.h
Map/camera.cpp
Map/overlay_handler.h
Map/geometry_model_renderer.h
)
SET(MapImpl_SRCS
MapImpl/abstract_effect_simulation_impl.cpp
MapImpl/abstract_effect_simulation_impl.h
MapImpl/abstract_map_object_impl.cpp
MapImpl/abstract_map_object_impl.h
MapImpl/coordinate_translation.cpp
MapImpl/coordinate_translation_thread.cpp
MapImpl/grid_impl.cpp
MapImpl/jump_point_model.cpp
MapImpl/jump_point_custom_view.cpp
MapImpl/jump_point_widget.cpp
MapImpl/logical_layer.cpp
MapImpl/layer_factory_impl.cpp
MapImpl/layer_control_widget.cpp
MapImpl/screen_location_elevation_helper_base.cpp
MapImpl/location_display_impl.cpp
MapImpl/location_to_elevation_helper.cpp
MapImpl/location_to_elevation_bulk.cpp
MapImpl/map_impl.cpp
MapImpl/map_layer.cpp
MapImpl/measurement_impl.cpp
MapImpl/object_container_impl.cpp
MapImpl/object_indicator_impl.cpp
MapImpl/overview_map_handler_impl.cpp
MapImpl/pixel_based_textbox_handler_impl.cpp
MapImpl/screen_to_location_helper.cpp
MapImpl/sidc_symbol_impl.cpp
MapImpl/sight_fan_impl.cpp
MapImpl/terrain_profile_impl.cpp
MapImpl/terrain_profile_processor.cpp
# MapImpl/tms_layer.cpp
MapImpl/viewshed_base.cpp
MapImpl/viewshed_analysis.cpp
MapImpl/viewshed_geo_processing.cpp
MapImpl/viewshed_base.cpp
MapImpl/viewshed_impl.cpp
MapImpl/jump_point_namer.cpp
MapImpl/geometry_model_renderer_esri.cpp
MapImpl/overlay_handler_impl.cpp
)
SET(MapImpl_HDRS
MapImpl/abstract_effect_simulation_impl.h
MapImpl/abstract_map_object_impl.h
MapImpl/coordinate_translation.h
MapImpl/coordinate_translation_thread.h
MapImpl/coord_translation_functor_impl.h
MapImpl/geometry_model_renderer_esri.h
MapImpl/grid_impl.cpp
MapImpl/grid_impl.h
MapImpl/jump_point_model.h
MapImpl/jump_point_custom_view.h
MapImpl/jump_point_widget.h
MapImpl/logical_layer.h
MapImpl/layer_control_widget.h
MapImpl/layer_factory_impl.h
MapImpl/screen_location_elevation_helper_base.h
MapImpl/location_display_impl.h
MapImpl/location_to_elevation_helper.h
MapImpl/location_to_elevation_bulk.h
MapImpl/map_impl.h
MapImpl/map_layer.h
MapImpl/measurement_impl.h
MapImpl/object_container_impl.h
MapImpl/object_indicator_impl.h
MapImpl/overview_map_handler_impl.h
MapImpl/overlay_handler_impl.h
MapImpl/pixel_based_textbox_handler_impl.h
MapImpl/screen_to_location_helper.h
MapImpl/sidc_symbol_impl.h
MapImpl/sight_fan_impl.h
MapImpl/terrain_profile_impl.h
MapImpl/terrain_profile_processor.h
# MapImpl/tms_layer.h
MapImpl/viewshed_base.h
MapImpl/viewshed_analysis.h
MapImpl/viewshed_geo_processing.h
MapImpl/viewshed_impl.h
MapImpl/jump_point_namer.h
)
SET(MapObj_SRCS
MapObjects/geometry.cpp
)
SET(MapObj_HDRS
MapObjects/abstract_multi_point_map_object.h
MapObjects/abstract_single_point_map_object.h
MapObjects/air_support.h
MapObjects/area_fire.h
MapObjects/biological_agent.h
MapObjects/building_outline.h
MapObjects/chemical_agent.h
MapObjects/cube.h
MapObjects/danger_area.h
MapObjects/functional_area.h
MapObjects/geo_image.h
MapObjects/geometry.h
MapObjects/hit_line.h
MapObjects/line_of_sight.h
MapObjects/map_object_attributes.h
MapObjects/map_object_indicator.h
MapObjects/mine.h
MapObjects/mine_field.h
MapObjects/nuclear_agent.h
MapObjects/participant.h
MapObjects/polygon.h
MapObjects/polyline.h
MapObjects/single_fire.h
# MapObjects/single_fire_central.h
MapObjects/sound_area.h
MapObjects/text.h
MapObjects/virtual_mine.h
#situation_map_objects_export.h
)
SET (LayerAggregation_SRCS
LayerAggregation/layer_aggregation_widget.cpp
LayerAggregation/participant_aggregation_dialog.cpp
)
SET (LayerAggregation_HDRS
LayerAggregation/layer_aggregation_widget.h
LayerAggregation/participant_aggregation_dialog.h
)
SET(Rubberbands_SRCS
Rubberbands/abstract_event_dispatcher.cpp
Rubberbands/drawable_ellipse.cpp
Rubberbands/drawable_line.cpp
Rubberbands/drawable_painter_path.cpp
Rubberbands/drawable_smooth_path.cpp
Rubberbands/event_delegater.cpp
Rubberbands/event_dispatcher.cpp
Rubberbands/event_mouse_navigator.cpp
Rubberbands/gestures.cpp
Rubberbands/rubberband_base.cpp
Rubberbands/rubberband.cpp
Rubberbands/rubberband_3d.cpp
Rubberbands/rubberband_arrow.cpp
Rubberbands/rubberband_corridor.cpp
Rubberbands/rubberband_drawable.cpp
Rubberbands/rubberband_factory.cpp
Rubberbands/rubberband_frame_handle.cpp
Rubberbands/rubberband_free_hand.cpp
Rubberbands/rubberband_ellipse.cpp
Rubberbands/rubberband_ellipse_handle.cpp
Rubberbands/rubberband_handle.cpp
Rubberbands/rubberband_handle_proxy.cpp
Rubberbands/rubberband_internal.cpp
Rubberbands/rubberband_line_handle.cpp
Rubberbands/rubberband_multi_point_feature.cpp
Rubberbands/rubberband_multi_ellipse_feature.cpp
Rubberbands/rubberband_multi_point_feature_3d.cpp
Rubberbands/rubberband_point_handle.cpp
Rubberbands/rubberband_point_cluster.cpp
Rubberbands/rubberband_point_feature.cpp
Rubberbands/rubberband_point_feature_3d.cpp
Rubberbands/rubberband_polyline_width.cpp
Rubberbands/rubberband_rectangle.cpp
Rubberbands/rubberband_smooth_line.cpp
Rubberbands/rubberband_state_select.cpp
Rubberbands/rubberband_transform.cpp
Rubberbands/rubberband_transform_move.cpp
Rubberbands/rubberband_transform_rotate.cpp
Rubberbands/rubberband_transform_scale.cpp
Rubberbands/transient_tactical_symbol.cpp
)
SET(Rubberbands_HDRS
Rubberbands/abstract_event_dispatcher.h
Rubberbands/drawable_ellipse.h
Rubberbands/drawable_line.h
Rubberbands/drawable_painter_path.h
Rubberbands/drawable_smooth_path.h
Rubberbands/event_delegater.h
Rubberbands/event_dispatcher.h
Rubberbands/event_mouse_navigator.h
Rubberbands/gestures.h
Rubberbands/rubberband_free_hand.h
Rubberbands/rubberband_base.h
Rubberbands/rubberband_base_internal.h
Rubberbands/rubberband.h
Rubberbands/rubberband_3d.h
Rubberbands/rubberband_arrow.h
Rubberbands/rubberband_corridor.h
Rubberbands/rubberband_drawable.h
Rubberbands/rubberband_ellipse.h
Rubberbands/rubberband_ellipse_handle.h
Rubberbands/rubberband_factory.h
Rubberbands/rubberband_frame_handle.h
Rubberbands/rubberband_handle.h
Rubberbands/rubberband_handle_proxy.h
Rubberbands/rubberband_internal.h
Rubberbands/rubberband_line_handle.h
Rubberbands/rubberband_multi_point_feature.h
Rubberbands/rubberband_multi_ellipse_feature.h
Rubberbands/rubberband_multi_point_feature_3d.h
Rubberbands/rubberband_point_cluster.h
Rubberbands/rubberband_point_feature.h
Rubberbands/rubberband_point_feature_3d.h
Rubberbands/rubberband_point_handle.h
Rubberbands/rubberband_polyline_width.h
Rubberbands/rubberband_rectangle.h
Rubberbands/rubberband_smooth_line.h
Rubberbands/rubberband_state_select.h
Rubberbands/rubberband_transform.h
Rubberbands/rubberband_transform_move.h
Rubberbands/rubberband_transform_rotate.h
Rubberbands/rubberband_transform_scale.h
Rubberbands/transient_tactical_symbol.h
)
SET(Utils_SRCS
situation_map_export.h
Utils/movement_track.cpp
Utils/movement_track_manager.cpp
Utils/terrain_profile_dialog.cpp
)
SET(Utils_HDRS
Utils/movement_track.h
Utils/movement_track_manager.h
Utils/terrain_profile_dialog.h
)
SET(MathUtils_SRCS
MathUtils/clipper.cpp
MathUtils/curve.cpp
MathUtils/geometry_engine.cpp
MathUtils/matrix2d.cpp
MathUtils/path_rasterer.cpp
MathUtils/simple_helper.cpp
)
SET(MathUtils_HDRS
MathUtils/clipper.hpp
MathUtils/curve.h
MathUtils/geometry_engine.h
MathUtils/matrix2d.h
MathUtils/math_const.h
MathUtils/path_rasterer.h
MathUtils/simple_helper.h
)
NGL_WRAP_UI(Utils_HDRS
MapImpl/jump_point_custom_view.ui
Utils/terrain_profile_dialog.ui
)
NGL_WRAP_UI(MapImpl_SRCS
MapImpl/jump_point_namer.ui
)
SOURCE_GROUP(GraphicalObjects FILES ${GraphicalObjects_SRCS} ${GraphicalObjects_HDRS})
SOURCE_GROUP(Map FILES ${Map_SRCS} ${Map_HDRS} ${MapImpl_SRCS} ${MapImpl_HDRS})
SOURCE_GROUP(MapObjects FILES ${MapObj_HDRS})
SOURCE_GROUP(LayerAggregation FILES ${LayerAggregation_SRCS} ${LayerAggregation_HDRS})
SOURCE_GROUP(Rubberband FILES ${Rubberbands_SRCS} ${Rubberbands_HDRS})
SOURCE_GROUP(Utils FILES ${Utils_SRCS} ${Utils_HDRS})
SOURCE_GROUP(MathUtils FILES ${MathUtils_SRCS} ${MathUtils_HDRS})
SOURCE_GROUP(SideBar FILES ${SideBar_SRCS} ${SideBar_HDRS})
NGL_ADD_LIBRARY(WS situationMap SHARED
# ${FunctionDialog_SRCS}
${Map_SRCS} ${Map_HDRS} ${MapImpl_SRCS}
${MapObj_SRCS} ${MapObj_HDRS}
${GraphicalObjects_SRCS} ${GraphicalObjects_HDRS}
${LayerAggregation_SRCS} ${LayerAggregation_HDRS}
${Rubberbands_SRCS}
${Utils_SRCS} ${Utils_HDRS}
${MathUtils_SRCS} ${MathUtils_HDRS}
)
NGL_TARGET_INCLUDE_DIRECTORIES(situationMap
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/..
)
NGL_TARGET_LINK_LIBRARIES(situationMap
PRIVATE
NGLLogger
ArcGIS::ArcGIS
Qt5::Concurrent
Qt5::Network
Qt5::PrintSupport
LtsCoordTrans
ArcGISQt5Hack
PUBLIC
Qt5::Core
Qt5::Widgets
LtsUtilsCoreHeaderOnly # QPoint3D
LtsWidgets
LtsDataView
situationMapCommon
situationMapElevationMap
situationMapSideBar
advancedSymbology
situationMapGeometryModel
ngltools
)
# Copy on LIBchanges:
IF(TARGET situationMap)
SET(SYMBOLE_CSV symbole2.csv)
ADD_CUSTOM_COMMAND(TARGET situationMap POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/FunctionDialog/${SYMBOLE_CSV} $<TARGET_FILE_DIR:situationMap>/${SYMBOLE_CSV}
)
# copy ini to build-dir/share/Lts/situation_map/:
SET(INI_DEST_DIR ${CMAKE_BINARY_DIR}/share/Lts/situation_map)
SET(SITUATIONMAPSETTINGS_INI situation_map_defaults.ini)
SET(SITUATIONMAPSETTINGS_INI_PATH Map/${SITUATIONMAPSETTINGS_INI})
ADD_CUSTOM_COMMAND(TARGET situationMap POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${SITUATIONMAPSETTINGS_INI_PATH} ${INI_DEST_DIR}/${SITUATIONMAPSETTINGS_INI}
)
SET(SITUATIONMAPSETTINGS_INI situation_map_defaults.ini)
SET(SITUATIONMAPSETTINGS_INI_PATH Map/${SITUATIONMAPSETTINGS_INI})
#check if we need to change it
IF(BUILD_RPM AND DEFINED _pname)
IF(UNIX AND "${_pname}" STREQUAL "guez")
MESSAGE("Install situationmap ini for GUEZ")
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_guez.ini)
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_guez_tablet.ini)
ElseIF(UNIX AND "${_pname}" STREQUAL "ahtc")
MESSAGE("Install situationmap ini for AHTC")
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_ahtc.ini)
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_ahtc_tablet.ini)
ElseIF(UNIX AND "${_pname}" STREQUAL "l400p2")
MESSAGE("Install situationmap ini for L400P2")
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_land400.ini)
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_l400p2_tablet.ini)
ElseIF(UNIX AND "${_pname}" STREQUAL "qatar")
MESSAGE("Install situationmap ini for Qatar")
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_qatar.ini)
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_qatar_tablet.ini)
ElseIF(UNIX AND "${_pname}" STREQUAL "qatarmout")
MESSAGE("Install situationmap ini for Qatar Mout")
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_qatarmout.ini)
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_qatar_tablet.ini)
ElseIF(UNIX AND "${_pname}" STREQUAL "commaster")
MESSAGE("Install situationmap ini for ComMaster/Luxemburg")
SET(SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_luxemburg.ini)
SET(TABLET_SITUATIONMAPSETTINGS_INI_PATH Map/situation_map_luxemburg_tablet.ini)
ENDIF()
ENDIF()
#now that we set the situation map ini if neccecsary we install it depending of the tablet build or not
IF(TABLET_MODE)
NGL_INSTALL(WS FILES ${TABLET_SITUATIONMAPSETTINGS_INI_PATH} DESTINATION "./share/Lts/situation_map" RENAME ${SITUATIONMAPSETTINGS_INI})
ELSE()
NGL_INSTALL(WS FILES ${SITUATIONMAPSETTINGS_INI_PATH} DESTINATION "./share/Lts/situation_map" RENAME ${SITUATIONMAPSETTINGS_INI})
ENDIF()
ENDIF()
IF(BUILD_TESTING AND BUILD_SITMAP_UNIT_TESTS)
NGL_ADD_LIBRARY(WS NO_TRANSLATION situationMap_static STATIC
${FunctionDialog_SRCS}
${Map_SRCS} ${Map_HDRS} ${MapImpl_SRCS}
${MapObj_SRCS} ${MapObj_HDRS}
${GraphicalObjects_SRCS}
${Rubberbands_SRCS}
${Utils_SRCS} ${Utils_HDRS}
${MathUtils_SRCS} ${MathUtils_HDRS}
)
NGL_TARGET_COMPILE_DEFINITIONS(situationMap_static PUBLIC "SITUATIONMAP_EXPORT=")
NGL_TARGET_INCLUDE_DIRECTORIES(situationMap_static
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}
)
NGL_TARGET_LINK_LIBRARIES(situationMap_static
PRIVATE
NGLLogger
Qt5::Concurrent
Qt5::Network
Qt5::PrintSupport
LtsCoordTrans
ArcGISQt5Hack
PUBLIC
Qt5::Core
Qt5::Widgets
LtsUtilsCoreHeaderOnly # QPoint3D
LtsWidgets
LtsDataView
situationMapCommon
situationMapElevationMap
situationMapSideBar
advancedSymbology_static
situationMapGeometryModel
ngltools
)
ENDIF()
NGL_INSTALL_TARGET(situationMap)
# Choose logical order instead of alphabetical.
# UnitTest should be performed BEFORE ModuleTest
ADD_SUBDIRECTORY(Common)
ADD_SUBDIRECTORY(ElevationMap)
ADD_SUBDIRECTORY(Symbology)
ADD_SUBDIRECTORY(SymbologyGui)
ADD_SUBDIRECTORY(SymbologyXML)
ADD_SUBDIRECTORY(MapObjectsImpl)
#ADD_SUBDIRECTORY(LocalSrv)
ADD_SUBDIRECTORY(SideBar)
ADD_SUBDIRECTORY(FunctionDialog)
ADD_SUBDIRECTORY(GeometryModel)
ADD_SUBDIRECTORY(Portal)
ADD_SUBDIRECTORY(Tests)
IF(BUILD_SITMAP_UNIT_TESTS)
ADD_SUBDIRECTORY(EvalApps)
ADD_SUBDIRECTORY(UnitTests)
ADD_SUBDIRECTORY(UnitTestsGeoModel)
ADD_SUBDIRECTORY(ModuleTests)
ENDIF()
+44
View File
@@ -0,0 +1,44 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# LIBRARY
SET(Common_SRCS
id_handler.cpp
referenced.cpp
resource_path.cpp
situation_map_logging.cpp
)
SET (Common_HDRS
exception.h
id_handler.h
ref_pointer.h
referenced.h
resource_path.h
situation_map_common_export.h
situation_map_logging.h
simple_value.h
)
SOURCE_GROUP(Common FILES ${Common_SRCS} ${Common_HDRS})
NGL_ADD_LIBRARY(WS AAR HLA SV situationMapCommon SHARED ${Common_SRCS} ${Common_HDRS})
NGL_TARGET_LINK_LIBRARIES(situationMapCommon
PRIVATE
ngltools
PUBLIC
NGLLogger
Qt5::Core
)
NGL_TARGET_INCLUDE_DIRECTORIES(situationMapCommon
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/..
)
NGL_INSTALL_TARGET(situationMapCommon)
+93
View File
@@ -0,0 +1,93 @@
/**
**
** @RDE_HEADER@
** Implementation of Splines
** $Id$
** $HeadURL$
** $Author$
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Joerg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 19.06.2012, JT : Urversion for use in VIntel project
** 12.08.2015, JT : adapted to SituationMap
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <QtCore/QString>
namespace SituationMap
{
/**
\class Exception exception.h
\brief Basisklasse for Exception-Handling
The class Exception defines a very simple exception handler, that will be able to return
a string message when an exception is thrown
*/
class Exception
{
public:
Exception()
: _message(QLatin1String("Error"))
{}
Exception(const Exception &) = default;
explicit Exception(const QString &msg)
: _message(msg)
{}
// explicit is not used here because
// throw SituationMap::Exception(__FILE__, __LINE__, "Message" );
// will become more complicated
Exception(const char *Source
, unsigned int lineNo
, const char *msg)
: Exception(QLatin1String(Source), lineNo, QLatin1String(msg))
{}
Exception(const char *Source
, unsigned int lineNo
, const QString &msg)
: Exception(QLatin1String(Source), lineNo, msg)
{}
Exception(const QString &Source
, unsigned int lineNo
, const QString &msg)
: _message(QStringLiteral("\"%1\" in %2 at %3").arg(msg, Source).arg(lineNo))
{}
~Exception() = default;
Exception &operator = (const Exception &e) = default;
QString getMessage() const { return _message; } //!< returns a specific error message as QString
protected:
QString _message;
};
} // namespace SituationMap
+345
View File
@@ -0,0 +1,345 @@
/**
**
** @RDE_HEADER@
** Simple Id Handler
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Linux, Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** ??.??.1994, JT : First edition for use with Tcl/Tk in START Feature Editor fe
** 16.08.2004, JT : Refactoring for use in Geo-Map Library GeISiR
** 11.05.2015, JT : Refactoring for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "id_handler.h"
#include <typeinfo>
#include "referenced.h"
namespace SituationMap
{
const IdHandler::UniqueId IdHandler::BadId = static_cast<IdHandler::UniqueId>(-1);
bool IdHandler::isIdValid(const UniqueId &id) { return id != BadId; }
IdHandler::IdHandler(unsigned int maxItems, unsigned int blockS)
: _blockSize(blockS)
, _maxIds(maxItems)
, _freeIds(maxItems)
, _firstFree(BadId)
, _lastAlloc(BadId)
, _notify(getLogger("IdHandler"))
, _idVector()
{
} // IdHandler::IdHandler
IdHandler::~IdHandler()
{
if (!_idVector.isEmpty())
{
if (_lastAlloc != BadId)
{
for (UniqueId i = 0; i <= _lastAlloc; ++i)
_idVector[i] = nullptr;
}
_maxIds = 0;
_freeIds = 0;
_firstFree = BadId;
_lastAlloc = BadId;
}
} // IdHandler::~IdHandler
bool IdHandler::initMemHandler()
{
if (_idVector.empty())
{
_idVector.resize(_maxIds);
_freeIds = _maxIds;
_firstFree = 0;
_lastAlloc = BadId;
return false;
}
return true;
} // IdHandler::initMemHandler
void IdHandler::lookForNextFreeId()
{
++_firstFree;
while (_firstFree < _lastAlloc)
{
if (!_idVector[_firstFree]) break;
++_firstFree;
}
if (_firstFree >= _lastAlloc) _firstFree = _maxIds;
} //IdHandler::lookForNextFreeId
bool IdHandler::valid() const
{
return ((static_cast<quint32>(_idVector.size()) == _maxIds) && (_firstFree != BadId));
} // IdHandler::valid
unsigned int IdHandler::countReservedIds() const { return _maxIds; }
unsigned int IdHandler::countUsedIds() const { return _maxIds - _freeIds; }
unsigned int IdHandler::countFreeIds() const { return _freeIds; }
bool IdHandler::resize(quint32 maxItems)
{
if (initMemHandler())
{
if (maxItems > static_cast<quint32>(_idVector.size()))
{
_freeIds += maxItems - _maxIds;
_maxIds = maxItems;
_idVector.resize(_maxIds);
}
}
return (static_cast<quint32>(_idVector.size()) == _maxIds);
} // IdHandler::resize
IdHandler::UniqueId IdHandler::createId(AccessableId *idPtr)
{
initMemHandler();
UniqueId id((_lastAlloc == BadId) ? 0 : _lastAlloc + 1);
if (id < _maxIds)
{
_idVector[id] = idPtr;
_lastAlloc = id;
if (_firstFree == id) ++_firstFree;
}
else
{
if (_firstFree >= _maxIds)
{
resize(_maxIds + _blockSize);
if (id < _maxIds)
{
_idVector[id] = idPtr;
_lastAlloc = id;
if (_firstFree == id)
++_firstFree;
}
else
{
ERROR_LOG(_notify)
<< LOGFUNCTION
<< QStringLiteral("Id table overflow, object <%1> of type <%2>, reserved Ids %3")
.arg(reinterpret_cast<qulonglong>(idPtr), 0, 16)
.arg(QLatin1String(typeid(idPtr).name()))
.arg(_maxIds);
return BadId;
}
}
else
{
id = _firstFree;
_idVector[id] = idPtr;
lookForNextFreeId();
}
}
_freeIds--;
return (id);
} // IdHandler::createId
bool IdHandler::reserveId(UniqueId id, AccessableId *idPtr)
{
initMemHandler();
if (!valid())
{
ERROR_LOG(_notify)
<< LOGFUNCTION
<< QStringLiteral("IdHandler is not initialzed, object <%1> of type <%2> ")
.arg(reinterpret_cast<qulonglong>(idPtr), 0, 16)
.arg(QLatin1String(typeid(idPtr).name()));
return false;
}
if (id == BadId)
{
ERROR_LOG(_notify)
<< LOGFUNCTION
<< " Requested id is bad id <" << id << ">";
return false;
}
if (id >= _maxIds)
{
if (!resize((((id + 1) / _blockSize) + 1) * _blockSize))
{
ERROR_LOG(_notify)
<< LOGFUNCTION
<< QStringLiteral("Requested id is to large, id <%1> object <%2> of type <%3>.")
.arg(id)
.arg(reinterpret_cast<qulonglong>(idPtr), 0, 16)
.arg(QLatin1String(typeid(idPtr).name()));
return false;
}
}
if (_idVector[id])
{
ERROR_LOG(_notify)
<< LOGFUNCTION
<< QStringLiteral("Requested id is already in use, object <%1> of type <%2>.")
.arg(reinterpret_cast<qulonglong>(idPtr), 0, 16)
.arg(QLatin1String(typeid(idPtr).name()));
return false;
}
_idVector[id] = idPtr;
if ((_lastAlloc == BadId) || (id > _lastAlloc)) _lastAlloc = id;
if (id == _firstFree)
{
++_firstFree;
lookForNextFreeId();
}
_freeIds--;
return true;
} // IdHandler::reserveId
bool IdHandler::freeId(UniqueId id)
{
if (valid() && (_lastAlloc != BadId) && (id != BadId))
{
if (id <= _lastAlloc)
{
if (_idVector[id])
{
_idVector[id] = nullptr;
if (id < _firstFree) _firstFree = id;
if (id == _lastAlloc)
{
/* ---------------------------------------------------------
* Last allocated id is now free. Search new lastAlloc ...
* ---------------------------------------------------------- */
if (_lastAlloc > 0)
{
--_lastAlloc;
while (!_idVector[_lastAlloc])
{
if (_lastAlloc < 1)
{
_lastAlloc = BadId;
break;
}
else --_lastAlloc;
} // while
}
else _lastAlloc = BadId;
}
_freeIds++;
return true;
}
}
else
{
ERROR_LOG(_notify)
<< LOGFUNCTION
<< "Id is not in use, id <" << id << ">";
}
}
else
{
if (id != BadId)
{
ERROR_LOG(_notify)
<< LOGFUNCTION
<< "IdHandler is not initialzed.";
}
else
{
ERROR_LOG(_notify)
<< LOGFUNCTION
<< "Bad id, id <" << id << ">";
}
}
return false;
} // IdHandler::freeId
IdHandler::AccessableId *IdHandler::accessId(UniqueId id) const
{
if (valid())
{
if ((id != BadId) && (id <= _lastAlloc))
return _idVector[id].get();
else
{
ERROR_LOG(_notify)
<< LOGFUNCTION
<< "Bad id or id is not in use, id <" << id << ">";
#ifdef UseDebugBreaks
#ifdef WIN32
#ifdef _DEBUG
__asm int 3
#endif
#endif
#endif
}
}
else
{
ERROR_LOG(_notify)
<< LOGFUNCTION
<< "IdHandler is not initialzed";
}
return nullptr;
} // IdHandler::accessId
bool IdHandler::isIdInUse(UniqueId id) const
{
if (valid())
{
if ((id != BadId) && (id <= _lastAlloc))
return (_idVector[id].get() != nullptr);
}
return false;
} // IdHandler::isIdInUse
} // SituationMap
+120
View File
@@ -0,0 +1,120 @@
/**
**
** @RDE_HEADER@
** Simple Id Handler
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Linux, Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** ??.??.1994, JT : First edition for use with Tcl/Tk in START Feature Editor fe
** 16.08.2004, JT : Refactoring for use in Geo-Map Library GeISiR
** 11.05.2015, JT : Refactoring for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
//#include <Map/situation_map_types.h>
#include "referenced.h"
#include "ref_pointer.h"
#include "situation_map_logging.h"
#include "situation_map_common_export.h"
#include <QVector>
namespace SituationMap
{
/**
@class IdHandler id_handler.h
@brief Simple IdHandler to map id's to data pointers
IdHandler is a class to manage integer ids and map them to data pointers. The IdHandler stores
the data pointer in a vector container. The index of the data pointer in this vector is used as
id value. If the vector gets out of size new vector elements will be added automaticaly. This
will be done blockwises. The initial size of the vector and the block size can be set as
parameter of IdHandler ctor. The default values are 10000 for the initial vector size and 1000
for the block size.
*/
class SITUATIONMAPCOMMON_EXPORT IdHandler
{
public:
using AccessableId = Referenced;
using UniqueId = quint32; // see UniqueMapId @ situation_map_types.h
static const UniqueId BadId;
static bool isIdValid(const UniqueId &id); //!< Checks if the \c id is not a BadId
IdHandler(const IdHandler &) = delete;
IdHandler &operator = (const IdHandler &) = delete;
/**
@brief Construction of IdHandler
Initialize IdHandler instances. The vector container to store data pointers is
reserved with \c maxItems. If the vector gets out of size new vector elements
will be added automaticaly
@param maxItems Initial size of the vector container to store the data pointer.
@param blockS Block size is used when the vector container will be extended.
*/
IdHandler(unsigned int maxItems = 10000, unsigned int blockS = 1000);
/**
@brief Destruction of IdHandler
*/
virtual ~IdHandler();
bool valid() const; //!< Checks if IdHandler is valid
quint32 countReservedIds() const; //!< Returns count of reserved ids.
quint32 countUsedIds() const; //!< Returns count of used ids.
quint32 countFreeIds() const; //!< Returnes count of free ids
bool resize(quint32 maxItems); //!< Resize idMem to store now maxItems ids. Returns true on success.
UniqueId createId(AccessableId *); //!< Create new \c id and returns this new id.
bool reserveId(UniqueId id, AccessableId *); //!< Reserve \c id if the id is unused. Returns true if \c id is not already in use and reservation of \c id is successful elsewise false.
bool freeId(UniqueId id); //!< Frees \c id. Returns true on success elsewise false.
AccessableId *accessId(UniqueId id) const; //!< Returns pointer to object for \c id. Returns pointer on success elsewise \c nullptr.
bool isIdInUse(UniqueId id) const; //!< Checks if a id is already in use.
protected:
quint32 _blockSize;
quint32 _maxIds;
quint32 _freeIds;
UniqueId _firstFree;
UniqueId _lastAlloc;
LOGGER_T _notify;
mutable QVector<RefPointer<AccessableId>> _idVector;
private:
bool initMemHandler();
void lookForNextFreeId();
}; /* IdHandler */
} /* SituationMap */
+226
View File
@@ -0,0 +1,226 @@
/**
**
** @RDE_HEADER@
** Base class for reference counted objects
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Umgebung: Intel-PC
** Software-Umgebung: Linux, Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Pgrm-Sprache ....: C++ 11
**
** HIER/SACHN ......: P: -- ---- - --- QE
**
** Version .........: $Revision$
** -----------------------------------------------------------------------------------------------
**
** Autor ...........: Nikolaus Hanekamp, SEDG, Tel. 2906
**
** -----------------------------------------------------------------------------------------------
**
** Notizen .........:
**
** 18.08.2004, NH : Urversion
** 13.05.2015, JT : Refactoring for use with Qt5, ArcGIS 10.2.5
** adding methodes according to std::share_ptr like reset
**
** -----------------------------------------------------------------------------------------------
**
** Copyright (C) 2004 Rheinmetall Defence Electronics GmbH, D-28309 BREMEN
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "referenced.h"
namespace SituationMap
{
/**
@class RefPointer ref_pointer.h
@brief Smart pointer for handling referenced counted objects
Simple class template to implement reference counted pointers or smart pointers. The RefPointer class controls the
reference counter of the object \c T the pointer points to. The class \c T have to be derived from class \c Referenced,
where the reference counter member variable is located. In case of this reference counter gets zero delete will be called
automatically.
@see Referenced
*/
template<class T> class RefPointer
{
public:
using ElementType = T;
/**
@name Construction and Destruction
@{
*/
RefPointer() : RefPointer(nullptr) {}
RefPointer(const RefPointer &rp) : RefPointer(rp._ptr) {}
explicit RefPointer(ElementType *t)
: _ptr(t)
{
static_assert(std::is_base_of<Referenced, T>::value
, "Class of template SituationMap::RefPointer have to be derived from class SituationMap::Referenced");
if (_ptr) _ptr->ref();
} /* RefPointer */
~RefPointer()
{
if (_ptr) _ptr->unref();
_ptr = nullptr;
} /* ~RefPointer */
/** @} */
/**
Checks if pointer is valid.
*/
explicit inline operator bool() const { return (_ptr != nullptr); }
/**
@name Casting
@{
*/
/**
To create reference pointer from a derived class directly this contructor template can be used.
How to use it is shown in the following example:
\code
RefPointer<AbstractMapObject> objPtr = getAbstractMapObject();
RefPointer<Participant> participantObj( objPtr );
if (participantObj != NULL)
{
...
}
\endcode
Alternatively it is posible to create \b participantObj from example above as follows:
\code
RefPointer<Participant> participantObj = RefPointer<Participant>(dynamic_cast<Participant*>(objPtr.get()));
\endcode
*/
template<class Y> explicit RefPointer(RefPointer<Y> assignPtr)
{
_ptr = dynamic_cast<T *>(assignPtr.get());
if (_ptr) _ptr->ref();
}
template<class Y> explicit RefPointer(Y *assignPtr)
{
_ptr = dynamic_cast<T *>(assignPtr);
if (_ptr) _ptr->ref();
}
/** @} */
inline RefPointer &operator = (const RefPointer &rp)
{
if (_ptr == rp._ptr) return *this;
T *tmp_ptr = _ptr;
_ptr = rp._ptr;
if (_ptr) _ptr->ref();
// unref second to prevent any deletion of any object which might
// be referenced by the other object. i.e rp is child of the
// original _ptr.
if (tmp_ptr) tmp_ptr->unref();
return *this;
}
inline RefPointer &operator = (ElementType *ptr)
{
if (_ptr == ptr) return *this;
T *tmp_ptr = _ptr;
_ptr = ptr;
if (_ptr) _ptr->ref();
// unref second to prevent any deletion of any object which might
// be referenced by the other object. i.e rp is child of the
// original _ptr.
if (tmp_ptr) tmp_ptr->unref();
return *this;
}
inline void reset() { *this = nullptr; }
inline void reset(T *ptr) { *this = ptr; }
/**
@name Comparison Operators
Compares the pointer element \c _ptr with other pointers.
@{
*/
inline bool operator == (const RefPointer &rp) const { return (_ptr == rp._ptr); }
inline bool operator != (const RefPointer &rp) const { return (_ptr != rp._ptr); }
inline bool operator < (const RefPointer &rp) const { return (_ptr < rp._ptr); }
inline bool operator > (const RefPointer &rp) const { return (_ptr > rp._ptr); }
inline bool operator == (const ElementType *ptr) const { return (_ptr == ptr); }
inline bool operator != (const ElementType *ptr) const { return (_ptr != ptr); }
inline bool operator < (const ElementType *ptr) const { return (_ptr < ptr); }
inline bool operator > (const ElementType *ptr) const { return (_ptr > ptr); }
/** @} */
/**
@name Access Operators
Get access to the pointer or the object it points to.
@{
*/
inline ElementType &operator*() { return *_ptr; }
inline const ElementType &operator*() const { return *_ptr; }
inline ElementType *operator->() { return _ptr; }
inline const ElementType *operator->() const { return _ptr; }
inline ElementType *get() { return _ptr; }
inline const ElementType *get() const { return _ptr; }
/** @} */
/**
@name Checks if the pointer is valid.
@{
*/
inline bool valid() const { return _ptr != nullptr; }
inline bool operator!() const { return _ptr == nullptr; }
/** @} */
/**
* @name Control Over Object Pointer
* Take control over the object pointed to by RefPointer, unreference but do not delete even if ref count goes to 0,
* return the pointer to the object.
* Note, do not use this unless you are 100% sure your code handles the deletion of the object correctly, and
* only use when absolutely required.
@{
*/
inline ElementType *take() { return release();}
inline ElementType *release() { T *tmp = _ptr; if (_ptr) _ptr->unref_nodelete(); _ptr = nullptr; return tmp;}
/** @} */
private:
ElementType *_ptr;
};
} // SituationMap
+76
View File
@@ -0,0 +1,76 @@
/**
**
** @RDE_HEADER@
** Base class for reference counted objects
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Umgebung: Intel-PC
** Software-Umgebung: Linux, Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Pgrm-Sprache ....: C++ 11
**
** HIER/SACHN ......: P: -- ---- - --- QE
**
** Version .........: $Revision$
** -----------------------------------------------------------------------------------------------
**
** Autor ...........: Nikolaus Hanekamp, SEDG, Tel. 2906
** Joerg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notizen .........:
**
** 18.08.2004, NH : Urversion
** 13.05.2015, JT : Refactoring for use with Qt5, ArcGIS 10.2.5
**
** -----------------------------------------------------------------------------------------------
*/
#include "referenced.h"
#include <QDebug>
#include <typeinfo>
#include <memory>
namespace SituationMap
{
std::shared_ptr<DeleteHandler> & s_deleteHandler()
{
static std::shared_ptr<DeleteHandler> deleteHandler(nullptr);
return deleteHandler;
} // std::shared_ptr<DeleteHandler> & s_deleteHandler()
void Referenced::setDeleteHandler(DeleteHandler *handler)
{
s_deleteHandler().reset(handler);
} // Referenced::setDeleteHandler
DeleteHandler *Referenced::getDeleteHandler() { return s_deleteHandler().get(); }
Referenced::~Referenced()
{
if (_refCount > 0)
{
qCritical() << "Deleting still referenced object < " << QString::number((qint64)this, 0, 16) << ">"
<< "of type <" << typeid(this).name() << ">"
<< "refCnt: <" << _refCount;
}
} // Referenced::~Referenced
} // end of namespace SituationMap
+157
View File
@@ -0,0 +1,157 @@
/**
**
** @RDE_HEADER@
** Base class for reference counted objects
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Umgebung: Intel-PC
** Software-Umgebung: Linux, Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Pgrm-Sprache ....: C++ 11
**
** HIER/SACHN ......: P: -- ---- - --- QE
**
** Version .........: $Revision$
** -----------------------------------------------------------------------------------------------
**
** Autor ...........: Nikolaus Hanekamp, SEDG, Tel. 2906
** Joerg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notizen .........:
**
** 18.08.2004, NH : Urversion
** 13.05.2015, JT : Refactoring for use with Qt5, ArcGIS 10.2.5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "situation_map_common_export.h"
namespace SituationMap
{
// forward declar, declared after Refenced below.
class DeleteHandler;
/**
@class Referenced referenced.h
@brief Base class for referenced counted object classes
Base class from providing referencing counted objects. Objects from type "Referenced" should
be used in combination with the class "RefPointer" for memory handling. In this case calling
delete direcly for those objects will result in an error at runtime. Unfortunately there is
no way to check this at compile time - to declare delete operator protected does not work.
@sa RefPointer
*/
class SITUATIONMAPCOMMON_EXPORT Referenced
{
public:
/**
@name Construction
@{
*/
Referenced() { _refCount = 0; }
Referenced(const Referenced &) { _refCount = 0; }
/** @} */
/**
Assign operator has to do nothing because is is permitted to change _refCount during assignment operation.
*/
inline Referenced &operator = (const Referenced &) { return *this; }
friend class DeleteHandler;
/** Set a DeleteHandler to which deletion of all referenced counted objects
* will be delegated to.*/
static void setDeleteHandler(DeleteHandler *handler);
/** Get a DeleteHandler.*/
static DeleteHandler *getDeleteHandler();
/** Increment the reference count by one, indicating that
this object has another pointer which is referencing it.*/
inline void ref() const { ++_refCount; }
/** Decrement the reference count by one, indicating that
a pointer to this object is referencing it. If the
reference count goes to zero, it is assumed that this object
is no longer referenced and is automatically deleted.*/
inline void unref() const;
/** Decrement the reference count by one, indicating that
a pointer to this object is referencing it. However, do
not delete it, even if ref count goes to 0. Warning, unref_nodelete()
should only be called if the user knows exactly who will
be resonsible for, one should prefer unref() over unref_nodelete()
as the later can lead to memory leaks.*/
inline void unref_nodelete() const { --_refCount; }
/** Return the number pointers currently referencing this object. */
inline int referenceCount() const { return _refCount; }
protected:
/**
Declaration of destructor is protected because only methode unref() or the delete
handler itself are allowed to destroy referenced objects.
*/
virtual ~Referenced();
mutable int _refCount;
};
/** Class for override the default delete behavior so that users can implement their own object
* deletion schemes. This might be done to help implement protection of multiple threads from deleting
* objects unintentionally.
* Note, the DeleteHandler cannot itself be reference counted, otherwise it
* would be responsible for deleting itself!
* An static auto_ptr<> is used internally in Referenced.cpp to manage the
* DeleteHandler's memory.*/
class SITUATIONMAPCOMMON_EXPORT DeleteHandler
{
public:
DeleteHandler() = default;
virtual ~DeleteHandler() = default;
/** Flush any cache of objects that need to be deleted by doing an actual delete.*/
virtual void flush() {}
static inline void doDelete(const Referenced *object) { delete object; }
/** Request the deletion of an object.
* Depending on users implementation of DeleteHandler, the delete of the object may occur
* straight away or be delayed until doDelete is called.
* The default implementation does a delete straight away.*/
virtual void requestDelete(const Referenced *object) { doDelete(object); }
}; /* DeleteHandler */
inline void Referenced::unref() const
{
--_refCount;
if (_refCount == 0)
{
if (getDeleteHandler()) getDeleteHandler()->requestDelete(this);
else delete this;
}
else if (_refCount < 0)
throw 2325;
} /* Referenced::unref */
} // SituationMap
+51
View File
@@ -0,0 +1,51 @@
/**
* @RDE_HEADER@
* Helper function to get the resource path
* $Id$
* $HeadURL$
* $Author$
*/
#include "resource_path.h"
#include <ngltools/ngltools_filesystem.h> // for NGL::directories
// Qt
#include <QDir>
#include <QVector>
//----------------------------------------------------------------------------
namespace SituationMap
{
QString getResourcePath()
{
const QString resDir = NGL::directory(NGL::FileType::ConfigFile, QLatin1String("resources"));
if (!resDir.isEmpty())
return resDir;
QVector<QString> pathsToSearch;
// for old systems
#ifdef Q_OS_WIN
pathsToSearch += QLatin1String("C:/ExtFw/resources/");
#else
pathsToSearch += QLatin1String("/usr/share/arcgis/resources");
#endif
for (const QString &path : qAsConst(pathsToSearch))
{
if (QDir(path).exists())
return path + QLatin1Char('/');
}
return QString();
}
} // namespace SituationMap
+24
View File
@@ -0,0 +1,24 @@
/**
* @RDE_HEADER@
* Helper function to get the resource path
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "situation_map_common_export.h"
// Qt
#include <QString>
//----------------------------------------------------------------------------
namespace SituationMap
{
QString SITUATIONMAPCOMMON_EXPORT getResourcePath();
} // namespace SituationMap
+96
View File
@@ -0,0 +1,96 @@
/**
* @RDE_HEADER@
* Helper class for storing a simple value and an implizit changed flag
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Qt
#include <sstream>
//----------------------------------------------------------------------------
namespace SituationMap
{
/*! \class SimpleValue
\brief Simple storing fo values
*/
template <class TYPE> class SimpleValue
{
protected:
TYPE m_value = TYPE(); // '{}' to initialize the member (and avoid unconditional jumps@valgrind)
bool m_changed = true;
public:
SimpleValue() = default;
// cppcheck-suppress noExplicitConstructor
SimpleValue(const TYPE &value) // should not be declared explicit to avoid additional writing stuff to cast values
: m_value(value)
{}
SimpleValue<TYPE> &operator=(const TYPE &newValue)
{
if (this->m_value != newValue)
{
this->m_value = newValue;
m_changed = true;
}
return *this;
}
const TYPE &operator()() const
{
return this->m_value;
}
const TYPE &value() const
{
return this->m_value;
}
TYPE &refValue()
{
m_changed = true;
return this->m_value;
}
const TYPE &refValue() const
{
return this->m_value;
}
bool changed() const
{
return m_changed;
}
void reset()
{
m_changed = false;
}
void setChanged()
{
m_changed = true;
}
friend std::ostream &operator<<(std::ostream &stream,
const SimpleValue &simpleVal)
{
stream << simpleVal.value();
return stream;
}
};
} // namespace SituationMap
@@ -0,0 +1,21 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <qglobal.h>
#ifndef SITUATIONMAPCOMMON_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define SITUATIONMAPCOMMON_EXPORT
# else
# if defined(MAKE_SITUATIONMAPCOMMON_LIB)
# define SITUATIONMAPCOMMON_EXPORT Q_DECL_EXPORT
# else
# define SITUATIONMAPCOMMON_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
+51
View File
@@ -0,0 +1,51 @@
/**
* @RDE_HEADER@
* Logging within SituationMap
* $Id$
* $HeadURL$
* $Author$
*/
#include "situation_map_logging.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QUuid>
namespace SituationMap
{
LOGGER_T getLogger(const char *name, int id)
{
static const QLatin1String prefix("SituationMap.");
std::string loggerName;
const size_t len = strlen(name);
loggerName.reserve(prefix.size() + len);
loggerName.append(prefix.data(), prefix.size());
loggerName.append(name, len);
if (id > 0)
{
std::stringstream loggerStream;
loggerStream << loggerName << "." << id;
loggerName = loggerStream.str();
}
try
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
getNGLLogger(loggerName);
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
} // namespace SituationMap
std::ostream &operator<< (std::ostream &stream,
const QUuid &value)
{
stream << "QUuid(" << value.toString() << ")";
return stream;
}
+38
View File
@@ -0,0 +1,38 @@
/**
* @RDE_HEADER@
* Logging within SituationMap
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
#include "situation_map_common_export.h"
class QUuid;
namespace SituationMap
{
using LOGGER_T = NGL::INGLLogger&;
// export for executables within 'Tests'
LOGGER_T SITUATIONMAPCOMMON_EXPORT getLogger(const char *name, int id = -1);
} // namespace SituationMap
SITUATIONMAPCOMMON_EXPORT std::ostream &operator<< (std::ostream &stream,
const QUuid &value);
+37
View File
@@ -0,0 +1,37 @@
#
# $Id$
# $HeadURL$
# $Author$
#
FIND_PACKAGE(GDAL REQUIRED)
SET(Elevation_SRCS
elevation_map.cpp
elevation_map.h
elevation_map_manager.cpp
elevation_map_manager.h
line_of_sight_calculation.cpp
line_of_sight_calculation.h
)
NGL_ADD_LIBRARY2(AAR SV WS HLA situationMapElevationMap SHARED ${Elevation_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(situationMapElevationMap
PRIVATE
${GDAL_INCLUDE_DIR}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(situationMapElevationMap
PRIVATE
situationMapCommon
Qt5::Concurrent
Qt5::Gui
NGLLogger
${GDAL_LIBRARIES}
LtsCoordTrans
PUBLIC
Qt5::Core
LtsUtilsCoreHeaderOnly
)
+975
View File
@@ -0,0 +1,975 @@
/**
* @RDE_HEADER@
* adapting GeISiR source to SituationMap
* $Id$
* $HeadURL$
* $Author$
*/
#include "elevation_map.h"
#include <QtConcurrent>
#include <QPolygonF>
#include <MathUtils/math_const.h>
#include <QElapsedTimer>
#include <gdal.h>
#include <iostream>
#include <limits>
#include <memory>
#include <math.h>
namespace SituationMap
{
class BoundingRect
{
double m_top = 0.0;
double m_bottom = 0.0;
double m_left = 0.0;
double m_right = 0.0;
void swapBounds()
{
if (m_top < m_bottom)
std::swap(m_bottom, m_top);
if (m_right < m_left)
std::swap(m_left, m_right);
} // void swapBounds()
public:
BoundingRect() = default;
BoundingRect(double left, double bottom, double right, double top)
: m_top(top), m_bottom(bottom), m_left(left), m_right(right)
{
swapBounds();
} // BoundingRect( double left, double bottom, double right, double top)
BoundingRect(const BoundingRect &) = default;
BoundingRect &operator =(const BoundingRect &) = default;
~BoundingRect() = default;
inline void operator()(double left, double bottom, double right, double top)
{
m_top = top;
m_bottom = bottom;
m_left = left;
m_right = right;
swapBounds();
} // inline void operator() (double left, double bottom, double right, double top)
double top() const { return m_top; }
double bottom() const { return m_bottom; }
double left() const { return m_left; }
double right() const { return m_right; }
bool contains(const QPointF &p) const { return ((p.x() >= m_left) && (p.x() <= m_right) && (p.y() >= m_bottom) && (p.y() <= m_top)); }
QRectF toQRectF() const
{
return QRectF(QPointF(m_left, m_top), QPointF(m_right, m_bottom));
} // toQRectF
}; // BoundingRect
struct ElevationMap::Internal
{
BoundingRect _location; // Lage der Karte in Lat/Lon
struct PointDouble
{
void setX(double x) { _x = x;}
void setY(double y) { _y = y;}
double x() { return _x;}
double y() { return _y;}
double _x{0.0};
double _y{0.0};
};
PointDouble _elexelSize; // LatLon Size of 1 elevation sample, redundat
int _totalColumns = 0;
int _totalRows = 0;
double _toMeterFactor = 1.0;
std::vector<int> _elevationField;
template<class BufferType> bool copyBufferData(GDALRasterBandH hBand, int xBlkSize, int yBlkSize)
{
// NLDEVCTRL-804: Konsistenz d. Z-Werte zwischen 2D/3D (also ElevationMap vs. ESRI::BaseSurface)
// This ElevationMap was using an approach similar to following.
// Now it´s more or less identical and the difference using 'Altmark_dt1.tif'
// are gone. AHTC is also fine :-)
/*
CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
{
memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
int nXBlockSize, nYBlockSize;
poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
{
for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
{
int nXValid, nYValid;
poBand->ReadBlock( iXBlock, iYBlock, pabyData );
// Compute the portion of the block that is valid
// for partial edge blocks.
poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
// Collect the histogram counts.
for( int iY = 0; iY < nYValid; iY++ )
{
for( int iX = 0; iX < nXValid; iX++ )
{
panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
}
}
}
}
}
Source https://gdal.org/api/gdalrasterband_cpp.html
*/
const size_t bufSize = xBlkSize * yBlkSize;
std::unique_ptr<BufferType[]> bufferPtr(new BufferType[bufSize]);
int nXBlocks = (GDALGetRasterBandXSize(hBand) + xBlkSize - 1) / xBlkSize;
int nYBlocks = (GDALGetRasterBandYSize(hBand) + yBlkSize - 1) / yBlkSize;
for (int iYBlock = 0; iYBlock < nYBlocks; ++iYBlock)
{
for (int iXBlock = 0; iXBlock < nXBlocks; ++iXBlock)
{
CPLErr err = GDALReadBlock( hBand, iXBlock, iYBlock, bufferPtr.get() ); // Gdal liest spaltenweise !! x <-> y
if (err != CE_None)
{
return false;
}
int nXValid, nYValid;
// Unfortunately GDALGetActualBlockSize is not available at Suse 42.3 (gdal 2.1.3)
// so check bounds using _totalColumns, _totalRows:
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2, 2, 0)
# define HAS_ACTUAL_BLOCKSIZE
#endif
#ifdef HAS_ACTUAL_BLOCKSIZE
GDALGetActualBlockSize(hBand, iXBlock, iYBlock, &nXValid, &nYValid);
#else
nXValid = xBlkSize;
nYValid = yBlkSize;
#endif // HAS_ACTUAL_BLOCKSIZE
const int curYOffset = (iYBlock * yBlkSize);
const int curXOffset = (iXBlock * xBlkSize);
for (int iY = 0; iY < nYValid; ++iY)
{
const int row = iY + curYOffset; // Line
#ifndef HAS_ACTUAL_BLOCKSIZE
if (row >= _totalRows)
continue;
#endif // HAS_ACTUAL_BLOCKSIZE
for (int iX = 0; iX < nXValid; ++iX)
{
// identical to gdallocationinfo
const int column = iX + curXOffset; // Pixel
#ifndef HAS_ACTUAL_BLOCKSIZE
if (column >= _totalColumns)
continue;
#endif // HAS_ACTUAL_BLOCKSIZE
int bi = iX + (iY * xBlkSize);
const int z = static_cast<int>( static_cast<double>(bufferPtr[bi]) / _toMeterFactor );
_elevationField[column + row * _totalColumns] = z;
} // for
} // for
} // for
} // for
return true;
} // template<class BufferType> void copyBufferData(BufferType * bufferPtr, int xBlkSize, int yBlkSize)
}; // struct ElevationMap::Internal
ElevationMap::ElevationMap(const QFileInfo &fileInfo)
: m_internal(new Internal())
, m_aproximation(true)
, m_valid(false)
, m_logger(getLogger("ElevationMap"))
{
GDALAllRegister();
m_fileName = fileInfo.absoluteFilePath();
INFO_LOG(m_logger) << " ctor ElevationMap: map of file '" << m_fileName << "'"
<< ", this=" << this;
if (!fileInfo.exists())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " elevation data file \'" << m_fileName << "\' doesn't exists.";
return;
}
if (!fileInfo.isReadable())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " elevation data file \'" << m_fileName << "\' isn't readable.";
return;
}
auto cb = [this]()
{
return readFromFile();
};
auto cbFinished = [this]()
{
NOTICE_LOG(m_logger) << " Finished reading elevation map of file '" << m_fileName << "'"
<< ", this=" << this;
};
QObject::connect(&m_gdalReadWatcher, &QFutureWatcher<bool>::finished,
&m_gdalReadWatcher, cbFinished);
m_gdalReadWatcher.setFuture(QtConcurrent::run(cb));
// sync init, takes ~800ms during sitmap loading 72MB file
// QElapsedTimer t;
// t.start();
// m_gdalReadWatcher.waitForFinished();
// NOTICE_LOG(m_logger) << "Time loading elevation map: " << t.elapsed();
} // ElevationMap::ElevationMap( const QFile &file )
ElevationMap::~ElevationMap()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_gdalReadWatcher.cancel();
m_gdalReadWatcher.waitForFinished();
delete m_internal;
m_internal = nullptr;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
} // ElevationMap::~ElevationMap
bool ElevationMap::waitForInitialization()
{
m_gdalReadWatcher.waitForFinished();
return m_valid;
}
bool ElevationMap::isValid() const
{
// N. Thoden, 27.04.2020
// isFinished seems to be unreliable:
// if mainThread request ::isValid() diretly after ::waitForInitialization()
// you get false (by 'if (!m_gdalReadWatcher.isFinished())'
// but m_valid is true. So skip the additional check.
// if (!m_gdalReadWatcher.isFinished())
// return false;
return m_valid;
}
QString ElevationMap::filename() const
{
return m_fileName;
}
bool ElevationMap::readFromFile()
{
m_valid = false;
GDALDatasetH hDataset = GDALOpen(m_fileName.toLocal8Bit().constData(), GA_ReadOnly);
if (nullptr == hDataset)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " GDALOpen failed, may be calling of GDALAllRegister is missing";
return false;
}
// Detect basic parameters
//
GDALDriverH hDriver = GDALGetDatasetDriver(hDataset);
int nRasterXSize = GDALGetRasterXSize(hDataset);
int nRasterYSize = GDALGetRasterYSize(hDataset);
double adfGeoTransform[6];
CPLErr err = GDALGetGeoTransform(hDataset, adfGeoTransform); // XY Spatial Referenz WGS84 (4326) expected!!!
if (err != CE_None)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " GDAL failed to get geo raster transform.";
GDALClose(hDataset);
return false;
}
if (nullptr == hDriver) { GDALClose(hDataset); return false; }
if (nRasterXSize <= 0) { GDALClose(hDataset); return false; }
if (nRasterYSize <= 0) { GDALClose(hDataset); return false; }
double pixWidth = adfGeoTransform[1];
double pixHeight = adfGeoTransform[5];
auto toRAD = [](double x) -> double { return x * MathConst::pi / 180.0; };
m_internal->_location(toRAD(adfGeoTransform[0]) // adfGeoTransform is in degrees
, toRAD(adfGeoTransform[3])
, toRAD(adfGeoTransform[0] + double(nRasterXSize) * pixWidth + double(nRasterYSize) * adfGeoTransform[2])
, toRAD(adfGeoTransform[3] + double(nRasterYSize) * pixHeight + double(nRasterXSize) * adfGeoTransform[4]));
m_internal->_elexelSize.setX(fabs(toRAD(pixWidth)));
m_internal->_elexelSize.setY(fabs(toRAD(pixHeight)));
GDALRasterBandH hBand = GDALGetRasterBand(hDataset, 1);
if (nullptr == hBand)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " GDAL failed to read raster band.";
GDALClose(hDataset);
return false;
}
int xBlkSize;
int yBlkSize;
GDALGetBlockSize(hBand, &xBlkSize, &yBlkSize);
if (xBlkSize <0 || yBlkSize < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no buffer, next operations will possible fail....";
return false;
}
m_internal->_totalColumns = nRasterXSize;
m_internal->_totalRows = nRasterYSize;
m_internal->_elevationField.resize(nRasterXSize * nRasterYSize);
const GDALDataType type = GDALGetRasterDataType(hBand);
switch (type)
{
case GDT_UInt16:
m_internal->_toMeterFactor = 1.0;
m_valid = m_internal->copyBufferData<unsigned short int> ( hBand, xBlkSize, yBlkSize );
break;
case GDT_Int16:
m_internal->_toMeterFactor = 1.0;
m_valid = m_internal->copyBufferData<short int> ( hBand, xBlkSize, yBlkSize );
break;
case GDT_Float32:
m_internal->_toMeterFactor = 0.01;
m_valid = m_internal->copyBufferData<float> ( hBand, xBlkSize, yBlkSize );
break;
case GDT_Float64:
m_internal->_toMeterFactor = 0.01;
m_valid = m_internal->copyBufferData<double> ( hBand, xBlkSize, yBlkSize );
break;
default:
{
ERROR_LOG(m_logger) << LOGFUNCTION << " data type isn't supported type or a floating point type"
<< " (type=" << type << ")";
GDALClose(hDataset);
return false;
}
} // switch
if (!m_valid)
{
CPLErrorNum errNum = CPLGetLastErrorNo();
ERROR_LOG(m_logger) << LOGFUNCTION << " GDAL failed to read data block (error no " << int(errNum) << ")";
}
GDALClose(hDataset);
INFO_LOG(m_logger) << LOGFUNCTION << " loaded, filename =" << m_fileName << "'"
<< ", m_valid=" << m_valid;
return m_valid;
} // bool ElevationMap::readFromFile(const QString & fileName)
QRectF ElevationMap::extent() const
{
if (!isValid())
return QRectF();
return m_internal->_location.toQRectF();
}
QPair<double, double> ElevationMap::elexelSize() const
{
return {m_internal->_elexelSize._x, m_internal->_elexelSize._y};
}
int ElevationMap::getElevation(int column, int row) const
{
row = m_internal->_totalRows - row;
const size_t index = column + row * m_internal->_totalColumns;
if (m_internal->_elevationField.empty() || m_internal->_elevationField.size() < index)
return std::numeric_limits<int>::min();
return m_internal->_elevationField.at(index);
} // int ElevationMap::getElevation( int column, int row)
double ElevationMap::elevation(double lon, double lat) const
{
if (!isValid())
return 0;
return getElevation(lon, lat) * m_internal->_toMeterFactor;
} // double ElevationMap::elevation( double lon, double lat)
double ElevationMap:: getElevation(double lon, double lat) const
{
if (!m_internal->_location.contains(QPointF(lon, lat)))
{
return std::numeric_limits<int>::min(); // ausserhalb der Höhenkarte !!
}
double x = (lon - m_internal->_location.left()) / m_internal->_elexelSize.x();
int column = floor(x);
double y = (lat - m_internal->_location.bottom()) / m_internal->_elexelSize.y();
int row = floor(y);
int elevation = getElevation(column, row);
if (elevation == std::numeric_limits<int>::min())
return elevation;
if (!m_aproximation)
return elevation;
/*
** Approximation: e0, e1, e2, e3 Hoehenwerte der 4 benachbarten Stützpunkte
**
** + e3 + e2
** y
** ^ + er er = e0 + x*(e1-e0) + y*(e3-e0) + x*y(e2-e3+e0-e1)
** |
** |
** |
** | + e0 + e1
** -----> x
**
** Besonderheiten: die Stützpunkte liegen definitiongemaess jeweils in der Mitte des Rasters,
** so dass je nach Groesse von x, y andere Nachbarpunkte zu berücksichtigen sind, und x, sowie y entsprechend
** angepasst werden muesen.
** Bei Randrasterpunkten kann keine Interpolation erfolgen, so dass hier entsprechend extrapoliert wird.
*/
x = (x - (double)column); // Residuum normiert auf Stützpunktabstand
y = (y - (double)row); // Residuum normiert auf Stützpunktabstand
x -= 0.5; // Mitte berücksichtigen
y -= 0.5; // Mitte berücksichtigen
if (x < 0.0) { column--; x += 1.0;} // linke Spalte zur Interpolation nutzen
if (y < 0.0) { row--; y += 1.0;} // untere Reihe zur Interpolation nutzen
// Randrasterpunkte berücksichtigen: extrapolieren statt interpolieren
if (column <= -1) { x = -x; column = 0;}
else if (column >= (m_internal->_totalColumns - 1)) { x += 1.0; column = m_internal->_totalColumns - 2;}
if (row == -1) { y = -y; row = 0;}
else if (row >= (m_internal->_totalRows - 1)) { y += 1.0; row = m_internal->_totalRows - 2;}
// Die Approximation:
double substitute = elevation;
double e0 = getOrSubstituteElevation(column, row, substitute);
double e1 = getOrSubstituteElevation(column + 1, row, substitute);
double e2 = getOrSubstituteElevation(column + 1, row + 1, substitute);
double e3 = getOrSubstituteElevation(column, row + 1, substitute);
double er = e0 + x * (e1 - e0) + y * (e3 - e0) + x * y * (e2 - e3 + e0 - e1);
return er; // floor(er+0.5);; runden herausgenommen 19.8.2008 JT
} // double ElevationMap:: getElevation( double lon, double lat)
double ElevationMap::getOrSubstituteElevation(int column, int row, double substitute) const
{
int elevation = getElevation(column, row);
if (elevation != std::numeric_limits<int>::min())
return elevation;
int substCount = 0;
double calcSubstitute = 0.0;
elevation = getElevation(column + 1, row);
if (elevation != std::numeric_limits<int>::min()) {substCount++; calcSubstitute += elevation; }
elevation = getElevation(column - 1, row);
if (elevation != std::numeric_limits<int>::min()) {substCount++; calcSubstitute += elevation; }
elevation = getElevation(column, row + 1);
if (elevation != std::numeric_limits<int>::min()) {substCount++; calcSubstitute += elevation; }
elevation = getElevation(column, row - 1);
if (elevation != std::numeric_limits<int>::min()) {substCount++; calcSubstitute += elevation; }
if (substCount)
substitute = calcSubstitute / substCount;
return substitute;
} // double ElevationMap::getOrSubstituteElevation( int column, int row, double substitute)
double ElevationMap::distance(const QPointF &start, const QPointF &end) const
{
if (!isValid())
return 0;
if (!m_internal->_location.contains(start) || !m_internal->_location.contains(end))
{
return -1.0; // ausserhalb{ der Höhenkarte !!
}
double start_z = getElevation(start.x(), start.y());
if (start_z <= std::numeric_limits<int>::min()) return -1.0;
double end_z = getElevation(end.x(), end.y());
if (end_z <= std::numeric_limits<int>::min()) return -1.0;
const QPointF &dist = distance_in_meter_WGS84(start, end);
double dz = end_z - start_z;
double d = sqrt(dist.x() * dist.x() + dist.y() * dist.y() + dz * dz) ;
return d;
} // double ElevationMap::distance( const QPointF &start, const QPointF &end )
double ElevationMap::profileDistance(const QPointF &start, const QPointF &end) const
{
if (!isValid())
return 0;
if (!m_internal->_location.contains(start) || !m_internal->_location.contains(end))
{
return -1.0; // ausserhalb der Höhenkarte !!
}
Vec3dVector elevProfile;
getSamplePoints(start, end, elevProfile);
for (Vec3dVector::iterator itr = elevProfile.begin(); itr != elevProfile.end(); ++itr)
itr->setZ(getElevation(itr->x(), itr->y()));
// Einzellaengen aufsummieren, Stützstellen mit undefinierten Hoehen werden ausgelassen!
Point3D curPos(*elevProfile.begin());
double sumLng = 0.0;
for (Vec3dVector::iterator itr = elevProfile.begin() + 1; itr != elevProfile.end(); ++itr)
{
if ((*itr).z() > std::numeric_limits<int>::min())
{
if (curPos.z() > std::numeric_limits<int>::min())
{
const QPointF &dist = distance_in_meter_WGS84(QPointF(curPos.x(), curPos.y()), QPointF(itr->x(), itr->y()));
double dz = itr->z() - curPos.z();
sumLng += sqrt(dist.x() * dist.x() + dist.y() * dist.y() + dz * dz) ;
}
else
{
double dx = itr->x() - curPos.x();
double dy = itr->y() - curPos.y();
sumLng += sqrt(dx * dx + dy * dy);
}
curPos = *itr;
}
}
return sumLng;
} // double ElevationMap::profileDistance( const QPointF &start, const QPointF &end)
unsigned int ElevationMap::elevationProfile(const QPointF &start, const QPointF &end, Vec3dVector &elevProfile) const
{
unsigned int startSize = elevProfile.size();
getSamplePoints(start, end, elevProfile);
for (Vec3dVector::iterator itr = elevProfile.begin() + startSize; itr != elevProfile.end(); ++itr)
itr->setZ(getElevation(itr->x(), itr->y()));
return (elevProfile.size() - startSize);
} // unsigned int ElevationMap::elevationProfile( const QPointF &start, const QPointF &end, Vec3dVector &elevProfile)
bool ElevationMap::contains(const QPointF &point) const
{
return m_internal->_location.contains(point);
}
bool ElevationMap::intersects(const QPolygonF &polygon) const
{
const BoundingRect &bbox = m_internal->_location;
// maybe QPointF uses float, but we can accept double to be reduced to float:
const QPolygonF &ourBorder = QPolygonF({QPointF(bbox.left() , bbox.bottom()),
QPointF(bbox.left() , bbox.top()),
QPointF(bbox.right(), bbox.top()),
QPointF(bbox.right(), bbox.bottom())});
#if QT_VERSION < QT_VERSION_CHECK(5,10,0)
return ourBorder.intersected(polygon).size() > 0;
#else
return ourBorder.intersects(polygon);
#endif
}
void ElevationMap::getSamplePoints(const QPointF &start, const QPointF &end, Vec3dVector &sPnts) const
{
sPnts.clear();
sPnts.push_back(Point3D::fromQPointF(start));
bool endIsClipped = false;
QPointF cStart(start);
QPointF cEnd(end);
if (!m_internal->_location.contains(start) || !m_internal->_location.contains(end))
{
int res = clipp2Map(start, end, cStart, cEnd);
if (res == 0) // no intersection
{
sPnts.push_back(Point3D::fromQPointF(end));
return;
}
if (res & 1) // start clipped
sPnts.push_back(Point3D::fromQPointF(cStart));
if (res & 2) // end clipped
endIsClipped = true;
}
QPointF delta(cEnd - cStart);
// Berechne alle Schnittpunkte des Vektors( cStart, cEnd) mit den x-Grenzen der Hoehenstuetzrechtecke.
// Die Stützpunkte liegen definitiongemaess jeweils in der Mitte des Raster-Rechtecks
int startCol = floor((cStart.x() - m_internal->_location.left()) / m_internal->_elexelSize.x());
if (startCol < 0) startCol = 0;
else if (startCol >= m_internal->_totalColumns) startCol = m_internal->_totalColumns - 1;
int endCol = floor((cEnd.x() - m_internal->_location.left()) / m_internal->_elexelSize.x());
if (endCol < 0) endCol = 0;
else if (endCol >= m_internal->_totalColumns) endCol = m_internal->_totalColumns - 1;
int incCol = 0;
if (endCol > startCol) incCol = 1;
else if (endCol < startCol) incCol = -1;
double m = delta.y() / delta.x();
Vec2dVector xCuts;
xCuts.reserve(std::abs(endCol - startCol));
for (int col = startCol; col != endCol; col += incCol)
{
double x = m_internal->_location.left() + ((col + 0.5) + (incCol * 0.5)) * m_internal->_elexelSize.x();
double y = cStart.y() + (x - cStart.x()) * m;
xCuts.push_back(QPointF(x, y));
}
// Berechne alle Schnittpunkte des Vektors( cStart, cEnd) mit den y-Grenzen der Hoehenstuetzrechtecke.
// Die Stützpunkte liegen definitiongemaess jeweils in der Mitte des Raster-Rechtecks
int startRow = floor((cStart.y() - m_internal->_location.bottom()) / m_internal->_elexelSize.y());
if (startRow < 0) startRow = 0;
else if (startRow >= m_internal->_totalRows) startRow = m_internal->_totalRows - 1;
int endRow = floor((end.y() - m_internal->_location.bottom()) / m_internal->_elexelSize.y());
if (endRow < 0) endRow = 0;
else if (endRow >= m_internal->_totalRows) endRow = m_internal->_totalRows - 1;
int incRow = 0;
if (endRow > startRow) incRow = 1;
else if (endRow < startRow) incRow = -1;
m = delta.x() / delta.y();
Vec2dVector yCuts;
yCuts.reserve(std::abs(endRow - startRow));
for (int row = startRow; row != endRow; row += incRow)
{
double y = m_internal->_location.bottom() + ((row + 0.5) + (incRow * 0.5)) * m_internal->_elexelSize.y();
double x = cStart.x() + (y - cStart.y()) * m;
yCuts.push_back(QPointF(x, y));
}
// xCuts und yCuts zusammenführen, unter Berücksichtigung der Reihenfolge
Vec2dVector mergeCuts;
Vec2dVector::iterator xCutItr = xCuts.begin();
Vec2dVector::iterator yCutItr = yCuts.begin();
while ((xCutItr != xCuts.end()) && (yCutItr != yCuts.end()))
{
if (incCol > 0)
{
if ((*xCutItr).x() < (*yCutItr).x()) { mergeCuts.push_back(*xCutItr); ++xCutItr; }
else { mergeCuts.push_back(*yCutItr); ++yCutItr; }
}
else
{
if ((*xCutItr).x() > (*yCutItr).x()) { mergeCuts.push_back(*xCutItr); ++xCutItr; }
else { mergeCuts.push_back(*yCutItr); ++yCutItr; }
}
}
while ((xCutItr != xCuts.end())) { mergeCuts.push_back(*xCutItr); ++xCutItr; }
while ((yCutItr != yCuts.end())) { mergeCuts.push_back(*yCutItr); ++yCutItr; }
// mergeCuts enthält sequenziell alle Schnittpunkte des Vektors mit den Hoehengridkanten
// Die 2 Schnittpunkte pro Hoehenwert werden gemittelt zu einem zusammengefasst
if (mergeCuts.size() > 1)
{
for (Vec2dVector::iterator itr = mergeCuts.begin() + 1; itr != mergeCuts.end(); ++itr)
sPnts.push_back(Point3D::fromQPointF((*(itr - 1) + *itr) * 0.5));
}
sPnts.push_back(Point3D::fromQPointF(cEnd));
// DEBUG_LOG(m_logger) << " xCuts.si " << xCuts.size()
// << ", yCuts.si " << yCuts.size()
// << ", mergeCuts.si " << mergeCuts.size();
if (endIsClipped) sPnts.push_back(Point3D::fromQPointF(end));
} // void ElevationMap::getSamplePoints( const QPointF &start, const QPointF &end, Vec3dVector & sPnts)
// start und/oder end liegt ausserhalb !! in Lat/Lon !!
int ElevationMap::clipp2Map(const QPointF &start, const QPointF &end, QPointF &cStart, QPointF &cEnd) const
{
Vec2dVector clippVec;
if (end.x() != start.x())
{
double x = m_internal->_location.right();
double m = (end.y() - start.y()) / (end.x() - start.x());
if (isInIntervall(x, start.x(), end.x()))
{
double yc = start.y() + (x - start.x()) * m;
if ((yc <= m_internal->_location.top()) && (yc >= m_internal->_location.bottom()))
clippVec.push_back(QPointF(x, yc));
}
x = m_internal->_location.left();
if (isInIntervall(x, start.x(), end.x()))
{
double yc = start.y() + (x - start.x()) * (end.y() - start.y()) / (end.x() - start.x());
if ((yc <= m_internal->_location.top()) && (yc >= m_internal->_location.bottom()))
clippVec.push_back(QPointF(x, yc));
}
}
if (end.y() != start.y())
{
double y = m_internal->_location.top();
double m = (end.x() - start.x()) / (end.y() - start.y());
if (isInIntervall(y, start.y(), end.y()))
{
double xc = start.x() + (y - start.y()) * m;
if ((xc < m_internal->_location.right()) && (xc > m_internal->_location.left()))
clippVec.push_back(QPointF(xc, y));
}
y = m_internal->_location.bottom();
if (isInIntervall(y, start.y(), end.y()))
{
double xc = start.x() + (y - start.y()) * m;
if ((xc < m_internal->_location.right()) && (xc > m_internal->_location.left()))
clippVec.push_back(QPointF(xc, y));
}
}
int size = (int)clippVec.size();
if (size == 0)
{
return 0; // komlett ausserhalb ( oder komplett innerhalb)
}
if (size == 1)
{
if (m_internal->_location.contains(start))
{
cEnd = clippVec[0]; return 2;
}
else
{
cStart = clippVec[0]; return 1;
}
}
if (size == 2)
{
if (squareLength(clippVec[0] - start) < squareLength(clippVec[1] - start))
{
cStart = clippVec[0];
cEnd = clippVec[1];
}
else
{
cStart = clippVec[1];
cEnd = clippVec[0];
}
return 3;
}
ERROR_LOG(m_logger) << LOGFUNCTION << "Internal Clipp Error!";
return 0;
} // int ElevationMap::clipp2Map( const QPointF &start, const QPointF &end, QPointF &cStart, QPointF &cEnd)
// Line of Sight Profile: berücksichtigt Erdkrümmung und WGS84 Erdellipsoid
void ElevationMap::LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile)
{
m_gdalReadWatcher.waitForFinished();
if (!m_internal->_location.contains(start)) return ; // ausserhalb der Höhenkarte !!
bool clipped = false;
double totalLng;
QPointF startG = start;
QPointF endG = end;
if (!m_internal->_location.contains(end)) // Clippen
{
clipped = true;
totalLng = length(endG - startG);
if (endG.x() < m_internal->_location.left())
{
double m = (endG.y() - startG.y()) / (endG.x() - startG.x());
double x = m_internal->_location.left();
endG.setX(x);
endG.setY(startG.y() + m * (x - startG.x()));
}
else if (endG.x() > m_internal->_location.right())
{
double m = (endG.y() - startG.y()) / (endG.x() - startG.x());
double x = m_internal->_location.right();
endG.setX(x);
endG.setY(startG.y() + m * (x - startG.x()));
}
if (endG.y() < m_internal->_location.bottom())
{
double m = (endG.x() - startG.x()) / (endG.y() - startG.y());
double y = m_internal->_location.bottom();
endG.setY(y);
endG.setX(startG.x() + m * (y - startG.y()));
}
else if (endG.y() > m_internal->_location.top())
{
double m = (endG.x() - startG.x()) / (endG.y() - startG.y());
double y = m_internal->_location.top();
endG.setY(y);
endG.setX(startG.x() + m * (y - startG.y()));
}
}
// Korrektursteigung aufgrund WGS84 Erdellipsoid, Lineare Approximation, Fehler bis 200 km: < 1.0m
double startRadius = radiusWGS84(startG.y());
double corrM = (radiusWGS84(endG.y()) - startRadius) / length(endG - startG);
Vec3dVector elevProfile;
getSamplePoints(start, end, elevProfile);
for (Vec3dVector::iterator itr = elevProfile.begin(); itr != elevProfile.end(); ++itr)
{
double dist = length(distance_in_meter_WGS84(start, itr->toPointF()));
double height = elevation(itr->x(), itr->y());
height += corrM * dist; // WGS84 Erdellipsoid Korrektur
height -= (startRadius * (1 - cos(atan(dist / startRadius)))); // Einbeziehen der Erdkruemmung
// alternativ als Naeherung: height -= ( dist * dist) / (startRadius * 2.0);
losProfile.push_back(LOSentry(dist, height));
}
if (clipped)
losProfile.push_back(LOSentry(totalLng, -NAN));
qCritical() << " losProfile.isze() = " << losProfile.size();
} // void ElevationMap::LOSProfile( const QPointF &start, const QPointF &end, LOSVector &losProfile)
} // SituationMap
/* -----------------------------------------------------------------------------------------------
** CVS-Id/Release ...: $Header$
** -----------------------------------------------------------------------------------------------
**
** Historie:
**
** $Log: not supported by cvs2svn $
** Revision 1.17.1.1 2008/06/16 06:05:37 joerg
** Transparenz und Bias einheitlich für alle Objekte implementiert
**
** Revision 1.17 2006/03/24 09:05:01 klaus
** Elevationprofile: Begrenzung auf Kartengröße aufgehoben ( Clipping)
**
** Revision 1.16 2005/11/09 13:44:36 klaus
** Umsetzung auf Linux;
**
** Revision 1.15 2005/04/15 13:05:45 joerg
** Resource Control
**
** Revision 1.14 2005/03/04 14:29:26 klaus
** Elevationmap mit CachedTileList versehen und automatischem Entladen von Tiles
**
** Revision 1.13 2005/03/03 12:37:53 klaus
** dynamischen Laden und Entladen der ElevationTiles für Reliefmap
**
** Revision 1.12 2005/03/01 12:36:59 klaus
** Reliefmap eingeführt, aus Elevationmap entfernt
**
** Revision 1.11 2005/02/25 15:32:56 klaus
** Ergänzung um Reliefkarte
**
** Revision 1.10 2005/02/10 14:15:19 klaus
** Bias in Basisklasse MapObject überführt
**
** Revision 1.9 2005/02/10 13:50:33 klaus
** Bias für SightFans eingeführt
**
** Revision 1.8 2005/02/09 16:45:26 klaus
** 1. Version der SightFans
**
** Revision 1.7 2005/01/26 12:26:23 klaus
** todos bearbeitet, Fehlerrückmeldnugen
**
** Revision 1.6 2004/12/14 10:29:48 klaus
** 7. Erweiterung für Höhenkarten
**
** Revision 1.5 2004/12/07 11:08:28 klaus
** 5. Erweiterung für Höhenkarten
**
** Revision 1.4 2004/12/03 16:25:14 klaus
** 4. Erweiterung für Höhenkarten
**
** Revision 1.3 2004/11/30 13:18:13 klaus
** 3. Erweiterung für Höhenkarten
**
** Revision 1.2 2004/11/23 14:36:40 klaus
** 2. Erweiterung für Höhenkarten
**
**
** ----------------------------------------------------------------------------------------------- */
+168
View File
@@ -0,0 +1,168 @@
/**
* @RDE_HEADER@
* adapting GeISiR source to SituationMap
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "elevation_map_helper.h"
#include <ElevationMap/situationmapelevationmap_export.h>
#include <LtsUtilsCore/qpoint3d.h>
#include <Common/situation_map_logging.h>
#include <QFutureWatcher>
#include <QPointF>
#include <QRectF>
#include <QVector>
class QFileInfo;
namespace SituationMap
{
//------------------------------------------------------------------------------------------------------------
// ElevationMap
//------------------------------------------------------------------------------------------------------------
class SITUATIONMAPELEVATIONMAP_EXPORT ElevationMap final
{
friend class ElevationMapManager;
public:
ElevationMap() = delete;
ElevationMap(const ElevationMap &) = delete;
ElevationMap &operator = (const ElevationMap &) = delete;
explicit ElevationMap(const QFileInfo &fileInfo);
~ElevationMap();
bool waitForInitialization();
bool isValid() const;
QString filename() const;
QRectF extent() const;
QPair<double, double> elexelSize() const;
double elevation(double lon, double lat) const; // rad
double distance(const QPointF &start, const QPointF &end) const;
double profileDistance(const QPointF &start, const QPointF &end) const;
unsigned int elevationProfile(const QPointF &start, const QPointF &end, Vec3dVector &elevProfile) const;
void interpolation(bool on) { m_aproximation = on; }
bool interpolation() const { return m_aproximation; }
bool contains(const QPointF &point) const;
bool intersects(const QPolygonF &polygon) const;
// Line of Sight Profile: berücksichtigt Erdkrümmung und WGS84 Erdellipsoid
void LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile);
protected:
int getElevation(int column, int row) const;
double getElevation(double lon, double lat) const;
double getOrSubstituteElevation(int column, int row, double substitute) const;
// getSamplePoints rastert den Vector( start, end) in Lat/Lon entsprechend dem Höhenraster
void getSamplePoints(const QPointF &start, const QPointF &end, Vec3dVector &sPnts) const;
int clipp2Map(const QPointF &start, const QPointF &end, QPointF &cStart, QPointF &cEnd) const;
bool readFromFile();
struct Internal;
Internal *m_internal;
QString m_fileName;
bool m_aproximation;
bool m_valid;
QFutureWatcher<bool> m_gdalReadWatcher;
LOGGER_T m_logger; ///< Interface of the Logging-Facility
}; // ElevationMap
} // SituationMap
/* -----------------------------------------------------------------------------------------------
** CVS-Id/Release ...: $Header$
** -----------------------------------------------------------------------------------------------
**
** Historie:
**
** $Log: not supported by cvs2svn $
** Revision 1.20 2006/09/26 07:51:12 Jörg
** Syntax Fehler unter Suse Linux 10.1 behoben.
**
** Revision 1.19 2006/03/24 09:05:24 klaus
** Elevationprofile: Begrenzung auf Kartengröße aufgehoben ( Clipping)
**
** Revision 1.18 2005/11/09 11:12:27 klaus
** Anpassung an Linux: Kommentar hinter #endif mit "//" versehen
**
** Revision 1.17 2005/08/22 14:15:02 joerg
** typeId()
**
** Revision 1.16 2005/08/12 09:37:44 joerg
** Koordinaten-Umprojezieren bei Wechsel der Projektion
**
** Revision 1.15 2005/04/15 13:04:35 joerg
** Resource Control
**
** Revision 1.14 2005/03/04 14:29:13 klaus
** Elevationmap mit CachedTileList versehen und automatischem Entladen von Tiles
**
** Revision 1.13 2005/03/03 12:37:14 klaus
** dynamischen Laden und Entladen der ElevationTiles für Reliefmap
**
** Revision 1.12 2005/03/01 12:33:12 klaus
** Reliefmap eingeführt, aus Elevationmap entfernt
**
** Revision 1.11 2005/02/25 15:26:41 klaus
** Ergänzung um Reliefkarte
**
** Revision 1.10 2005/02/10 14:13:21 klaus
** Bias in Basisklasse MapObject überführt
**
** Revision 1.9 2005/02/10 13:51:01 klaus
** Bias für SightFans eingeführt
**
** Revision 1.8 2005/02/09 16:53:06 klaus
** 1. Version der SightFans
**
** Revision 1.7 2005/01/26 12:25:41 klaus
** todos bearbeitet, Fehlerrückmeldnugen
**
** Revision 1.6 2004/12/14 09:43:25 klaus
** 7. Erweiterung für Höhenkarten
**
** Revision 1.5 2004/12/07 11:07:20 klaus
** 5. Erweiterung für Höhenkarten
**
** Revision 1.4 2004/12/03 16:24:12 klaus
** 4. Erweiterung für Höhenkarten
**
** Revision 1.3 2004/11/30 13:15:28 klaus
** 3. Erweiterung für Höhenkarten
**
** Revision 1.2 2004/11/23 14:36:14 klaus
** 2. Erweiterung für Höhenkarten
**
**
** ----------------------------------------------------------------------------------------------- */
@@ -0,0 +1,88 @@
/**
* @RDE_HEADER@
* Some functions and struct for ElevationMap/LineOfSight (LOS)
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <LtsUtilsCore/qpoint3d.h>
#include <math.h>
#include <MathUtils/math_const.h>
#include <QPointF>
#include <QVector>
namespace SituationMap
{
inline bool isInIntervall(double x, double x1, double x2)
{
return (((x > x1) && (x < x2)) || (((x > x2) && (x < x1))));
} // inline bool isInIntervall(double x, double x1, double x2)
inline double radiusWGS84(double lat)
{
double sinLAT = sin(lat);
return (MathConst::WGS84_Major_a * sqrt(1.0 - MathConst::WGS84_SQR_EXC * sinLAT * sinLAT));
} // inline double radiusWGS84(double lat)
inline QPointF distance_in_meter_WGS84(const QPointF &start, const QPointF &end) // start, end in LonLat
{
// todo: prüfen ob Distanz zu groß, dann verbesserte Berechnung !!
double lat = (end.y() + start.y()) / 2.0;
double faktorLon = MathConst::WGS84_Major_a * cos(lat); // radiusWGS84(lat) * 2.0 * PI;
double faktorLat = MathConst::WGS84_Minor_b;
return QPointF(faktorLon * (end.x() - start.x()), faktorLat * (end.y() - start.y()));
} // QPointF distance_in_meter_WGS84(const QPointF &start, const QPointF &end)
inline double squareLength(const QPointF &v)
{
return v.x() * v.x() + v.y() * v.y();
} // inline double squareLength(const QPoint & v)
inline double length(const QPointF &v)
{
return sqrt(squareLength(v));
} // inline double length(const QPoint & v)
struct LOSentry // Defines 1 Entry for Line of Sight
{
LOSentry() = default;
LOSentry(double dist, double height) : _dist(dist), _height(height) { ; }
double &dist() { return _dist; }
double &height() { return _height; }
double dist() const { return _dist; }
double height() const { return _height; }
bool isUndefined() const { return std::isnan(_height); }
private:
double _dist = 0; // Distance from Start
double _height = -NAN;
}; /* LOSentry */
using Point3D = LtsUtils::QPoint3D; ///< x = lon ; y = lat , z = elevation/altitude in meters
using LOSVector = QVector<LOSentry>;
using Vec2dVector = QVector<QPointF>;
using Vec3dVector = QVector<Point3D>;
} // SituationMap
@@ -0,0 +1,531 @@
/**
* @RDE_HEADER@
* Manage and combine several ElevationMap
* $Id$
* $HeadURL$
* $Author$
*/
#include "elevation_map_manager.h"
#include "elevation_map.h"
// Qt
#include <QPointer>
#include <QFileInfo>
#include <QRectF>
#include <QPolygonF>
// system
#include <vector>
namespace SituationMap
{
static long s_counter{0};
//------------------------------------------------------------------------------------------------------------
// ElevationMapManager::Private
//------------------------------------------------------------------------------------------------------------
class ElevationMapManager::Private
{
public:
// fine to rough
std::vector<ElevationMap *> m_elevationMapCont;
QRectF m_simpleExtent;
};
//------------------------------------------------------------------------------------------------------------
// ElevationMapManager
//------------------------------------------------------------------------------------------------------------
ElevationMapManager::ElevationMapManager()
: BaseClass()
, d(new Private())
, m_logger(getLogger("ElevationMapManager"))
{
++s_counter;
TRACE_LOG(m_logger) << LOGFUNCTION << " START, s_counter=" << s_counter << " this=" << this;
TRACE_LOG(m_logger) << LOGFUNCTION << " END, s_counter=" << s_counter << " this=" << this;
}
ElevationMapManager::~ElevationMapManager()
{
--s_counter;
TRACE_LOG(m_logger) << LOGFUNCTION << " START, s_counter=" << s_counter << " this=" << this;
cleanupCurrentContent();
delete d;
d = nullptr;
TRACE_LOG(m_logger) << LOGFUNCTION << " END, s_counter=" << s_counter << " this=" << this;
}
int ElevationMapManager::init(const QStringList &filePaths_rough_to_fine)
{
NOTICE_LOG(m_logger) << LOGFUNCTION << " START" << " filePaths_rough_to_fine=" << filePaths_rough_to_fine.join(QStringLiteral(" ; "));
cleanupCurrentContent();
d->m_elevationMapCont.reserve(filePaths_rough_to_fine.size());
int cnt = 0;
for (const QString &filePath : filePaths_rough_to_fine)
{
QFileInfo fileInfo(filePath);
const QString &fileName = fileInfo.absoluteFilePath();
if (!fileInfo.exists())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " elevation data file \'" << fileName << "\' doesn't exists.";
continue;
}
if (!fileInfo.isReadable())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " elevation data file \'" << fileName << "\' isn't readable.";
continue;
}
// ctor will spawn thread via QtConcurrent and read file async:
d->m_elevationMapCont.insert(d->m_elevationMapCont.begin(), new ElevationMap(fileInfo));
++cnt;
} // for
NOTICE_LOG(m_logger) << LOGFUNCTION << " END" << " filePaths_rough_to_fine=" << filePaths_rough_to_fine.join(QStringLiteral(" ; "))
<< ", following number of files are going to be loaded: " << cnt;
return cnt;
}
void ElevationMapManager::cleanupCurrentContent()
{
qDeleteAll(d->m_elevationMapCont);
d->m_elevationMapCont.clear();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool ElevationMapManager::waitForInitialization()
{
for (ElevationMap *elevationMap : d->m_elevationMapCont)
elevationMap->waitForInitialization();
return isValid();
}
bool ElevationMapManager::isValid() const
{
bool allAreValid = true;
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
allAreValid = allAreValid && elevationMap->isValid();
// FATAL_LOG(m_logger) << LOGFUNCTION << " allAreValid = " << allAreValid;
return allAreValid;
}
double ElevationMapManager::elevation(double lon_rad, double lat_rad, bool *bIsCovered) const
{
// assume, that all children are ready
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
{
// qCritical() << " EMM::elevation: "
// << " lon_rad=" << lon_rad
// << " lat_rad=" << lat_rad
// << " (try: " << elevationMap->filename() << ")...";
double singleResult = elevationMap->elevation(lon_rad, lat_rad);
if (singleResult > -300) // -300 -> ausserhalb der Höhenkarte !!
{
// qCritical() << " EMM::elevation: elevation= " << singleResult << " (taken from: " << elevationMap->filename() << ")";
if (bIsCovered)
*bIsCovered = true;
return singleResult;
}
}
// DEBUG_LOG(m_logger) << LOGFUNCTION << " invalid= "
// << " lon_rad=" << lon_rad
// << " lat_rad=" << lat_rad;
if (bIsCovered)
*bIsCovered = false;
return std::numeric_limits<double>::min();
}
double ElevationMapManager::elevation(double lon_rad, double lat_rad, double defaultValue, bool *bIsCovered) const
{
bool bIsCoveredLocal = false;
const double elevationValue = elevation(lon_rad, lat_rad, &bIsCoveredLocal);
// in any case: if provided, transfer isCovered back to caller
if (bIsCovered)
*bIsCovered = bIsCoveredLocal;
// which value to be returned?
if (!bIsCoveredLocal)
return defaultValue;
return elevationValue;
}
QRectF ElevationMapManager::simpleUnitedExtent() const
{
if (d->m_simpleExtent.isNull())
{
bool bFirst = true;
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
{
const QRectF &singleExtent = elevationMap->extent();
if (bFirst)
{
bFirst = false;
d->m_simpleExtent = singleExtent;
// qCritical() << " bFirst.left " << singleExtent.left() << " bFirst.right " << singleExtent.right();
// qCritical() << " bFirst.top " << singleExtent.top() << " bFirst.bottom " << singleExtent.bottom();
} else {
// prefer following instead QRectF::united (top vs. bottom):
// qCritical() << " next.left " << singleExtent.left() << " secnextright " << singleExtent.right();
// qCritical() << " next.top " << singleExtent.top() << " next.bottom " << singleExtent.bottom();
d->m_simpleExtent.setLeft (std::min(d->m_simpleExtent.left(), singleExtent.left()));
d->m_simpleExtent.setTop (std::max(d->m_simpleExtent.top(), singleExtent.top())); // top - >use max !!!
d->m_simpleExtent.setBottom(std::min(d->m_simpleExtent.bottom(), singleExtent.bottom())); // bottom -> use min
d->m_simpleExtent.setRight (std::max(d->m_simpleExtent.right(), singleExtent.right()));
}
} // for
}
return d->m_simpleExtent;
}
bool ElevationMapManager::contains(const QPointF &point) const
{
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
{
if (elevationMap->contains(point))
return true;
}
return false;
}
void ElevationMapManager::LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (d->m_elevationMapCont.empty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no elevationMap";
return;
}
waitForInitialization();
QRectF simpleExtentLocal = simpleUnitedExtent();
// qCritical() << " simpleExtent.left " << simpleExtentLocal.left() << " simpleExtent.right " << simpleExtentLocal.right();
// qCritical() << " simpleExtent.top " << simpleExtentLocal.top() << " simpleExtent.bottom " << simpleExtentLocal.bottom();
if (!simpleExtentLocal.contains(start))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " start coordinate not within area"
<< ", start: x=" << start.x() << " ; y=" << start.y()
<< ", area: "
<< " left " << simpleExtentLocal.left() << ", right " << simpleExtentLocal.right()
<< " top " << simpleExtentLocal.top() << ", bottom " << simpleExtentLocal.bottom()
;
return; // ausserhalb der Höhenkarte !!
}
bool clipped = false;
double totalLng;
QPointF startG = start;
QPointF endG = end;
if (!simpleExtentLocal.contains(end)) // Clippen
{
clipped = true;
totalLng = length(endG - startG);
if (endG.x() < simpleExtentLocal.left())
{
double m = (endG.y() - startG.y()) / (endG.x() - startG.x());
double x = simpleExtentLocal.left();
endG.setX(x);
endG.setY(startG.y() + m * (x - startG.x()));
}
else if (endG.x() > simpleExtentLocal.right())
{
double m = (endG.y() - startG.y()) / (endG.x() - startG.x());
double x = simpleExtentLocal.right();
endG.setX(x);
endG.setY(startG.y() + m * (x - startG.x()));
}
if (endG.y() < simpleExtentLocal.bottom())
{
double m = (endG.x() - startG.x()) / (endG.y() - startG.y());
double y = simpleExtentLocal.bottom();
endG.setY(y);
endG.setX(startG.x() + m * (y - startG.y()));
}
else if (endG.y() > simpleExtentLocal.top())
{
double m = (endG.x() - startG.x()) / (endG.y() - startG.y());
double y = simpleExtentLocal.top();
endG.setY(y);
endG.setX(startG.x() + m * (y - startG.y()));
}
}
// Korrektursteigung aufgrund WGS84 Erdellipsoid, Lineare Approximation, Fehler bis 200 km: < 1.0m
double startRadius = radiusWGS84(startG.y());
double corrM = (radiusWGS84(endG.y()) - startRadius) / length(endG - startG);
//
// getSamplePoints(start, end, elevProfile);
// find best elevationMap for equested path {startG, endG}
//
// 1st find maps covering the desired pathG:
const QPolygonF pathG( QVector<QPointF>{startG, endG} );
std::vector<ElevationMap *> coveredElevationMaps;
coveredElevationMaps.reserve(d->m_elevationMapCont.size());
for (auto curItem : qAsConst(d->m_elevationMapCont))
{
if (curItem && curItem->intersects(pathG))
coveredElevationMaps.push_back(curItem);
} // for
if (m_logger.isDebugEnabled())
{
DEBUG_LOG(m_logger) << " coveredElevationMap.size() = " << coveredElevationMaps.size();
for (auto curItem : qAsConst(coveredElevationMaps))
DEBUG_LOG(m_logger) << " coveredElevationMap = " << curItem->filename();
}
// if no maps covers the desired path, stay on old approach: use most bottom elevation map:
if (coveredElevationMaps.empty())
coveredElevationMaps = d->m_elevationMapCont;
// 2nd: find elevation map with highest resolution to achieve best results:
using ELE_VEC_IT = std::vector<ElevationMap*>::iterator;
ELE_VEC_IT eleIt = coveredElevationMaps.begin();
for (ELE_VEC_IT curItem = coveredElevationMaps.begin()+1; curItem != coveredElevationMaps.end(); ++curItem)
{
ElevationMap *elePtr = *curItem;
if (!elePtr)
continue;
if (elePtr->elexelSize().first < (*eleIt)->elexelSize().first)
eleIt = curItem;
} // for
Q_ASSERT_X((*eleIt), "ElevationMapManager::LOSProfile", "eleIt failed");
Vec3dVector elevProfile;
(*eleIt)->getSamplePoints(start, end, elevProfile);
INFO_LOG(m_logger) << "Using ElevationMap '" << (*eleIt)->filename() << "'"
<< " (of size = " << d->m_elevationMapCont.size() << ")"
<< " with_elexelSize " << (*eleIt)->elexelSize().first
<< " -> # SamplePoints = " << elevProfile.size();
for (Vec3dVector::iterator itr = elevProfile.begin(); itr != elevProfile.end(); ++itr)
{
double dist = length(distance_in_meter_WGS84(start, itr->toPointF()));
double height = elevation(itr->x(), itr->y()); // use elevation over all seperate elevationMaps
height += corrM * dist; // WGS84 Erdellipsoid Korrektur
height -= (startRadius * (1 - cos(atan(dist / startRadius)))); // Einbeziehen der Erdkruemmung
// alternativ als Naeherung: height -= ( dist * dist) / (startRadius * 2.0);
losProfile.push_back(LOSentry(dist, height));
}
if (clipped)
losProfile.push_back(LOSentry(totalLng, -NAN));
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
ElevationMapManager::LineOfSight ElevationMapManager::lineOfSightCalculation(const LOSVector &losProfile,
double centerHat,
double objHat) const
{
// Analog zu SightFanImpl::calculateSightBeam
if (losProfile.size() < 2) // Startpunkt undefiniert oder ausserhalb der Karte
{
return LineOfSight::LOS_ERROR;
}
LOSVector::const_iterator itr = losProfile.begin();
const double centerHeight = itr->height() + centerHat;
double d1 = 0.0;
double height1 = itr->height();
// // überspringen bis _innerRadius erreicht ist !
// while( ++itr != losProfile.end())
// {
// double d2 = itr->dist(); // *EarthRadius;
// double height2 = itr->height();
// if( d2 >= m_internal->m_innerRadius)
// {
// height1 = height1 + (m_internal->m_innerRadius - d1) * ( height2 - height1)/(d2 - d1);
// d1 = m_internal->m_innerRadius;
// --itr;
// break;
// }
// d1 = d2;
// height1 = height2;
// }
// bool visible = true;
// SightMode mode = START;
d1 = itr->dist();
double curM = (height1 - centerHeight ) / d1; // bestimmende Steigung
// sBeam.add( SightEntry( d1, START) );
while (++itr != losProfile.end())
{
double d2 = itr->dist(); // *EarthRadius;
double height2 = itr->height();
if (std::isnan(height2)) // Undefined
{
return LineOfSight::LOS_UNDEFINED;
}
double hObj = (height2 + objHat - centerHeight );
double objM = hObj / d2; // Steigung bezogen auf Objekte( Objekte verdecken nicht !)
LineOfSight newMode = ((objM >= curM)) ? LineOfSight::LOS_VISIBLE : LineOfSight::LOS_INVISIBLE;
if (newMode == LineOfSight::LOS_INVISIBLE)
return LineOfSight::LOS_INVISIBLE;
// if (newMode != mode)
// {
// if ( (mode != LineOfSight::LOS_UNDEFINED) && (d2 != d1) )
// {
// // Korrekturwert für Distanz berechnen, unter Berücksichtigung der Objekthoehe !!
// double localM = (height2 - height1) /(d2 - d1);
// // localM == curM kann nicht auftreten, da newMode != mode
// double dCorr = (hObj - (curM * d2)) / (localM - curM);
// if (dCorr < 0.0)
// dCorr = 0.0;
// dCorr = d2 - dCorr;
// if (dCorr < d1)
// dCorr = d1;
// sBeam.add( SightEntry( dCorr, mode) );
// }
// mode = newMode;
// }
double terrM = (height2 - centerHeight) / d2; // Steigung bezogen auf Gelaende
if (terrM >= curM)
{
curM = terrM; // neue bestimmende Steigung
}
// height1 = height2;
// d1 = d2;
} // while
return LineOfSight::LOS_VISIBLE;
}
ElevationMapManager::LineOfSight ElevationMapManager::lineOfSightCalculation(const LtsUtils::QPoint3D &startPointGeo_absZ,
const LtsUtils::QPoint3D &endPointGeo_absZ)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << ", startPointGeo_absZ = " << startPointGeo_absZ << ", endPointGeo_absZ = " << endPointGeo_absZ;
if (!isValid())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, LtsElevationManager not valid";
return LineOfSight::LOS_ERROR;
}
// 1st: a) centerHat / startHat:
const double startHat = startPointGeo_absZ.z() - this->elevation(startPointGeo_absZ.x(), startPointGeo_absZ.y(), -10000);
if (startHat < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, startHat is negativ";
return LineOfSight::LOS_ERROR;
}
// 1st: b) endHat / objHat:
const double endHat = endPointGeo_absZ.z() - this->elevation(endPointGeo_absZ.x(), endPointGeo_absZ.y(), -10000);
if (endHat < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, objHat is negativ"
<< ", startPointGeo_absZ=" << startPointGeo_absZ
<< ", endPointGeo_absZ=" << endPointGeo_absZ;
return LineOfSight::LOS_ERROR;
}
SituationMap::ElevationMapManager::LineOfSight eleMapMgrResult = lineOfSightCalculation(startPointGeo_absZ.toPointF(), startHat,
endPointGeo_absZ.toPointF(), endHat);
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << ", startPointGeo = " << startPointGeo_absZ << ", endPointGeo = " << endPointGeo_absZ
<< " -> LineOfSight " << static_cast<int>(eleMapMgrResult);
return eleMapMgrResult;
}
ElevationMapManager::LineOfSight ElevationMapManager::lineOfSightCalculation(const QPointF &startPointGeo, double startHat,
const QPointF &endPointGeo, double endHat)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< ", startPointGeo = " << startPointGeo << ", startHat = " << startHat
<< ", endPointGeo = " << endPointGeo << ", endHat = " << endHat ;
if (!isValid())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, LtsElevationManager not valid";
return LineOfSight::LOS_ERROR;
}
if (startHat < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, startHat is negativ";
return LineOfSight::LOS_ERROR;
}
if (endHat < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, endHat is negativ";
return LineOfSight::LOS_ERROR;
}
// 1st: create LOSVector:
SituationMap::LOSVector losProfile;
LOSProfile(startPointGeo, endPointGeo, losProfile);
if (losProfile.size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, losProfile not valid"
<< ", losProfile.size = " << losProfile.size();
return LineOfSight::LOS_ERROR;
}
// 2nd: lineOfSightCalculation
SituationMap::ElevationMapManager::LineOfSight eleMapMgrResult = this->lineOfSightCalculation(losProfile, startHat, endHat);
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< ", startPointGeo = " << startPointGeo << ", startHat = " << startHat
<< ", endPointGeo = " << endPointGeo << ", endPointHat = " << endHat
<< " -> LineOfSight " << static_cast<int>(eleMapMgrResult);
return eleMapMgrResult;
}
} // SituationMap
@@ -0,0 +1,84 @@
/**
* @RDE_HEADER@
* Manage and combine several ElevationMap
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "elevation_map_helper.h"
#include <ElevationMap/situationmapelevationmap_export.h>
#include <Common/situation_map_logging.h>
#include <QObject>
namespace SituationMap
{
// forward:
class ElevationMap;
//------------------------------------------------------------------------------------------------------------
// ElevationMapManager
//------------------------------------------------------------------------------------------------------------
class SITUATIONMAPELEVATIONMAP_EXPORT ElevationMapManager final : public QObject
{
using BaseClass = QObject;
public:
ElevationMapManager();
ElevationMapManager(const ElevationMapManager &) = delete;
ElevationMapManager &operator = (const ElevationMapManager &) = delete;
~ElevationMapManager();
int init(const QStringList &filePaths_rough_to_fine);
void cleanupCurrentContent();
bool waitForInitialization();
bool isValid() const;
double elevation(double lon_rad, double lat_rad, bool *bIsCovered = nullptr) const;
double elevation(double lon_rad, double lat_rad, double defaultValue, bool *bIsCovered = nullptr) const;
// united extent of seperate files:
QRectF simpleUnitedExtent() const;
bool contains(const QPointF &point) const;
// Line of Sight Profile: berücksichtigt Erdkrümmung und WGS84 Erdellipsoid
void LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile);
/*! \name Line of Sight */
//@{
enum class LineOfSight { LOS_UNDEFINED,
LOS_ERROR,
LOS_VISIBLE,
LOS_INVISIBLE };
LineOfSight lineOfSightCalculation(const LOSVector &losProfile,
double centerHat,
double objHat) const;
LineOfSight lineOfSightCalculation(const LtsUtils::QPoint3D &startPointGeo_absZ,
const LtsUtils::QPoint3D &endPointGeo_absZ);
LineOfSight lineOfSightCalculation(const QPointF &startPointGeo, double startHat,
const QPointF &endPointGeo, double endHat);
//@}
protected:
class Private;
Private *d;
LOGGER_T m_logger; ///< Interface of the Logging-Facility
}; // ElevationMapManager
} // SituationMap
@@ -0,0 +1,229 @@
/**
* @RDE_HEADER@
* LineOfSightCalculation (L400)
* $Id$
* $HeadURL$
* $Author$
* Created by N. Thoden, NLE, 06.04.2020
*/
#include "line_of_sight_calculation.h"
#include "elevation_map.h"
#include <LtsCoordTrans/lts_coord_trans.h>
//
// ESRI / ARCGIS
// if you link libEsriCommonQt, you propably have to add ArcGISQt5Hack AND: # make sure it's loaded *before* libEsriCommonQt.so
// this may effect all executables linking situationMapElevationMap. CHECK!
//
// Qt
#include <QTimer>
#include <QElapsedTimer>
// some helper functions
inline Q_CONSTEXPR double pi() { return M_PI; }
inline Q_CONSTEXPR double deg2rad() { return pi() / 180.; }
inline Q_CONSTEXPR double rad2deg() { return 1. / deg2rad(); }
namespace SituationMap
{
LineOfSightCalculation::LineOfSightCalculation(ElevationMap *elevationMap)
: m_logger(getLogger("LineOfSightCalculation"))
, m_elevationMap(elevationMap)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
LineOfSightCalculation::~LineOfSightCalculation()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool LineOfSightCalculation::calculate(ObserverTargetData &observerTarget, unsigned int sampleIntervallMeter)
{
// same checks:
if (!m_elevationMap || !m_elevationMap->isValid())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no elevationMap configured or not valid";
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
return false;
}
if (!observerTarget.isObserverAndTargetValid())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " observer and/or target not valid";
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
return false;
}
if (observerTarget.observer().toPointF() == observerTarget.target().toPointF())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " observer and target are identical regarding x and y";
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
return false;
}
bool success = true;
QElapsedTimer timer;
if (m_logger.isInfoEnabled())
timer.start();
//
//
// consider using ElevationMap::LOSProfile
//
//
// determine how many iterations we need:
double distanceInMeter = distanceMeter(observerTarget.observer(),
observerTarget.target());
//ERROR_LOG(m_logger) << LOGFUNCTION << " distanceMeter = " << distanceInMeter;
int maxNumberOfIterations = distanceInMeter / sampleIntervallMeter; // check visibility every ~5m
// maxNumberOfIterations = 1000000;
if (maxNumberOfIterations<=0)
maxNumberOfIterations = 5;
double distanceFromObserverToTargetAsFraction = 0;
int i = 0;
while (i<maxNumberOfIterations)
{
++i;
/*
z-axis (Elevation) pCandidate
|---------- /
| ----------
| ----------
| ----------
| ----------
|------------------------------------------------------------ xy-axis
^ ^ ^ ^ ^ ^ ^ ^ samples (every ~5meters)
^ ^
ObserverPosition TargetPosition
On every sample position, check if directLineElevation (maximum) is
obstructed by elevationMapElevation (real value)
if (elevationMapElevation>directLineElevation) -> obstructed/break
*/
distanceFromObserverToTargetAsFraction = (double)i/maxNumberOfIterations;
const Point3D &pCandidate = movePoint(observerTarget.observer(),
observerTarget.target(),
distanceFromObserverToTargetAsFraction);
// {
// static Point3D oldCandidate;
// double distanceInMeter = distanceMeter(pCandidate, oldCandidate);
// ERROR_LOG(m_logger) << LOGFUNCTION << " distanceMeter = " << distanceInMeter;
// oldCandidate = pCandidate;
// }
// z is the elevation of a *direct* line:
const double directLineElevation = pCandidate.z();
const double elevationMapElevation = m_elevationMap->elevation(pCandidate.x(), pCandidate.y());
// Coord covered by elevationMap?
if (elevationMapElevation <= std::numeric_limits<int>::min())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, coordinate not covered be elevationData. Finish this LineOfSightCalculation."
<< " i=" << i
<< ", pCandidate = " << pCandidate;
// write back data
observerTarget.setObstacle(pCandidate);
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
// finish the loop:
success = false;
break;
}
// analyze / check visibility:
if (elevationMapElevation>directLineElevation)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " i=" << i
<< " break - pCandidate = " << pCandidate
<< " -> directLineElevation = " << directLineElevation
<< " -> elevationMapElevation = " << elevationMapElevation;
// write result
observerTarget.setObstacle(pCandidate);
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Obstructed);
// finish the loop:
break;
} else {
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Visible);
}
} // while
if (m_logger.isInfoEnabled())
{
INFO_LOG(m_logger) << LOGFUNCTION << " END"
<< ", success = " << success
<< ", " << i << " of "<< maxNumberOfIterations << " iterations"
<< ", distanceFromObserverToTargetAsFraction = " << distanceFromObserverToTargetAsFraction
<< ", pCandidate=" << observerTarget.obstacle()
<< ", lineOfSightVisibility=" << static_cast<int>(observerTarget.lineOfSightVisibility())
<< ", took [ms] " << timer.elapsed();
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << ", success = " << success;
return success;
}
Point3D LineOfSightCalculation::movePoint(const Point3D &oberserver, const Point3D &target, double distanceFromObserverToTargetAsFraction) // 0.0 ... 1.0
{
// positions are lon/lat @ rad.
// for evaluation we do that very simple:
// strange, but: using Point3D seems to be faster then using QPointF
const Point3D &dist = target - oberserver;
const Point3D &point = oberserver + (dist * distanceFromObserverToTargetAsFraction);
return point;
}
double LineOfSightCalculation::distanceMeter(const Point3D &oberserver, const Point3D &target)
{
// Try to avoid the dependency to ESRI (keep ArcGISQt5Hack in mind)
// And good accuracy is not required here
// use LtsCoordTrans::distance
// Esri::ArcGISRuntime::Point geom1(oberserver.x()*rad2deg(), oberserver.y()*rad2deg(), oberserver.z(), Esri::ArcGISRuntime::SpatialReference::wgs84());
// Esri::ArcGISRuntime::Point geom2(target.x() *rad2deg(), target.y() *rad2deg(), target.z() , Esri::ArcGISRuntime::SpatialReference::wgs84());
// Esri::ArcGISRuntime::GeometryEngine *gEngine = Esri::ArcGISRuntime::GeometryEngine::instance();
// Esri::ArcGISRuntime::GeodeticDistanceResult geodeticDistanceResult = gEngine->distanceGeodetic(geom1, geom2,
// Esri::ArcGISRuntime::LinearUnitId::Meters,
// Esri::ArcGISRuntime::AngularUnitId::Degrees,
// Esri::ArcGISRuntime::GeodeticCurveType::Geodesic);
// double distance = geodeticDistanceResult.distance();
double distance = LtsCoordTrans::distance(oberserver.toPointF(), target.toPointF());
return distance;
}
} // namespace SituationMap
@@ -0,0 +1,92 @@
/**
* @RDE_HEADER@
* LineOfSightCalculation (L400)
* $Id$
* $HeadURL$
* $Author$
* Created by N. Thoden, NLE, 06.04.2020
*/
#pragma once
#include <ElevationMap/situationmapelevationmap_export.h>
#include <Common/situation_map_logging.h>
#include <LtsUtilsCore/qpoint3d.h>
using Point3D = LtsUtils::QPoint3D; ///< x = lon ; y = lat , z = elevation/altitude in meters
namespace SituationMap
{
// forward
class ElevationMap;
//----------------------------------------------------------------------------
/*!
\brief Define visibility.
*/
enum class LineOfSightVisibility
{
Undefined, /*!< no data at that location? */
Visible,
Obstructed
};
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
class SITUATIONMAPELEVATIONMAP_EXPORT ObserverTargetData
{
public:
explicit ObserverTargetData(const Point3D &oberserver = Point3D(), // z-value: incl. observerHeight
const Point3D &target = Point3D()) // z-value: incl. targetHeight
: m_oberserver(oberserver)
, m_target(target)
{}
const Point3D &observer() const { return m_oberserver; }
const Point3D &target() const { return m_target; }
const Point3D &obstacle() const { return m_obstacle; }
void setObstacle(const Point3D &obstacle) { m_obstacle = obstacle; }
LineOfSightVisibility lineOfSightVisibility() const { return m_visible; }
void setLineOfSightVisibility(const LineOfSightVisibility &visible) { m_visible = visible; }
bool isObserverAndTargetValid() const { return (!m_oberserver.isNull()) && (!m_target.isNull()); }
private:
Point3D m_oberserver;
Point3D m_target;
Point3D m_obstacle;
LineOfSightVisibility m_visible = LineOfSightVisibility::Undefined;
};
//----------------------------------------------------------------------------
class SITUATIONMAPELEVATIONMAP_EXPORT LineOfSightCalculation
{
public:
explicit LineOfSightCalculation(ElevationMap *elevationMap);
~LineOfSightCalculation();
bool calculate(ObserverTargetData &observerTarget, unsigned int sampleIntervallMeter = 5);
protected:
static Point3D movePoint(const Point3D &oberserver,
const Point3D &target,
double distanceFromObserverToTargetAsFraction);
static double distanceMeter(const Point3D &oberserver,
const Point3D &target);
private:
LOGGER_T m_logger; ///< Interface of the Logging-Facility
ElevationMap *m_elevationMap = nullptr;
ObserverTargetData m_observerTarget;
};
} // namespace SituationMap
+9
View File
@@ -0,0 +1,9 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# ADD_SUBDIRECTORY(Viewshed3D)
+43
View File
@@ -0,0 +1,43 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# Evaluation application for 3D viewshed
FIND_PACKAGE(ArcGIS REQUIRED)
INCLUDE_DIRECTORIES(${ARCGIS_INCLUDE_DIR}/arcgis)
SET(EXE_SRCS
main.cpp
ViewshedLocation.cpp
)
SET(EXE_HDRS
ViewshedLocation.h
)
SOURCE_GROUP(EvalViewshed3DApp FILES ${EXE_SRCS} ${EXE_HDRS})
NGL_ADD_EXECUTABLE(WS NO_TRANSLATION EvalViewshed3DApp ${EXE_SRCS} ${EXE_HDRS})
NGL_TARGET_LINK_LIBRARIES(
EvalViewshed3DApp
ArcGIS::ArcGIS
Qt5::Core
Qt5::Gui
Qt5::Widgets
Qt5::Network
)
IF(MSVC)
# Configure the template file
SET(VS_USER_FILE EvalViewshed3DApp.vcxproj.user)
configure_file( ../../SituationMap.vcxproj.user.in ${CMAKE_CURRENT_BINARY_DIR}/${VS_USER_FILE} @ONLY)
ENDIF(MSVC)
NGL_INSTALL_TARGET(EvalViewshed3DApp)
@@ -0,0 +1,58 @@
#-------------------------------------------------
# Copyright 2015 Esri.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#-------------------------------------------------
mac {
cache()
}
CONFIG += c++11 esri_runtime_qt100_0_0 debug
QT += core gui opengl xml network positioning sensors
win32:CONFIG += \
embed_manifest_exe
TARGET = LocationViewshed
TEMPLATE = app
SOURCES += \
main.cpp \
ViewshedLocation.cpp
HEADERS += \
ViewshedLocation.h
win32 {
INCLUDEPATH += "C:/Program Files (x86)/ArcGIS SDKs/Qt100.0/sdk/include"
debug:LIBPATH += "C:/Program Files (x86)/ArcGIS SDKs/Qt100.0/sdk/windows/x64/lib/Debug"
release:LIBPATH += "C:/Program Files (x86)/ArcGIS SDKs/Qt100.0/sdk/windows/x64/lib/Release"
debug:LIBS += -lEsriCommonQtd
release:LIBS += -lEsriCommonQt
debug:LIBS += -lEsriRuntimeQtd
release:LIBS += -lEsriRuntimeQt
}
linux {
INCLUDEPATH += /usr/include/arcgis
LIBS += -lEsriCommonQt
LIBS += -lEsriRuntimeQt
LIBS += -lc++
}
macx {
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.11
}
@@ -0,0 +1,274 @@
/**
* @RDE_HEADER@
* Declaration/Definition
* $Id$
* $HeadURL$
* $Author$
*/
// [WriteFile Name=ViewshedLocation, Category=Analysis]
// [Legal]
// Copyright 2017 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]
#include "ViewshedLocation.h"
#include "ArcGISTiledElevationSource.h"
#include "Scene.h"
#include "SceneGraphicsView.h"
#include "LocationViewshed.h"
#include "Camera.h"
#include "Point.h"
#include "AnalysisOverlay.h"
#include "QColor"
using namespace Esri::ArcGISRuntime;
ViewshedLocation::ViewshedLocation(QObject* parent /* = nullptr */):
QObject(parent)
{
}
void ViewshedLocation::init(Esri::ArcGISRuntime::SceneGraphicsView* sceneView)
{
m_sceneView = sceneView;
// Register classes for QML
// qmlRegisterType<SceneQuickView>("Esri.Samples", 1, 0, "SceneView");
// qmlRegisterType<ViewshedLocation>("Esri.Samples", 1, 0, "ViewshedLocationSample");
Surface* surface = new Surface(this);
surface->elevationSources()->append(
new ArcGISTiledElevationSource(
QUrl(QStringLiteral("http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer")),
this));
m_sceneView->arcGISScene()->setBaseSurface(surface);
// set initial viewpoint
setInitialViewpoint();
// connect signals
connectSignals();
}
void ViewshedLocation::setInitialViewpoint()
{
// Set a viewpoint
double x = 6.86088;
double y = 45.3604;
double z = 3582.55;
Point point(x, y, z, SpatialReference(4326));
double heading = 345;
double pitch = 70;
double roll = 0;
Camera camera(point, heading, pitch, roll);
m_sceneView->setViewpointCamera(camera);
}
void ViewshedLocation::connectSignals()
{
// on mouse click perform the location viewshed
connect(m_sceneView, &SceneGraphicsView::mouseClicked, this, [this](QMouseEvent& event)
{
if (!m_locationViewshed[0])
createViewshed(event.x(), event.y());
else
{
for (int i = 0; i < 3; ++i)
{
const Point pt = m_sceneView->screenToBaseSurface(event.x(), event.y());
m_locationViewshed[i]->setLocation(pt);
}
}
});
connect(m_sceneView, &SceneGraphicsView::mousePressedAndHeld, this, [this](QMouseEvent& event)
{
if (!m_locationViewshed[0])
createViewshed(event.x(), event.y());
m_calculating = true;
});
connect(m_sceneView, &SceneGraphicsView::mouseMoved, this, [this](QMouseEvent& event)
{
if (m_calculating)
{
for (int i = 0; i < 3; ++i)
{
const Point pt = m_sceneView->screenToBaseSurface(event.x(), event.y());
m_locationViewshed[i]->setLocation(pt);
}
}
});
connect(m_sceneView, &SceneGraphicsView::mouseReleased, this, [this](QMouseEvent)
{
m_calculating = false;
});
}
void ViewshedLocation::createViewshed(double x, double y)
{
m_analysisOverlay = new AnalysisOverlay(this);
m_sceneView->analysisOverlays()->append(m_analysisOverlay);
const Point pt = m_sceneView->screenToBaseSurface(x, y);
qCritical() << " pt=";
qCritical() << " pt=" << pt.x();
qCritical() << " pt=" << pt.y();
qCritical() << " pt=" << pt.z();
for (int i = 0; i < 3; ++i)
{
double heading = i * 120.0;
m_locationViewshed[i] = new LocationViewshed(pt
, heading
, 90.0 // pitch
, 120.0 // horizontalAngle
, 90.0 // verticalAngle
, 10.0 // minDistance
, 20000
, this);
m_locationViewshed[i]->setVisible(m_viewshedVisible);
// Add the Viewshed to the Analysis Overlay
m_analysisOverlay->analyses()->append(m_locationViewshed[i]);
m_locationViewshed[i]->setFrustumOutlineVisible(true);
// QColor frustumColor(0, 0, 0, 255);
// m_locationViewshed->setFrustumOutlineColor(frustumColor);
}
return;
}
// Getters/Setters for each Q_PROPERTY
bool ViewshedLocation::isViewshedVisible() const
{
return m_viewshedVisible;
}
void ViewshedLocation::setViewshedVisible(bool viewshedVisible)
{
for (int i = 0; i < 3; ++i)
{
if (m_locationViewshed[i])
{
if (m_locationViewshed[i]->isVisible() == viewshedVisible)
{
continue;
}
m_locationViewshed[i]->setVisible(viewshedVisible);
}
}
if (m_viewshedVisible != viewshedVisible)
{
m_viewshedVisible = viewshedVisible;
emit viewshedVisibleChanged();
}
}
bool ViewshedLocation::isFrustumOutlineVisible() const
{
return m_locationViewshed[0] ? m_locationViewshed[0]->isFrustumOutlineVisible() : m_frustumVisible;
}
void ViewshedLocation::setFrustumOutlineVisible(bool frustumVisible)
{
for (int i = 0; i < 3; ++i)
{
if (m_locationViewshed[i])
{
if (m_locationViewshed[i]->isFrustumOutlineVisible() == frustumVisible)
{
continue;
}
m_frustumVisible = frustumVisible;
m_locationViewshed[i]->setFrustumOutlineVisible(frustumVisible);
}
}
if (m_frustumVisible != frustumVisible)
{
m_frustumVisible = frustumVisible;
emit frustumVisibleChanged();
}
}
double ViewshedLocation::minDistance() const
{
return m_locationViewshed[0] ? m_locationViewshed[0]->minDistance() : m_minDistance;
}
void ViewshedLocation::setMinDistance(double minDistance)
{
for (int i = 0; i < 3; ++i)
{
if (m_locationViewshed[i])
{
if (m_locationViewshed[i]->minDistance() == minDistance)
{
continue;
}
m_locationViewshed[i]->setMinDistance(minDistance);
}
}
if (m_minDistance != minDistance)
{
m_minDistance = minDistance;
emit minDistanceChanged();
}
}
double ViewshedLocation::maxDistance() const
{
return m_locationViewshed[0] ? m_locationViewshed[0]->maxDistance() : m_maxDistance;
}
void ViewshedLocation::setMaxDistance(double maxDistance)
{
for (int i = 0; i < 3; ++i)
{
if (m_locationViewshed[i])
{
if (m_locationViewshed[i]->maxDistance() == maxDistance)
{
continue;
}
m_locationViewshed[i]->setMaxDistance(maxDistance);
}
}
if (m_maxDistance != maxDistance)
{
m_maxDistance = maxDistance;
emit maxDistanceChanged();
}
}
@@ -0,0 +1,99 @@
/**
* @RDE_HEADER@
* Declaration/Definition
* $Id$
* $HeadURL$
* $Author$
*/
// [WriteFile Name=ViewshedLocation, Category=Analysis]
// [Legal]
// Copyright 2017 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]
#ifndef VIEWSHEDLOCATION_H
#define VIEWSHEDLOCATION_H
#include <QObject>
#include <QColor>
namespace Esri
{
namespace ArcGISRuntime
{
class SceneGraphicsView;
class LocationViewshed;
class AnalysisOverlay;
}
}
class ViewshedLocation : public QObject
{
Q_OBJECT
public:
explicit ViewshedLocation(QObject* parent = nullptr);
~ViewshedLocation() = default;
// void componentComplete() Q_DECL_OVERRIDE;
void init(Esri::ArcGISRuntime::SceneGraphicsView* sceneView);
Q_PROPERTY(bool viewshedVisible READ isViewshedVisible WRITE setViewshedVisible NOTIFY viewshedVisibleChanged)
Q_PROPERTY(bool frustumVisible READ isFrustumOutlineVisible WRITE setFrustumOutlineVisible NOTIFY frustumVisibleChanged)
Q_PROPERTY(double minDistance READ minDistance WRITE setMinDistance NOTIFY minDistanceChanged)
Q_PROPERTY(double maxDistance READ maxDistance WRITE setMaxDistance NOTIFY maxDistanceChanged)
bool isViewshedVisible() const;
void setViewshedVisible(bool viewshedVisible);
bool isFrustumOutlineVisible() const;
void setFrustumOutlineVisible(bool frustumVisible);
double minDistance() const;
void setMinDistance(double minDistance);
double maxDistance() const;
void setMaxDistance(double maxDistance);
signals:
void viewshedVisibleChanged();
void frustumVisibleChanged();
void minDistanceChanged();
void maxDistanceChanged();
private:
void connectSignals();
void setInitialViewpoint();
void createViewshed(double x, double y);
Esri::ArcGISRuntime::SceneGraphicsView *m_sceneView = nullptr;
Esri::ArcGISRuntime::LocationViewshed *m_locationViewshed[3] = { nullptr, nullptr, nullptr };
Esri::ArcGISRuntime::AnalysisOverlay *m_analysisOverlay = nullptr;
bool m_viewshedVisible = true;
bool m_frustumVisible = false;
double m_minDistance = 50;
double m_maxDistance = 1000;
double m_horizontalAngle = 45;
double m_veriticalAngle = 90;
double m_heading = 0;
double m_pitch = 90;
bool m_calculating = false;
};
#endif // VIEWSHEDLOCATION_H
+245
View File
@@ -0,0 +1,245 @@
/*
**
** @RDE_HEADER@
** Showing artefacts when drawing 3D map.
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Linux, Qt 5.9. ArcGISRuntimeQt 100.1
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 08.11.2017, JT : Initial
**
** -----------------------------------------------------------------------------------------------
*/
#include <QTimer>
#include <QtCore/QDir>
#include <QtCore/QUrl>
#include <QtCore/QDebug>
#include <QtGui/QSurface>
#include <QtNetwork/QNetworkProxy>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDesktopWidget>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QGraphicsScene>
#include <QtWidgets/QGraphicsProxyWidget>
#include <QtWidgets/QMainWindow>
#include <Map.h>
#include <Scene.h>
#include <SceneGraphicsView.h>
#include <GraphicsOverlay.h>
#include <GeoView.h>
#include <Basemap.h>
#include <ArcGISTiledLayer.h>
#include <Layer.h>
#include <GraphicsOverlay.h>
#include "ViewshedLocation.h"
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
class MapWindow : public QWidget
{
Esri::ArcGISRuntime::Basemap * m_basemap;
Esri::ArcGISRuntime::Scene * m_scene;
Esri::ArcGISRuntime::SceneGraphicsView * m_sceneGraphicsView;
Esri::ArcGISRuntime::GeoView * m_mapView;
Esri::ArcGISRuntime::GraphicsOverlay * m_graphicsOverlay;
Qt::MouseButton m_pressedMouseButton;
QPoint m_mouseMoveRefPos;
Esri::ArcGISRuntime::TaskWatcher m_pickingTask;
bool m_pendingRequest;
public:
MapWindow() : QWidget(), m_graphicsOverlay(nullptr), m_pickingTask(), m_pendingRequest(false)
{
m_pressedMouseButton = Qt::MouseButton::NoButton;
m_mouseMoveRefPos = QPoint();
m_basemap = new Esri::ArcGISRuntime::Basemap(this);
m_scene = new Esri::ArcGISRuntime::Scene(m_basemap,this);
connect( m_basemap, &Esri::ArcGISRuntime::Map::errorOccurred , this, &MapWindow::onErrorBasemap );
connect( m_scene , &Esri::ArcGISRuntime::Scene::errorOccurred, this, &MapWindow::onErrorScene );
connect( m_scene , &Esri::ArcGISRuntime::Scene::doneLoading , this, &MapWindow::onDoneLoading );
m_sceneGraphicsView = nullptr;
try
{
m_sceneGraphicsView = new Esri::ArcGISRuntime::SceneGraphicsView(); // no parent,
m_sceneGraphicsView->setObjectName(QLatin1String("EsriSceneView"));
m_sceneGraphicsView->setFrameShape(QFrame::NoFrame); // frameless
}
catch (std::exception &stdEx)
{
const char *what = stdEx.what();
if (what)
qCritical()<< "MapWindow init SceneGraphicsView: std Exception " << " what: '" << what << "'";
else
qCritical() << "MapWindow init SceneGraphicsView: std Exception";
throw; // re-throw
}
catch (...)
{
qCritical() << "MapWindow init SceneGraphicsView: unknown Exception";
throw; // re-throw
}
if (!m_sceneGraphicsView)
return;
m_sceneGraphicsView->setArcGISScene(m_scene);
QHBoxLayout *layout = new QHBoxLayout(this);
layout->addWidget(m_sceneGraphicsView);
initMapLayer(QLatin1String("http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"));
initMapLayer(QLatin1String("http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"));
Esri::ArcGISRuntime::Camera camera(28.4, 83.9, 10010.0, 10.0, 80.0, 300.0);
m_sceneGraphicsView->setViewpointCameraAndWait(camera);// set the viewpoint
/*
QPushButton * aButton = new QPushButton(tr("Click me")); // toplevel widget
QGraphicsProxyWidget *proxy = m_sceneGraphicsView->QGraphicsView::scene()->addWidget(aButton);
proxy->setOpacity(0.99);
connect( aButton, &QPushButton::clicked, this, []() {qCritical() << "A Button has been clicked!";} );
*/
QTimer *timer = new QTimer(this);
timer->setSingleShot(true);
timer->setInterval(5000);
connect(timer, &QTimer::timeout, this, [this]() {
qCritical() << "Create viewshed ...";
ViewshedLocation * vLoc = new ViewshedLocation(this);
vLoc->init(m_sceneGraphicsView);
});
timer->start();
} // MapWindow()
~MapWindow() = default;
void initMapLayer( const QString &mapServiceUrl )
{
Esri::ArcGISRuntime::ArcGISTiledLayer *tiledLayer = new Esri::ArcGISRuntime::ArcGISTiledLayer(QUrl(mapServiceUrl), this);
tiledLayer->setName(mapServiceUrl);
tiledLayer->setObjectName(tiledLayer->name());
m_basemap->baseLayers()->append(tiledLayer);
} // void initMapLayer()
private:
void onDoneLoading(const Esri::ArcGISRuntime::Error &loadError)
{
} // void onDoneLoading(const Esri::ArcGISRuntime::Error &loadError)
void onErrorBasemap(const Esri::ArcGISRuntime::Error &error)
{
qCritical() << " ---EsriError,Basemap --- occured: "
<< " code=" << error.code()
<< " domain=" << (int)error.domain()
<< " extendedErrorType=" << (int)error.extendedErrorType()
<< ", message='" << error.message() << "'";
} // void onErrorBasemap(const Esri::ArcGISRuntime::Error &error)
void onErrorScene(const Esri::ArcGISRuntime::Error &error)
{
qCritical() << " ---EsriError, Scene --- occured: "
<< " code=" << error.code()
<< " domain=" << (int)error.domain()
<< " extendedErrorType=" << (int)error.extendedErrorType()
<< ", message='" << error.message() << "'";
} // void onErrorScene(const Esri::ArcGISRuntime::Error &error)
}; // MapWindow
int main(int argc, char* argv[])
{
QApplication app(argc,argv);
// ESRI :
#ifdef Q_OS_WIN
// Force usage of OpenGL ES through ANGLE on Windows
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#endif
// : ESRI
#define PROXY
#ifdef PROXY
QNetworkProxy proxy;
proxy.setType(QNetworkProxy::HttpProxy);
proxy.setHostName(QStringLiteral("proxy-rde"));
proxy.setPort(8080);
proxy.setUser(QStringLiteral("norbert.thoden@rheinmetall.com"));
proxy.setPassword(QStringLiteral("RDEWWW11"));
QNetworkProxy::setApplicationProxy(proxy);
#endif
MapWindow * mapWin = new MapWindow();
QDesktopWidget wid;
int width = mapWin->frameGeometry().width();
int height = mapWin->frameGeometry().height();
int screenWidth = wid.screen()->width();
int screenHeight = wid.screen()->height();
mapWin->setGeometry((screenWidth / 2) - (width / 2), (screenHeight / 2) - (height / 2), width, height);
mapWin->show();
app.setQuitOnLastWindowClosed(true);
int retval = app.exec();
delete mapWin;
return retval;
} // main
+46
View File
@@ -0,0 +1,46 @@
#
# $Id$
# $HeadURL$
# $Author$
#
FIND_PACKAGE(ArcGIS REQUIRED)
# LIBRARY
SET(FunctionDialog_SRCS
function_dialog.cpp
simple_esri_layer.cpp
)
SET(FunctionDialog_HDRS
function_dialog_export.h
function_dialog.h
simple_esri_layer.h
)
SET(FunctionDialog_ICONS
state_icon_b.xpm
state_icon_a.xpm
state_icon_c.xpm
)
SOURCE_GROUP(FunctionDialog FILES ${FunctionDialog_SRCS} ${FunctionDialog_HDRS})
NGL_ADD_LIBRARY(WS situationMapFunctionDialog SHARED ${FunctionDialog_SRCS} ${FunctionDialog_HDRS})
NGL_TARGET_LINK_LIBRARIES(situationMapFunctionDialog
PRIVATE
NGLLogger
LtsCoordTrans
LtsWidgets
advancedSymbologyGui
PUBLIC
ArcGIS::ArcGIS
situationMap
situationMapObjects
situationMapPortal
Qt5::Core
Qt5::Widgets
)
NGL_INSTALL_TARGET(situationMapFunctionDialog)
File diff suppressed because it is too large. Load diff
+289
View File
@@ -0,0 +1,289 @@
/**
* @RDE_HEADER@
* FunctionDialog
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "function_dialog_export.h"
#include <Map/map.h>
#include <QWidget>
#include <Symbology/symbol_dictionary.h>
// ESRI
#include <arcgis/Map.h>
#include <arcgis/MapGraphicsView.h>
#include <arcgis/GraphicsOverlay.h>
// #define USE_LOCAL_SERVER
class QStandardItemModel;
//----------------------------------------------------------------------------
namespace SituationMap
{
namespace RB
{
class RubberbandBase;
}
class Map;
// TODO: nur fuer Tests exportiert
class FUNCTIONDIALOG_EXPORT FunctionDialog : public QWidget
{
Q_OBJECT
public:
explicit FunctionDialog(Esri::ArcGISRuntime::Map *esriMap,
Esri::ArcGISRuntime::MapGraphicsView *esriView,
QWidget *parent);
explicit FunctionDialog(SituationMap::Map *map);
virtual ~FunctionDialog();
static void addButtonToMap(SituationMap::Map *map, bool isVisible = true);
void init();
void setGraphicsLayer(Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer);
void setMapPositionString(const QString &mapPosition);
void setPixelSizeString(const QString &text);
void addMapPositionString(const QString &mapPosition);
FunctionDialog(const FunctionDialog &other) = delete; // No copy
FunctionDialog &operator=(const FunctionDialog &other) = delete; // No copy
protected:
void addSimpleLayerTab();
void addLogicalLayerTab();
void addLayerPerformanceTab();
void addGraphicsTab();
void addGraphics3DTab();
void addMessageTab();
void addMapObjectTab();
void addRubberbandTab();
void addRubberband3DTab();
void addToolsTab();
void addViewshedTab();
void addOverlayPlanTab();
void addIconRenderTab();
void addPortalTab();
void addMovePointLuxemburgTab();
void getRotationAndAngle(const QPointF &sectStart, const QPointF &sectEnd, double &rotationDegOut, double &openAngleDegOut);
// void addYourTab();
Esri::ArcGISRuntime::Graphic *createCube(const SituationMap::PositionCont &mapPosCont,
int baseHeight,
double objHeight,
const QString &partyNameValue = QString());
public Q_SLOTS:
void onDestroyed();
void onLayerPerfCreateLayer();
void onGenerateGraphics();
void onGenerateCube();
void onGenerateCubeArray();
void onGenerateStackedCubes();
void onGenerateGraphicsKristenStrandford();
void onGenerateUniqueVaueRendererMountingPoints();
void onGenerate3DGraphicSphereRENDERER();
void onSphereOpacityChangedRENDERER(int opacityValue);
void onGenerate3DGraphicSphere();
void onSphereOpacityChanged(int opacityValue);
void onSphereZValueChanged(int ZValue);
void onGenerate3DGraphicCone();
void onConeOpacityChanged(int opacityValue);
void onConeZValueChanged(int ZValue);
void onConeHeadingChanged(float angle);
void onConeRollChanged(float angle);
void onConePitchChanged(float angle);
void on3dModel();
void on3dModelZValueChanged(int ZValue);
void onGenerate3DGraphicConeUniqueValueRenderer();
void onAddCivilSymbols();
void onMessage();
void onMessageSelect();
void onAddSymbol();
void onSomeParticipants();
void onRubberbandApply(RB::RubberbandBase *);
void onRubberbandAbort(RB::RubberbandBase *);
void onRubberband3DApply(RB::RubberbandBase *);
void onRubberband3DAbort(RB::RubberbandBase *);
void onRubberbandDefineArrow();
void onRubberbandDefineEllipse();
void onRubberbandBoobyTrapSector();
void onRubberbandCheckCoordinates();
void onRubberbandStateSelect();
void onRubberbandTwoInOne();
void onRectCheckCoordinates();
void onPolygonCreate();
void onPolylineCreate();
void onPolylineUpdate();
void onTextCreate();
void onTextUpdate();
void onMapObjectIndicatorCreate();
void onParticipantGetPosition();
void onParticipantGetPositionApplied(RB::RubberbandBase *rubberband = nullptr);
bool createParticipant(const Point3D &origin,
const QString &debugInfo);
void onParticipantCreate();
void onParticipantUpdate();
void onAreaFireCreate();
void onAreaFireUpdate();
void onBuildingCreate();
void onBuildingUpdate();
void onBiologicalAgentCreate();
void onBiologicalAgentUpdate();
void onChemicalAgentCreate();
void onCubeCreate();
void onDangerAreaCreate();
void onDangerAreaUpdate();
void onFunctionalAreaCreate();
void onFunctionalAreaUpdate();
void onGeoImageCreate();
void onMapObjectClicked(const SituationMap::Map::RefPointerMapObjectList &mapObjList,
const QPointF &viewportPosition);
void onSoundAreaCreate();
void onSoundAreaUpdate();
void onHitLineCreate();
void onHitLineUpdate();
void onLineOfSightLineCreate();
void onMineCreate();
void onMineUpdate();
void onMineFieldCreate();
void onMineFieldUpdate();
void onNuclearCreate();
void onNuclearUpdate();
void onChargeEffectCreate();
void onChargeEffectUpdate();
void onBoobyTrapCreate();
void onBoobyTrapUpdate();
void onSingleFireCreate();
void onSingleFireUpdate();
void onShowBasePoint();
void onShowPolizei();
void onObjectIndicator();
void onMeasureLength();
void onStartLocationDisplay();
void onStopLocationDisplay();
void onLoadFile();
void onPortal();
void onMovePoint();
#ifdef USE_LOCAL_SERVER
void onStartLocalService();
void onStopLocalService();
void onStartViewshedSvc();
void onStopViewshedSvc();
void onViewshedInteractive();
void onViewshed();
#endif // USE_LOCAL_SERVER
void onSightFan();
void onViewshedSightFan();
void onLoadPlan();
void onOverlayVisiChanged(bool checked);
void onRemovePlan();
void onRemoveAllPlans();
void onToPdf();
void onDump();
void onOverviewMap();
void onBackupOms();
void onRestoreOms();
void onRemove();
void onRemoveAll();
void onToggleGrid();
void onToggleVisibility();
void onToggleVisibilityTechn();
void onToggleVisibilityTact();
void onToggleSelection();
void onTogglePicking();
void onToggleBoundingBox();
void onToggleBB2();
void onMapRotationChanged();
void onSymbolSizeChanged();
void onSymbolOpacityChanged();
void onDrawOrderChanged();
//void onBuildingPERFORMANCE();
void onMouseWindowPositionChanged(int x, int y);
void onMouseMapPositionChanged(const Point3D &mapPos, bool isValid);
void onMouseGeoPositionChanged(const Point3D &geoPos, bool isValid);
void onExtendChanged();
private:
class Private;
/**
* The private d-pointer to not break BC when changing internals of this class
*/
Private *d = nullptr;
};
} // namespace SituationMap
@@ -0,0 +1,21 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <qglobal.h>
#ifndef FUNCTIONDIALOG_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define FUNCTIONDIALOG_EXPORT
# else
# if defined(MAKE_SITUATIONMAPFUNCTIONDIALOG_LIB)
# define FUNCTIONDIALOG_EXPORT Q_DECL_EXPORT
# else
# define FUNCTIONDIALOG_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
@@ -0,0 +1,378 @@
/**
* @RDE_HEADER@
* FunctionDialog
* $Id$
* $HeadURL$
* $Author$
*/
#include "simple_esri_layer.h"
#include <arcgis/Map.h>
#include <MapImpl/map_impl.h>
#include <arcgis/Map.h>
#include <arcgis/MapGraphicsView.h>
#include <arcgis/LayerListModel.h>
#include <arcgis/ArcGISTiledLayer.h>
// for overview
#include <QDebug>
#include <QDialog>
#include <QLabel>
#include <QCheckBox>
#include <QPushButton>
#include <QSlider>
#include <QGridLayout>
#include <QStandardItemModel>
namespace SituationMap
{
Esri::ArcGISRuntime::Layer *getEsriBasemap_Layer(Esri::ArcGISRuntime::Map *map,
const QString &layername)
{
if (!(map &&
map->basemap() &&
map->basemap()->baseLayers())
)
return nullptr;
Esri::ArcGISRuntime::Layer *layerFound = nullptr;
const Esri::ArcGISRuntime::LayerListModel *model = map->basemap()->baseLayers();
for (int i = 0; i < model->size(); ++i)
{
const Esri::ArcGISRuntime::Layer *curLayer = model->at(i);
const QString &curName = curLayer->name();
if (QString::compare(layername, curName) == 0)
{
layerFound = model->at(i);
break;
}
} // for
return layerFound;
}
Esri::ArcGISRuntime::ArcGISTiledLayer *getEsriBasemap_ArcGISTiledLayer(Esri::ArcGISRuntime::Map *map,
const QString &layername)
{
Esri::ArcGISRuntime::Layer *layerFound = getEsriBasemap_Layer(map, layername);
if (! layerFound)
return nullptr;
if (layerFound->layerType() == Esri::ArcGISRuntime::LayerType::ArcGISTiledLayer)
{
Esri::ArcGISRuntime::ArcGISTiledLayer *layer2 =
static_cast<Esri::ArcGISRuntime::ArcGISTiledLayer *>(layerFound);
return layer2;
}
return nullptr;
}
class SimpleEsriLayer::Private
{
public:
Private()
{
}
~Private()
{
}
// ESRI data:
Esri::ArcGISRuntime::Map *m_map = nullptr;
Esri::ArcGISRuntime::MapGraphicsView *m_mapView = nullptr;
// OWN data:
QGridLayout *m_layout = nullptr;
}; // class SimpleEsriLayer::Private
//-----------------------------------------------------------------------------
SimpleEsriLayer::SimpleEsriLayer(QWidget *parent, Esri::ArcGISRuntime::MapGraphicsView *mapView)
: QWidget(parent)
, d(new Private)
{
d->m_mapView = mapView;
if (d->m_mapView)
d->m_map = d->m_mapView->map();
d->m_layout = new QGridLayout(this);
updatePanel();
}
SimpleEsriLayer::~SimpleEsriLayer()
{
delete d;
}
bool SimpleEsriLayer::updatePanel()
{
for (int row = 0; row < d->m_layout->rowCount(); ++row)
{
for (int col = 0; col < d->m_layout->columnCount(); ++col)
{
QLayoutItem *item = d->m_layout->itemAtPosition(row, col);
if (item)
{
QWidget *w = item->widget();
delete w;
}
}
}
delete d->m_layout;
d->m_layout = new QGridLayout(this);
if (d->m_map)
{
// Header
int row = 0;
int col = 0;
for (const char *name : { "OnOff", "Opac", "Brightness", "Contrast", "Gamma" })
d->m_layout->addWidget(new QLabel(QString::fromLatin1(name)), row, col++);
row = d->m_layout->rowCount();
// GraphicalOverlay
Esri::ArcGISRuntime::GraphicsOverlayListModel *graphicsOverlayListModel = d->m_mapView->graphicsOverlays();
if (graphicsOverlayListModel)
{
int graphicsOverlaySize = graphicsOverlayListModel->size();
// qDebug() << LOGFUNCTION << " graphicsOverlayListModel -> size=" << graphicsOverlaySize;
row += graphicsOverlaySize;
for (int i = 0; i < graphicsOverlaySize; ++i)
{
--row;
col = 0;
// qDebug() << LOGFUNCTION << " graphicsOverlayListModel handle layer i='" << i;
Esri::ArcGISRuntime::GraphicsOverlay *gOverlay = graphicsOverlayListModel->at(i);
if (! gOverlay)
{
qWarning() << LOGFUNCTION << " gOverlay is nil";
return false;
}
const QString &layername = gOverlay->objectName();
QCheckBox *cbOnOff = new QCheckBox(layername);
cbOnOff->setChecked(gOverlay->isVisible());
connect(cbOnOff, &QCheckBox::stateChanged, this, &SimpleEsriLayer::layerOnOff);
d->m_layout->addWidget(cbOnOff, row, col++);
SimpleEsriLayerSlider *sl_opac = new SimpleEsriLayerSlider(layername, 0, 100);
sl_opac->setValue(gOverlay->opacity() * 100);
connect(sl_opac, &SimpleEsriLayerSlider::valueChanged, this, &SimpleEsriLayer::opacity);
d->m_layout->addWidget(sl_opac, row, col++);
} // for
} // if (graphicsOverlayListModel)
// BasemapLayer
row = d->m_layout->rowCount();
Esri::ArcGISRuntime::LayerListModel *baseLayerModel = d->m_map->basemap()->baseLayers();
if (baseLayerModel)
{
int baseLayerModelSize = baseLayerModel->size();
qWarning() << LOGFUNCTION << " baseLayerModel -> size=" << baseLayerModelSize;
row += baseLayerModelSize;
for (int i = 0; i < baseLayerModelSize; ++i)
{
col = 0;
--row;
qWarning() << LOGFUNCTION << " baseLayerModel handle layer i=" << i;
Esri::ArcGISRuntime::Layer *layer = baseLayerModel->at(i);
if (! layer)
{
qWarning() << LOGFUNCTION << " layer is nil";
return false;
}
const QString &layername = layer->name();
QCheckBox *cbOnOff = new QCheckBox(layername);
cbOnOff->setChecked(layer->isVisible());
// QString tooltip = layer->url();
// if (!l->serviceDescription().isEmpty())
// tooltip += QLatin1String(" ; ") % l->serviceDescription();
// if (!tooltip.isEmpty())
// cbOnOff->setToolTip(tooltip);
connect(cbOnOff, &QCheckBox::stateChanged, this, &SimpleEsriLayer::layerOnOff);
d->m_layout->addWidget(cbOnOff, row, col++);
SimpleEsriLayerSlider *sl_opac = new SimpleEsriLayerSlider(layername, 0, 100);
sl_opac->setValue(layer->opacity() * 100);
connect(sl_opac, &SimpleEsriLayerSlider::valueChanged, this, &SimpleEsriLayer::opacity);
d->m_layout->addWidget(sl_opac, row, col++);
if (layer->layerType() == Esri::ArcGISRuntime::LayerType::ArcGISTiledLayer
// || layer->type() == EsriRuntimeQt::LayerType::ArcGISTiledMapService
)
{
Esri::ArcGISRuntime::ArcGISTiledLayer *realLayer =
dynamic_cast<Esri::ArcGISRuntime::ArcGISTiledLayer *>(layer);
if (realLayer)
{
float brightness = realLayer->brightness();
float contrast = realLayer->contrast();
float gamma = realLayer->gamma();
qWarning() << " brightness=" << brightness; // QuartzBeta1 -> not supported
qWarning() << " contrast=" << contrast; // QuartzBeta1 -> not supported
qWarning() << " gamma=" << gamma; // QuartzBeta1 -> not supported
SimpleEsriLayerSlider *sl_brightness = new SimpleEsriLayerSlider(layername, -100, 100);
sl_brightness->setValue(brightness * 100);
connect(sl_brightness, &SimpleEsriLayerSlider::valueChanged, this, &SimpleEsriLayer::brightness);
d->m_layout->addWidget(sl_brightness, row, col++);
SimpleEsriLayerSlider *sl_contrast = new SimpleEsriLayerSlider(layername, -100, 100);
sl_contrast->setValue(contrast * 100);
connect(sl_contrast, &SimpleEsriLayerSlider::valueChanged, this, &SimpleEsriLayer::contrast);
d->m_layout->addWidget(sl_contrast, row, col++);
SimpleEsriLayerSlider *sl_gamma = new SimpleEsriLayerSlider(layername, -100, 100);
sl_gamma->setValue(gamma * 100);
connect(sl_gamma, &SimpleEsriLayerSlider::valueChanged, this, &SimpleEsriLayer::gamma);
d->m_layout->addWidget(sl_gamma, row, col++);
} // ir (realLayer)
} // if (layer->type() == Es
} // for
} // if (baseLayerModel)
QPushButton *pbMaximizeExtent = new QPushButton(QLatin1String("maximize scale of 1st basemap"));
d->m_layout->addWidget(pbMaximizeExtent, 9999, 0);
connect(pbMaximizeExtent, &QPushButton::clicked, this, [this]()
{
if (d->m_map)
{
d->m_map->setMinScale(500000000); // 5e+08
d->m_map->setMaxScale(100);
}
});
}
else
qWarning() << LOGFUNCTION << " no map !!! ";
return true;
}
void SimpleEsriLayer::layerOnOff()
{
QCheckBox *cb = qobject_cast<QCheckBox *>(sender());
if (!cb)
return;
QString layername = cb->text();
qDebug() << LOGFUNCTION << " layername=" << layername;
Esri::ArcGISRuntime::Layer *l = getEsriBasemap_Layer(d->m_map, layername);
if (l)
l->setVisible(cb->isChecked());
else
qDebug() << LOGFUNCTION << " no layer!!!, layername=" << layername;
}
void SimpleEsriLayer::opacity(int)
{
SimpleEsriLayerSlider *sl = qobject_cast<SimpleEsriLayerSlider *>(sender());
if (!sl)
return;
QString layername = sl->m_layername;
double value = sl->value() / 100.0;
Esri::ArcGISRuntime::Layer *l = getEsriBasemap_Layer(d->m_map, layername);
if (l)
{
qDebug() << LOGFUNCTION << " layername=" << layername << " set to val=" << value;
l->setOpacity(value);
}
else
qWarning() << LOGFUNCTION << " no layer!!!, layername=" << layername;
}
void SimpleEsriLayer::brightness(int)
{
SimpleEsriLayerSlider *sl = qobject_cast<SimpleEsriLayerSlider *>(sender());
if (!sl)
return;
QString layername = sl->m_layername;
Esri::ArcGISRuntime::ArcGISTiledLayer *l = getEsriBasemap_ArcGISTiledLayer(d->m_map, layername);
double value = sl->value() / 100.0;
// double value = sl->value();
qDebug() << LOGFUNCTION << " layername=" << layername << " set to val=" << value;
l->setBrightness(value);
}
void SimpleEsriLayer::contrast(int)
{
SimpleEsriLayerSlider *sl = qobject_cast<SimpleEsriLayerSlider *>(sender());
if (!sl)
return;
QString layername = sl->m_layername;
Esri::ArcGISRuntime::ArcGISTiledLayer *l = getEsriBasemap_ArcGISTiledLayer(d->m_map, layername);
double value = sl->value() / 100.0;
// double value = sl->value();
qDebug() << LOGFUNCTION << " layername=" << layername << " set to val=" << value;
l->setContrast(value);
}
void SimpleEsriLayer::gamma(int)
{
SimpleEsriLayerSlider *sl = qobject_cast<SimpleEsriLayerSlider *>(sender());
if (!sl)
return;
QString layername = sl->m_layername;
Esri::ArcGISRuntime::ArcGISTiledLayer *l = getEsriBasemap_ArcGISTiledLayer(d->m_map, layername);
double value = sl->value() / 100.0;
// double value = sl->value();
qDebug() << LOGFUNCTION << " layername=" << layername << " set to val=" << value;
l->setGamma(value);
}
} // namespace SituationMap
+79
View File
@@ -0,0 +1,79 @@
/**
* @RDE_HEADER@
* FunctionDialog
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QObject>
#include <QSlider>
// ESRI
#include <arcgis/Map.h>
#include <arcgis/MapGraphicsView.h>
#include <arcgis/GraphicsOverlay.h>
//----------------------------------------------------------------------------
namespace SituationMap
{
class SimpleEsriLayerSlider : public QSlider
{
Q_OBJECT
public:
SimpleEsriLayerSlider(const QString &layername, int min, int max)
: QSlider(), m_layername(layername)
{
this->setOrientation(Qt::Horizontal);
setMinimum(min);
setMaximum(max);
}
public:
QString m_layername;
};
class SimpleEsriLayer : public QWidget
{
Q_OBJECT
public:
SimpleEsriLayer(QWidget *parent, Esri::ArcGISRuntime::MapGraphicsView *mapView);
virtual ~SimpleEsriLayer();
SimpleEsriLayer(const SimpleEsriLayer &other) = delete; // No copy
SimpleEsriLayer &operator=(const SimpleEsriLayer &other) = delete; // No copy
bool updatePanel();
private slots:
void layerOnOff();
void opacity(int);
void brightness(int);
void contrast(int);
void gamma(int);
private :
class Private;
/**
* The private d-pointer to not break BC when changing internals of this class
*/
Private *d = nullptr;
};
} // namespace SituationMap
//----------------------------------------------------------------------------
// Q_DECLARE_METATYPE(SituationMap::GeometryType);
+156
View File
@@ -0,0 +1,156 @@
/* XPM */
static const char * stateIconA_xpm[] = {
"24 24 129 2",
" c None",
". c #4CE146",
"+ c #9E8E3A",
"@ c #4CE045",
"# c #BDAB46",
"$ c #A3912F",
"% c #4BDF44",
"& c #32942E",
"* c #B8C14A",
"= c #CABF35",
"- c #4ADE43",
"; c #F2DA55",
"> c #A7973C",
", c #CDC74E",
"' c #E1D132",
") c #347D25",
"! c #48DD42",
"~ c #E7CF4C",
"{ c #F7D519",
"] c #F8DB3E",
"^ c #9D8E38",
"/ c #E3CC50",
"( c #F6D629",
"_ c #56821F",
": c #37AA32",
"< c #47DB41",
"[ c #DAC54B",
"} c #F6D51F",
"| c #F5D210",
"1 c #F5D211",
"2 c #F5DA3F",
"3 c #819D38",
"4 c #E8D14F",
"5 c #F6D522",
"6 c #A48D0C",
"7 c #46DA40",
"8 c #C3B445",
"9 c #F4D425",
"0 c #F3D00E",
"a c #C9BF13",
"b c #F3D00F",
"c c #F2D840",
"d c #8FAA3D",
"e c #E7D54D",
"f c #F4D31B",
"g c #D4B50C",
"h c #45D93E",
"i c #AC9B3C",
"j c #F3D52C",
"k c #EBCC0D",
"l c #7D9516",
"m c #CCAE0A",
"n c #F1CE0C",
"o c #F1CE0E",
"p c #F4D738",
"q c #F1D015",
"r c #DFC70E",
"s c #43D73D",
"t c #8E7F31",
"u c #F0D434",
"v c #DBC50D",
"w c #588019",
"x c #D6B709",
"y c #EFCC0A",
"z c #EDCB0A",
"A c #5B8F1F",
"B c #42D63B",
"C c #ECD23C",
"D c #C9BA0D",
"E c #3A7F1F",
"F c #DEBD07",
"G c #EDCA08",
"H c #A39309",
"I c #2E972A",
"J c #40D43A",
"K c #E7CF41",
"L c #C2A60A",
"M c #27701E",
"N c #33A92E",
"O c #C1A405",
"P c #38BB32",
"Q c #DCC543",
"R c #9D8709",
"S c #37B931",
"T c #3FD338",
"U c #24711E",
"V c #C2B33F",
"W c #3DD137",
"X c #C8B54A",
"Y c #83A134",
"Z c #3D6517",
"` c #3CD036",
" . c #E4CA37",
".. c #EDD035",
"+. c #29731E",
"@. c #F6D726",
"#. c #F9D821",
"$. c #3ACF34",
"%. c #39CD33",
"&. c #8F8132",
"*. c #F6D414",
"=. c #F6D311",
"-. c #AD9B39",
";. c #38CC32",
">. c #C9B337",
",. c #D9BF33",
"'. c #37CB30",
"). c #E9CB29",
"!. c #F1CD0C",
"~. c #EFD022",
"{. c #36CA2F",
"]. c #EFCD12",
"^. c #EECB09",
"/. c #EECC0C",
"(. c #8C7E2F",
"_. c #35C92E",
":. c #B29F34",
"<. c #EBC806",
"[. c #C4AD31",
"}. c #D7BD29",
"|. c #E8C503",
"1. c #E4C722",
"2. c #E8C714",
"3. c #E7C402",
"4. c #E8C508",
"5. c #97872E",
"6. c #E5C201",
"7. c #E5C200",
"8. c #B8A330",
" ",
" . . . . . . . . + ",
" @ @ @ @ # $ ",
" % & * = ",
" - ; > , ' ) ",
" ! ~ { ] ^ / ( _ : ",
" < [ } | 1 2 3 4 5 6 < ",
" 7 8 9 0 a 0 b c d e f g 7 ",
" h i j k l m n o p q r h ",
" s t u v w x y y z A s ",
" B C D E F G H I B ",
" J K L M N O J ",
" P Q R S T ",
" U V W # X W W ",
" Y Z ` ... ` ` ",
" +. @.#. $. $. ",
" %. &.*.=.-. %. ",
" ;. >.0 0 ,. ;. ",
" '. ).!.!.~. '. ",
" {. ].^.^./.(. {. ",
" _. :.<.<.<.<.[. _. ",
" }.|.|.|.|.1. ",
" 2.3.3.3.3.4. ",
" 5.6.7.7.7.7.7.8. "};
+216
View File
@@ -0,0 +1,216 @@
/* XPM */
static const char * stateIconB_xpm[] = {
"24 24 189 2",
" c None",
". c #4A8448",
"+ c #69BC66",
"@ c #75D272",
"# c #7ADA76",
"$ c #77D673",
"% c #6CC269",
"& c #508E4D",
"* c #61AE5E",
"= c #7EE57A",
"- c #73E76E",
"; c #64E55F",
"> c #5BE355",
", c #57E351",
"' c #59E353",
") c #62E55D",
"! c #71E76C",
"~ c #7EE779",
"{ c #68BB65",
"] c #7BE076",
"^ c #69E563",
"/ c #50E149",
"( c #46CE40",
"_ c #34982E",
": c #44C93E",
"< c #4EE047",
"[ c #65E45F",
"} c #7CE377",
"| c #4A8447",
"1 c #51934E",
"2 c #75E56F",
"3 c #51E04B",
"4 c #48D541",
"5 c #46D140",
"6 c #4FE048",
"7 c #71E56B",
"8 c #59A056",
"9 c #6EE368",
"0 c #4BDE44",
"a c #42C73C",
"b c #40BF3A",
"c c #6AE364",
"d c #4C894A",
"e c #6EDF69",
"f c #49DD43",
"g c #40C63B",
"h c #3FC13A",
"i c #6CE068",
"j c #66BD62",
"k c #4BDC45",
"l c #44D03E",
"m c #5EAB5B",
"n c #75D571",
"o c #42CD3D",
"p c #65C062",
"q c #5CDE57",
"r c #46DA40",
"s c #74D670",
"t c #64E05F",
"u c #52DC4C",
"v c #44CF3E",
"w c #5BDD56",
"x c #5AA956",
"y c #46D93F",
"z c #3EC438",
"A c #6DD168",
"B c #4FDB49",
"C c #3CBC36",
"D c #6DD268",
"E c #58A954",
"F c #57C352",
"G c #43D73D",
"H c #389234",
"I c #569F53",
"J c #50DA4A",
"K c #3ABA35",
"L c #3ABB35",
"M c #4FDA49",
"N c #5BA758",
"O c #58C553",
"P c #50D04B",
"Q c #42D63B",
"R c #5CCA57",
"S c #5BCE56",
"T c #50D049",
"U c #46D240",
"V c #40D43A",
"W c #4CD146",
"X c #3ECE38",
"Y c #3DCB38",
"Z c #4AD545",
"` c #41CF3A",
" . c #3FD338",
".. c #42CF3B",
"+. c #43D03C",
"@. c #45CF3E",
"#. c #40D139",
"$. c #41CE3A",
"%. c #3EC738",
"&. c #3DD137",
"*. c #3ABC35",
"=. c #41D23B",
"-. c #BDAB46",
";. c #C8B54A",
">. c #42D23C",
",. c #3ABF35",
"'. c #3BB136",
"). c #3CD036",
"!. c #53A74F",
"~. c #2F812B",
"{. c #64CF60",
"]. c #E4CA37",
"^. c #EDD035",
"/. c #66CF62",
"(. c #30852C",
"_. c #51A44D",
":. c #3DB637",
"<. c #338530",
"[. c #3ACF34",
"}. c #55CF51",
"|. c #33B72E",
"1. c #42CF3D",
"2. c #F6D726",
"3. c #F9D821",
"4. c #3A6E37",
"5. c #44D13E",
"6. c #35BD2F",
"7. c #55CC51",
"8. c #348930",
"9. c #38CA32",
"0. c #3FCF39",
"a. c #57A654",
"b. c #278723",
"c. c #8F8132",
"d. c #F6D414",
"e. c #F6D311",
"f. c #AD9B39",
"g. c #2EA72A",
"h. c #519A4E",
"i. c #42CF3C",
"j. c #2C9928",
"k. c #38CC32",
"l. c #56D351",
"m. c #C9B337",
"n. c #F3D00E",
"o. c #D9BF33",
"p. c #5AD256",
"q. c #2E9F2A",
"r. c #34C02D",
"s. c #38CB31",
"t. c #62D25D",
"u. c #E9CB29",
"v. c #F1CD0C",
"w. c #EFD022",
"x. c #64CD5F",
"y. c #3ACC33",
"z. c #34BF2D",
"A. c #35C62E",
"B. c #3BCB34",
"C. c #67D261",
"D. c #EFCD12",
"E. c #EECB09",
"F. c #EECC0C",
"G. c #8C7E2F",
"H. c #6ACF65",
"I. c #3FCC39",
"J. c #34C42D",
"K. c #39CA32",
"L. c #5BC656",
"M. c #B29F34",
"N. c #EBC806",
"O. c #C4AD31",
"P. c #63CD5E",
"Q. c #3ECB37",
"R. c #34C52D",
"S. c #30B82A",
"T. c #2B8327",
"U. c #D7BD29",
"V. c #E8C503",
"W. c #E4C722",
"X. c #2D9428",
"Y. c #2FB72A",
"Z. c #E8C714",
"`. c #E7C402",
" + c #E8C508",
".+ c #97872E",
"++ c #E5C201",
"@+ c #E5C200",
"#+ c #B8A330",
" . + @ # # $ % & ",
" * = - ; > , , ' ) ! ~ { ",
" ] ^ / ( _ : < [ } | ",
" 1 2 3 4 5 6 7 8 ",
" 9 0 a b 0 c d ",
" e f g h f i ",
" j k l m n = = n m o k p ",
" q r s t u v v u t s r w ",
"x y z A B C C B D z y E ",
"F G H I J K L M N H G O ",
"P Q R Q Q S Q T ",
"U V W X Y Z V U ",
"` . ..+. @.#. .$.",
"%.&. *.=. -.;. >.,. &.%.",
"'.).!. ~.).{. ].^. /.).(. _.).:.",
"<.[.}. |.1. 2.3. 4.5.6. 7.[.8.",
" 9.0.a. b. c.d.e.f. g. h.i.9. ",
" j.k.l. m.n.n.o. p.k.q. ",
" r.s.t. u.v.v.w. x.y.z. ",
" A.B.C. D.E.E.F.G. H.I.A. ",
" J.K.L. M.N.N.N.N.O. P.Q.R. ",
" S.T. U.V.V.V.V.W. X.Y. ",
" Z.`.`.`.`. + ",
" .+++@+@+@+@+@+#+ "};
+110
View File
@@ -0,0 +1,110 @@
/* XPM */
static const char * stateIconC_xpm[] = {
"24 24 83 1",
" c None",
". c #7FBD7C",
"+ c #8BCF88",
"@ c #84C582",
"# c #588456",
"$ c #63BE5F",
"% c #57B953",
"& c #73BF70",
"* c #56B752",
"= c #499B45",
"- c #699F66",
"; c #59B755",
"> c #54B550",
", c #52B14E",
"' c #6ABC67",
") c #52B34E",
"! c #377334",
"~ c #6FAF6C",
"{ c #50B24C",
"] c #4FB14B",
"^ c #48A144",
"/ c #4C734A",
"( c #5DB559",
"_ c #4DAE49",
": c #4CAD48",
"< c #6BB569",
"[ c #4AAC46",
"} c #377F35",
"| c #5E915C",
"1 c #50AD4C",
"2 c #48A944",
"3 c #44A040",
"4 c #61B05E",
"5 c #45A641",
"6 c #527F50",
"7 c #7BBF78",
"8 c #78BA75",
"9 c #639C60",
"0 c #46A542",
"a c #42A33E",
"b c #368633",
"c c #389035",
"d c #3FA13B",
"e c #43A33F",
"f c #619B5E",
"g c #56AC53",
"h c #3D9D39",
"i c #3B9C37",
"j c #3C9E38",
"k c #54A951",
"l c #64A761",
"m c #3D9E39",
"n c #2A6B26",
"o c #3A9B35",
"p c #3B9B36",
"q c #62A55F",
"r c #4B7749",
"s c #48A243",
"t c #33892F",
"u c #328B2F",
"v c #379833",
"w c #459F41",
"x c #4F7E4D",
"y c #5CA659",
"z c #369632",
"A c #349530",
"B c #349630",
"C c #59A955",
"D c #3A9936",
"E c #276C25",
"F c #256C22",
"G c #32932E",
"H c #2F892B",
"I c #2C8728",
"J c #2F912B",
"K c #2F902B",
"L c #2D8E29",
"M c #2D8F29",
"N c #257322",
"O c #226E1F",
"P c #2B8D27",
"Q c #298826",
"R c #288424",
" ",
" ",
" .+++@ ",
" #$%%% ",
" &***= ",
" -;>>, ",
" ')))! ",
" ~{]]^ ",
" /(__: ",
" <[[[} ",
" |1223 ",
" 4555 ",
" 67778 90aab ",
" cddef gddh ",
" ijjk lmjj ",
" noopq rsoot ",
" uvvwxyvvz ",
" ABBCDBBE ",
" FGGGGGH ",
" IJJJK ",
" LMMN ",
" OPQ ",
" R ",
" "};
+445
View File
@@ -0,0 +1,445 @@
"id";"name";"sym_klassifiz_id";"name";"symbol_id_code";"id";"name";"def_symbol_id"
"611";"ADMINISTRATIVE FINANCE";"331";"FINANCE";"S*G*USAF--*****";"(null)";"(null)";"(null)"
"609";"ADMINISTRATIVE JUDGE ADVOCATE GENERAL (JAG)";"325";"JUDGEADVOCATEGENERAL(JAG)";"S*G*USAJ--*****";"(null)";"(null)";"(null)"
"606";"ADMINISTRATIVE LABOUR";"355";"LABOUR";"S*G*USAL--*****";"(null)";"(null)";"(null)"
"607";"ADMINISTRATIVE MORAL, WELFARE, RECREATION (MWR)";"358";"MORAL,WELFARE,RECREATION(MWR)";"S*G*USAW--*****";"(null)";"(null)";"(null)"
"613";"ADMINISTRATIVE MORTUARY/GRAVE REGISTRY";"337";"MORTUARY/GRAVESREGISTRY";"S*G*USAM--*****";"(null)";"(null)";"(null)"
"612";"ADMINISTRATIVE PERSONNEL SERVICES";"334";"PERSONNELSERVICES";"S*G*USAS--*****";"(null)";"(null)";"(null)"
"610";"ADMINISTRATIVE POSTAL";"328";"POSTAL";"S*G*USAO--*****";"(null)";"(null)";"(null)"
"615";"ADMINISTRATIVE PUPLIC AFFAIRS";"343";"PUBLICAFFAIRS";"S*G*USAP--*****";"(null)";"(null)";"(null)"
"608";"ADMINISTRATIVE QUARTERMASTER (";"361";"QUARTERMASTER(SUPPLY)";"S*G*USAQ--*****";"(null)";"(null)";"(null)"
"614";"ADMINISTRATIVE RELIGIOUS/CHAPLAIN";"340";"RELIGIOUS/CHAPLAIN";"S*G*USAR--*****";"(null)";"(null)";"(null)"
"605";"ADMINISTRATIVE REPLACEMENT HOLDING UNIT (RHV)";"352";"REPLACEMENTHOLDINGUNIT(RHU)";"S*G*USAX--*****";"(null)";"(null)";"(null)"
"364";"AIR DEFENCE";"79";"AIRDEFENCE";"S*G*UCD---*****";"(null)";"(null)";"(null)"
"664";"AIR DEFENCE (AD) MISSILE LAUNC";"471";"AIRDEFENCE(AD)MISSILELAUNCH";"S*G*EWMA--*****";"(null)";"(null)";"(null)"
"379";"AIR DEFENCE COMPOSITE";"90";"COMPOSITE";"S*G*UCDC--*****";"(null)";"(null)";"(null)"
"367";"Air Defence COY";"79";"AIRDEFENCE";"S*G*UCD---*****";"(null)";"(null)";"(null)"
"683";"AIR DEFENCE GUN";"527";"AIRDEFENCEGUN";"S*G*EWA---*****";"(null)";"(null)";"(null)"
"686";"AIR DEFENCE GUN HEAVY";"530";"AIRDEFENCEGUNHEAVY";"S*G*EWAH--*****";"(null)";"(null)";"(null)"
"684";"AIR DEFENCE GUN LIGHT";"528";"AIRDEFENCEGUNLIGHT";"S*G*EWAL--*****";"(null)";"(null)";"(null)"
"685";"AIR DEFENCE GUN MEDIUM";"529";"AIRDEFENCEGUNMEDIUM";"S*G*EWAM--*****";"44";"Soldier Air Defence";"685"
"378";"AIR DEFENCE GUN UNIT";"89";"GUNUNIT";"S*G*UCDG--*****";"(null)";"(null)";"(null)"
"377";"AIR DEFENCE H/MAD";"88";"H/MAD";"S*G*UCDH--*****";"(null)";"(null)";"(null)"
"372";"AIR DEFENCE MISSILE";"83";"AIRDEFENCEMISSILE";"S*G*UCDM--*****";"(null)";"(null)";"(null)"
"376";"AIR DEFENCE MISSILE HEAVY";"87";"AIRDEFENCEMISSILEHEAVY";"S*G*UCDMH-*****";"(null)";"(null)";"(null)"
"373";"AIR DEFENCE MISSILE LIGHT";"84";"AIRDEFENCEMISSILELIGHT";"S*G*UCDML-*****";"229";"Legatus Wiesel";"373"
"375";"AIR DEFENCE MISSILE MEDIUM";"86";"AIRDEFENCEMISSILEMEDIUM";"S*G*UCDMM-*****";"(null)";"(null)";"(null)"
"374";"AIR DEFENCE MISSILE MOTORIZED";"85";"AIRDEFENCEMISSILEMOTORIZED";"S*G*UCDMLA*****";"(null)";"(null)";"(null)"
"369";"AIR DEFENCE SHORT RANGE";"80";"SHORTRANGE";"S*G*UCDS--*****";"(null)";"(null)";"(null)"
"371";"AIR DEFENCE SHORT RANGE GUN";"82";"GUN";"S*G*UCDS--*****";"(null)";"(null)";"(null)"
"370";"AIR DEFENCE SHORT RANGE MISSILE";"81";"MISSILE";"S*G*UCDS--*****";"(null)";"(null)";"(null)"
"380";"AIR DEFENCE TARGETING UNIT";"91";"TARGETINGUNIT";"S*G*UCDT--*****";"(null)";"(null)";"(null)"
"381";"AIR DEFENCE THEATRE MISSILE DEFENCE UNIT";"92";"THEATREMISSILEDEFENCEUNIT";"S*G*UCDO--*****";"(null)";"(null)";"(null)"
"781";"AIRPORT/AIRBASE";"605";"AIRPORT/AIRBASE";"S*G*IBA---H****";"(null)";"(null)";"(null)"
"342";"AIR TRACK";"6";"AIRTRACK";"S*A*------*****";"(null)";"(null)";"(null)"
"777";"AMMUNITION AND EXPLOSIVES PRODUCTION";"595";"AMMUNITIONANDEXPLOSIVESPRODUCTION";"S*G*IME---H****";"(null)";"(null)";"(null)"
"788";"AMPHIBIOUS WARFARE SHIP";"620";"AMPHIBIOUSWARFARESHIP";"S*S*CA----*****";"(null)";"(null)";"(null)"
"414";"ANTI ARMOUR";"110";"ANTIARMOUR";"S*G*UCAA--*****";"(null)";"(null)";"(null)"
"422";"ANTI ARMOUR AIR ASSAULT";"114";"ANTIARMOURAIRASSAULT";"S*G*UCAAS-*****";"(null)";"(null)";"(null)"
"421";"ANTI ARMOUR AIRBORNE";"113";"ANTIARMOURAIRBORNE";"S*G*UCAAM-*****";"(null)";"(null)";"(null)"
"424";"ANTI ARMOUR ARMOURED";"117";"ANTIARMOURARMOURED";"S*G*UCAAA-*****";"(null)";"(null)";"(null)"
"427";"ANTI ARMOUR ARMOURED AIR ASSAU";"120";"ANTIARMOURARMOUREDAIRASSAULT";"S*G*UCAAAS*****";"(null)";"(null)";"(null)"
"425";"ANTI ARMOUR ARMOURED TRACKED";"118";"ANTIARMOURARMOUREDTRACKED";"S*G*UCAAAT*****";"(null)";"(null)";"(null)"
"426";"ANTI ARMOUR ARMOURED WHEELED";"119";"ANTIARMOURARMOUREDWHEELED";"S*G*UCAAAW*****";"(null)";"(null)";"(null)"
"419";"ANTI ARMOUR DISMOUNTED";"111";"ANTIARMOURDISMOUNTED";"S*G*UCAAD-*****";"(null)";"(null)";"(null)"
"420";"ANTI ARMOUR LIGHT";"112";"ANTIARMOURLIGHT";"S*G*UCAAL-*****";"(null)";"(null)";"(null)"
"428";"ANTI ARMOUR MOTORIZED";"121";"ANTIARMOURMOTORIZED";"S*G*UCAAO-*****";"(null)";"(null)";"(null)"
"429";"ANTI ARMOUR MOTORIZED AIR ASSA";"122";"ANTIARMOURMOTORIZEDAIRASSAULT";"S*G*UCAAOS*****";"(null)";"(null)";"(null)"
"423";"ANTI ARMOUR MOUNTAIN";"115";"ANTIARMOURMOUNTAIN";"S*G*UCAAU-*****";"(null)";"(null)";"(null)"
"718";"ANTITANK GUN";"515";"ANTITANKGUN";"S*G*EWG---*****";"130";"Soldier AT (RPG7)";"718"
"722";"ANTITANK GUN HEAVY";"519";"ANTITANKGUNHEAVY";"S*G*EWGH--*****";"(null)";"(null)";"(null)"
"720";"ANTITANK GUN LIGHT";"517";"ANTITANKGUNLIGHT";"S*G*EWGL--*****";"(null)";"(null)";"(null)"
"721";"ANTITANK GUN MEDIUM";"518";"ANTITANKGUNMEDIUM";"S*G*EWGM--*****";"(null)";"(null)";"(null)"
"719";"ANTITANK GUN RECOILLESS";"516";"ANTITANKGUNRECOILLESS";"S*G*EWGR--*****";"(null)";"(null)";"(null)"
"695";"ANTITANK ROCKET LAUNCHER";"492";"ANTITANKROCKETLAUNCHER";"S*G*EWT---*****";"(null)";"(null)";"(null)"
"698";"ANTITANK ROCKET LAUNCHER HEAVY";"495";"ANTITANKROCKETLAUNCHERHEAVY";"S*G*EWTH--*****";"(null)";"(null)";"(null)"
"696";"ANTITANK ROCKET LAUNCHER LIGHT";"493";"ANTITANKROCKETLAUNCHERLIGHT";"S*G*EWTL--*****";"(null)";"(null)";"(null)"
"697";"ANTITANK ROCKET LAUNCHER MEDIU";"494";"ANTITANKROCKETLAUNCHERMEDIUM";"S*G*EWTM--*****";"(null)";"(null)";"(null)"
"392";"ARMOUR";"93";"ARMOUR";"S*G*UCA---*****";"(null)";"(null)";"(null)"
"752";"ARMOURED CARRIER WITH SCATTERA";"561";"ARMOUREDCARRIERWITHSCATTERABLEMINES";"S*G*EVEMSM*****";"(null)";"(null)";"(null)"
"734";"ARMOURED INFANTRY";"542";"ARMOUREDINFANTRY";"S*G*EVAI--*****";"(null)";"(null)";"(null)"
"732";"ARMOURED PERSONNEL CARRIER";"540";"ARMOUREDPERSONNELCARRIER";"S*G*EVAA--*****";"(null)";"(null)";"(null)"
"733";"ARMOURED PERSONNEL CARRIER REC";"541";"ARMOUREDPERSONNELCARRIERRECOVERY";"S*G*EVAAR-*****";"(null)";"(null)";"(null)"
"724";"ARMOURED VEHICLE";"532";"ARMOUREDVEHICLE";"S*G*EVA---*****";"231";"Marder";"724"
"750";"ARMOURED VEHICLE MOUNTED";"558";"ARMOUREDVEHICLEMOUNTED";"S*G*EVEMA-*****";"(null)";"(null)";"(null)"
"397";"ARMOUR TRACK";"94";"ARMOURTRACK";"S*G*UCAT--*****";"(null)";"(null)";"(null)"
"398";"ARMOUR TRACK AIRBORNE";"95";"ARMOURTRACKAIRBORNE";"S*G*UCATA-*****";"(null)";"(null)";"(null)"
"399";"ARMOUR TRACK AMPHIBIOUS";"96";"ARMOURTRACKAMPHIBIOUS";"S*G*UCATW-*****";"(null)";"(null)";"(null)"
"400";"ARMOUR TRACK AMPHIBIOUS RECOVE";"97";"ARMOURTRACKAMPHIBIOUSRECOVERY";"S*G*UCATWR*****";"(null)";"(null)";"(null)"
"403";"ARMOUR TRACK HEAVY";"100";"ARMOURTRACK,HEAVY";"S*G*UCATH-*****";"(null)";"(null)";"(null)"
"401";"ARMOUR TRACK LIGHT";"98";"ARMOURTRACK,LIGHT";"S*G*UCATL-*****";"(null)";"(null)";"(null)"
"402";"ARMOUR TRACK MEDIUM";"99";"ARMOURTRACK,MEDIUM";"S*G*UCATM-*****";"(null)";"(null)";"(null)"
"404";"ARMOUR TRACK RECOVERY";"101";"ARMOURTRACK,RECOVERY";"S*G*UCATR-*****";"(null)";"(null)";"(null)"
"405";"ARMOUR WHEELED";"102";"ARMOUR,WHEELED";"S*G*UCAW--*****";"(null)";"(null)";"(null)"
"406";"ARMOUR WHEELED AIR ASSAULT";"103";"ARMOUR,WHEELEDAIRASSAULT";"S*G*UCAWS-*****";"(null)";"(null)";"(null)"
"407";"ARMOUR WHEELED AIRBORNE";"104";"ARMOUR,WHEELEDAIRBORNE";"S*G*UCAWA-*****";"227";"BMP3 IFV";"407"
"408";"ARMOUR WHEELED AMPHIBIOUS";"105";"ARMOUR,WHEELEDAMPHIBIOUS";"S*G*UCAWA-*****";"(null)";"(null)";"(null)"
"409";"ARMOUR WHEELED AMPHIBIOUS RECO";"1325";"ARMOURWHEELEDAMPHIBIOUSRECOVERY";"S*G*UCAWWR*****";"(null)";"(null)";"(null)"
"412";"ARMOUR WHEELED HEAVY";"108";"ARMOUR,WHEELEDHEAVY";"S*G*UCAWH-*****";"(null)";"(null)";"(null)"
"410";"ARMOUR WHEELED LIGHT";"106";"ARMOUR,WHEELEDLIGHT";"S*G*UCAWL-*****";"(null)";"(null)";"(null)"
"411";"ARMOUR WHEELED MEDIUM";"107";"ARMOUR,WHEELEDMEDIUM";"S*G*UCAWM-*****";"(null)";"(null)";"(null)"
"413";"ARMOUR WHEELED RECOVERY";"109";"ARMOUR,WHEELEDRECOVERY";"S*G*UCAWR-*****";"10";"Armored Recovery Vehicle";"413"
"789";"ASSAULT VESSEL";"621";"ASSAULTVESSEL";"S*S*CALA--*****";"(null)";"(null)";"(null)"
"776";"ATOMIC ENERGY PRODUCTION";"593";"ATOMICENERGYPRODUCTION";"S*G*IMF---H****";"(null)";"(null)";"(null)"
"430";"AVIATION";"123";"AVIATION";"S*G*UCV---*****";"(null)";"(null)";"(null)"
"431";"AVIATION FIXED WING";"124";"FIXEDWING";"S*G*UCVF--*****";"(null)";"(null)";"(null)"
"433";"AVIATION FIXED WING ATTACK";"126";"ATTACKFIXEDWING";"S*G*UCVFA-*****";"(null)";"(null)";"(null)"
"436";"AVIATION FIXED WING RECON";"129";"RECONFIXEDWING";"S*G*UCVFR-*****";"(null)";"(null)";"(null)"
"432";"AVIATION FIXED WING UTILITY";"125";"UTILITYFIXEDWING";"S*G*UCVFU-*****";"(null)";"(null)";"(null)"
"435";"AVIATION FORWARD AIR CONTROLLER (FAC)";"128";"FORWARDAIRCONTROLLER(FAC)";"S*G*UCVUFC*****";"(null)";"(null)";"(null)"
"437";"AVIATION ROTARY WING";"130";"ROTARYWING";"S*G*UCVR--*****";"(null)";"(null)";"(null)"
"440";"AVIATION ROTARY WING C2";"138";"C2ROTARYWING";"S*G*UCVRUC*****";"(null)";"(null)";"(null)"
"441";"AVIATION ROTARY WING MEDEVAC";"139";"MEDEVACROTARYWING";"S*G*UCVRUE*****";"(null)";"(null)";"(null)"
"439";"AVIATION ROTARY WING UTILITY";"134";"UTILITYROTARYWING";"S*G*UCVRU-*****";"(null)";"(null)";"(null)"
"434";"AVIATION TACTICAL AIR CONTROL";"127";"TACTICALAIRCONTROLPARTY(TACP)";"S*G*UCVUTP*****";"(null)";"(null)";"(null)"
"445";"AVIATION UAV CONTROL";"1326";"AVIATIONUAVCONTROL";"S*G*UCVU--*****";"(null)";"(null)";"(null)"
"446";"AVIATION UAV LAUNCHER";"1327";"AVIATIONUAVLAUNCHER";"S*G*UCVU--*****";"(null)";"(null)";"(null)"
"447";"AVIATION UAV RECOVERY";"1337";"AVIATIONUAVRECOVERY";"S*G*UCVU--*****";"(null)";"(null)";"(null)"
"444";"AVIATION UNMANNED AERIAL VEHIC";"145";"UNMANNEDAERIALVEHICLEFIXEDWING";"S*G*UCVUF-*****";"(null)";"(null)";"(null)"
"448";"AVIATION UNMANNED AERIAL VEHICLE ROTARY WING";"146";"UNMANNEDAERIALVEHICLEROTARYWING";"S*G*UCVUR-*****";"(null)";"(null)";"(null)"
"443";"AVIATION UNMANNED AVIATION VEH";"144";"UNMANNEDAERIALVEHICLE";"S*G*UCVU--*****";"(null)";"(null)";"(null)"
"442";"AVIATION VERTICAL/SHORT TAKEOF";"143";"VERTICAL/SHORTTAKEOFFANDLANDING(V/STOL)";"S*G*UCVV--*****";"(null)";"(null)";"(null)"
"769";"BIOLOGICAL";"581";"BIOLOGICAL";"S*G*IRNB--H****";"(null)";"(null)";"(null)"
"745";"BRIDGE";"553";"BRIDGE";"S*G*EVEB--*****";"(null)";"(null)";"(null)"
"778";"BRIDGE";"599";"BRIDGE";"S*G*IMNB--H****";"(null)";"(null)";"(null)"
"739";"BUS";"547";"BUS";"S*G*EVUB--*****";"(null)";"(null)";"(null)"
"735";"C2V/ACV";"543";"C2V/ACV";"S*G*EVAC--*****";"(null)";"(null)";"(null)"
"548";"CBRN";"256";"COMBATSUPPORTCBRN";"S*G*UUA---*****";"(null)";"(null)";"(null)"
"768";"CBRN";"580";"CBRN";"S*G*IRN---H****";"(null)";"(null)";"(null)"
"560";"CBRN BIOLOGICAL";"268";"BIOLOGICAL";"S*G*UUAB--*****";"(null)";"(null)";"(null)"
"561";"CBRN BIOLOGICAL RECON EQUIPPED";"269";"RECONEQUIPPED";"S*G*UUABR-*****";"(null)";"(null)";"(null)"
"549";"CBRN CHEMICAL";"257";"CHEMICAL";"S*G*UUAC--*****";"(null)";"(null)";"(null)"
"556";"CBRN CHEMICAL RECON";"264";"CHEMICALRECON";"S*G*UUACR-*****";"(null)";"(null)";"(null)"
"553";"CBRN CHEMICAL SMOKE";"261";"SMOKE";"S*G*UUACS-*****";"(null)";"(null)";"(null)"
"555";"CBRN CHEMICAL SMOKE ARMOUR";"263";"ARMOURSMOKE";"S*G*UUACSA*****";"(null)";"(null)";"(null)"
"550";"CBRN CHEMICAL SMOKE/DECON";"258";"SMOKE/DECON";"S*G*UUACC-*****";"(null)";"(null)";"(null)"
"551";"CBRN CHEMICAL SMOKE/DECON MECHANIZED";"259";"MECHANIZEDSMOKE/DECON";"S*G*UUACCK*****";"(null)";"(null)";"(null)"
"552";"CBRN CHEMICAL SMOKE/DECON MOTO";"260";"MOTORIZEDSMOKE/DECON";"S*G*UUACCM*****";"(null)";"(null)";"(null)"
"554";"CBRN CHEMICAL SMOKE MOTORIZED";"262";"MOTORIZEDSMOKE";"S*G*UUACSM*****";"(null)";"(null)";"(null)"
"557";"CBRN CHEMICAL WHEELED ARMOURED VEHICLE";"265";"CHEMICALWHEELEDARMOUREDVEHICLE";"S*G*UUACRW*****";"(null)";"(null)";"(null)"
"558";"CBRN CHEMICAL WHEELED ARMOURED VEHICLE RECONNAISAN";"266";"CHEMICALWHEELEDARMOUREDVEHICLERECONNAISSANCESURVEI";"S*G*UUACRS*****";"(null)";"(null)";"(null)"
"562";"CBRN DECON";"270";"DECONTAMINATION";"S*G*UUAD--*****";"(null)";"(null)";"(null)"
"564";"CBRN DECON EQUIPMENT";"1330";"CBRNDECONEQUIPMENT";"S*G*UUADE-*****";"(null)";"(null)";"(null)"
"565";"CBRN DECON EQUIPMENT/TROOP";"1331";"CBRNDECONEQUIPMENT/TROOP";"S*G*UUADET*****";"(null)";"(null)";"(null)"
"563";"CBRN DECON TROOP";"1329";"CBRNDECONTROOP";"S*G*UUADT-*****";"(null)";"(null)";"(null)"
"760";"CBRN EQUIPMENT";"571";"CBRNEQUIPMENT";"S*G*EXN---*****";"(null)";"(null)";"(null)"
"566";"CBRN LABORATORY";"1332";"CBRNLABORATORY";"S*G*UUAL--*****";"(null)";"(null)";"(null)"
"559";"CBRN NUCLEAR";"267";"NUCLEAR";"S*G*UUAN--*****";"(null)";"(null)";"(null)"
"770";"CHEMICAL";"582";"CHEMICAL";"S*G*IRNC--H****";"(null)";"(null)";"(null)"
"356";"CIVIL FIXED WING";"73";"FIXEDWING";"S*A*CF----*****";"(null)";"(null)";"(null)"
"755";"CIVILIAN VEHICLE";"565";"CIVILIANVEHICLE";"S*G*EVC---*****";"(null)";"(null)";"(null)"
"357";"CIVIL ROTARY WING";"74";"ROTARYWING";"S*A*CH----*****";"(null)";"(null)";"(null)"
"604";"COMBAT SERVICE SUPPORT";"321";"COMBATSERVICESUPPORT";"S*G*US----*****";"(null)";"(null)";"(null)"
"736";"COMBAT SERVICE SUPPORT VEHICLE";"544";"COMBATSERVICESUPPORTVEHICLE";"S*G*EVAS--*****";"(null)";"(null)";"(null)"
"547";"COMBAT SUPPORT";"255";"COMBATSUPPORT";"S*G*UU----*****";"(null)";"(null)";"(null)"
"748";"CONSTRUCTION VEHICLE";"556";"CONSTRUCTIONVEHICLE";"S*G*EVEC--*****";"(null)";"(null)";"(null)"
"742";"CROSS-COUNTRY TRUCK";"550";"CROSS-COUNTRYTRUCK";"S*G*EVUX--*****";"212";"TATRA Tanker Fuel";"742"
"742";"CROSS-COUNTRY TRUCK";"550";"CROSS-COUNTRYTRUCK";"S*G*EVUX--*****";"50";"Truck 2t off-road";"742"
"772";"DECON";"585";"DECON";"S*G*IPD---H****";"(null)";"(null)";"(null)"
"676";"DIRECT FIRE GUN";"520";"DIRECTFIREGUN";"S*G*EWD---*****";"(null)";"(null)";"(null)"
"681";"DIRECT FIRE GUN HEAVY";"525";"DIRECTFIREGUNHEAVY";"S*G*EWDH--*****";"(null)";"(null)";"(null)"
"682";"DIRECT FIRE GUN HEAVY SELF-PRO";"526";"DIRECTFIREGUNHEAVYSELF-PROPELLED";"S*G*EWDHS-*****";"(null)";"(null)";"(null)"
"677";"DIRECT FIRE GUN LIGHT";"521";"DIRECTFIREGUNLIGHT";"S*G*EWDL--*****";"(null)";"(null)";"(null)"
"678";"DIRECT FIRE GUN LIGHT SELF PRO";"522";"DIRECTFIREGUNLIGHTSELF-PROPELLED";"S*G*EWDLS-*****";"(null)";"(null)";"(null)"
"679";"DIRECT FIRE GUN MEDIUM";"523";"DIRECTFIREGUNMEDIUM";"S*G*EWDM--*****";"(null)";"(null)";"(null)"
"680";"DIRECT FIRE GUN MEDIUM SELF-PR";"524";"DIRECTFIREGUNMEDIUMSELF-PROPELLED";"S*G*EWDMS-*****";"(null)";"(null)";"(null)"
"753";"DOZER";"562";"DOZER";"S*G*EVED--*****";"215";"CAT Excavator";"753"
"746";"EARTHMOVER";"554";"EARTHMOVER";"S*G*EVEE--*****";"(null)";"(null)";"(null)"
"774";"ELCECTRIC POWER FACILITY";"590";"ELECTRICPOWERFACILITY";"S*G*IUE---H****";"(null)";"(null)";"(null)"
"758";"EMPLACED SENSOR";"568";"EMPLACEDSENSOR";"S*G*ESE---*****";"(null)";"(null)";"(null)"
"467";"ENGINEER";"159";"ENGINEER";"S*G*UCE---*****";"(null)";"(null)";"(null)"
"472";"ENGINEER COMBAT";"160";"ENGINEERCOMBAT";"S*G*UCEC--*****";"(null)";"(null)";"(null)"
"473";"ENGINEER COMBAT AIR ASSAULT";"161";"ENGINEERCOMBATAIRASSAULT";"S*G*UCECS-*****";"(null)";"(null)";"(null)"
"478";"ENGINEER COMBAT AIRBORNE";"162";"ENGINEERCOMBATAIRBORNE";"S*G*UCECA-*****";"(null)";"(null)";"(null)"
"475";"ENGINEER COMBAT BRIDGING";"171";"ENGINEERCOMBATBRIDGING";"S*G*UCEC--*****";"(null)";"(null)";"(null)"
"481";"ENGINEER COMBAT HEAVY";"166";"ENGINEERCOMBATHEAVY";"S*G*UCECH-*****";"(null)";"(null)";"(null)"
"479";"ENGINEER COMBAT LIGHT";"164";"ENGINEERCOMBATLIGHT";"S*G*UCECL-*****";"(null)";"(null)";"(null)"
"482";"ENGINEER COMBAT MECH (TRACK)";"167";"ENGINEERCOMBATMECHANIZED(TRACK)";"S*G*UCECT-*****";"(null)";"(null)";"(null)"
"480";"ENGINEER COMBAT MEDIUM";"165";"ENGINEERCOMBATMEDIUM";"S*G*UCECM-*****";"(null)";"(null)";"(null)"
"476";"ENGINEER COMBAT MINE CLEARING";"172";"ENGINEERCOMBATMINECLEARING";"S*G*UCEC--*****";"(null)";"(null)";"(null)"
"477";"ENGINEER COMBAT MINE LAYING";"173";"ENGINEERCOMBATMINELAYING";"S*G*UCEC--*****";"(null)";"(null)";"(null)"
"483";"ENGINEER COMBAT MOTORIZED";"168";"ENGINEERCOMBATMOTORIZED";"S*G*UCECW-*****";"(null)";"(null)";"(null)"
"484";"ENGINEER COMBAT MOUNTAIN";"169";"ENGINEERCOMBATMOUNTAIN";"S*G*UCECO-*****";"(null)";"(null)";"(null)"
"474";"ENGINEER COMBAT RECON";"170";"ENGINEERCOMBATRECON";"S*G*UCECR-*****";"(null)";"(null)";"(null)"
"485";"ENGINEER CONSTRUCTION";"175";"ENGINEERCONSTRUCTION";"S*G*UCEN--*****";"(null)";"(null)";"(null)"
"744";"ENGINEER VEHICLE";"552";"ENGINEERVEHICLE";"S*G*EVE---*****";"(null)";"(null)";"(null)"
"657";"ENVIRONMENTAL PROTECTION";"463";"ENVIRONMENTALPROTECTION";"S*G*USXEP-*****";"(null)";"(null)";"(null)"
"576";"EW CORPS";"280";"CORPS";"S*G*UUMSEC*****";"(null)";"(null)";"(null)"
"575";"EW THEATRE";"279";"THEATRE";"S*G*UUMSET*****";"(null)";"(null)";"(null)"
"602";"EXPLOSIVE ORDNANCE DISPOSAL";"317";"EXPLOSIVEORDINANCEDISPOSAL";"S*G*UUE---*****";"(null)";"(null)";"(null)"
"490";"FIELD ARTELLERY HOWITZER/GUN AIRBORNE";"181";"AIRBORNE";"S*G*UCFHA-*****";"(null)";"(null)";"(null)"
"495";"FIELD ARTELLERY HOWITZER/GUN AMPHIBIOUS";"187";"AMPHIBIOUS";"S*G*UCFHX-*****";"(null)";"(null)";"(null)"
"494";"FIELD ARTELLERY HOWITZER/GUN HEAVY";"186";"HEAVY";"S*G*UCFHH-*****";"(null)";"(null)";"(null)"
"492";"FIELD ARTELLERY HOWITZER/GUN LIGHT";"184";"LIGHT";"S*G*UCFHL-*****";"(null)";"(null)";"(null)"
"493";"FIELD ARTELLERY HOWITZER/GUN MEDIUM";"185";"MEDIUM";"S*G*UCFHM-*****";"(null)";"(null)";"(null)"
"491";"FIELD ARTELLERY HOWITZER/GUN MOUNTAIN";"183";"MOUNTAIN";"S*G*UCFHO-*****";"(null)";"(null)";"(null)"
"496";"FIELD ARTELLERY ROCKET";"188";"ROCKET";"S*G*UCFR--*****";"(null)";"(null)";"(null)"
"498";"FIELD ARTILEERY ROCKET SINGLE";"190";"SINGLEROCKETSELFPROPELLED";"S*G*UCFRSS*****";"(null)";"(null)";"(null)"
"486";"FIELD ARTILLERY";"177";"FIELDARTILLERY";"S*G*UCF---*****";"(null)";"(null)";"(null)"
"521";"FIELD ARTILLERY ARTILLERY SURV";"214";"ARTILLERYSURVEY";"S*G*UCFS--*****";"(null)";"(null)";"(null)"
"523";"FIELD ARTILLERY FIRE DIRECTION CENTRE";"224";"FIREDIRECTIONCENTRE";"S*G*UCF---*****";"(null)";"(null)";"(null)"
"487";"FIELD ARTILLERY HOWITZER/GUN";"178";"HOWITZER/GUN";"S*G*UCFH--*****";"(null)";"(null)";"(null)"
"489";"FIELD ARTILLERY HOWITZER/GUN AIR ASSAULT";"180";"AIRASSAULT";"S*G*UCFHS-*****";"(null)";"(null)";"(null)"
"488";"FIELD ARTILLERY HOWITZER/GUN SELF-PROPELLED";"179";"SELFPROPELLED";"S*G*UCFHE-*****";"(null)";"(null)";"(null)"
"522";"FIELD ARTILLERY METEOROLOGICAL";"219";"METEOROLOGICAL";"S*G*UCFO--*****";"(null)";"(null)";"(null)"
"513";"FIELD ARTILLERY MORTAR";"205";"MORTAR";"S*G*UCFM--*****";"(null)";"(null)";"(null)"
"514";"FIELD ARTILLERY MORTAR SP TRAC";"206";"SELFPROPELLED(SP)TRACKEDMORTAR";"S*G*UCFMS-*****";"(null)";"(null)";"(null)"
"515";"FIELD ARTILLERY MORTAR SP WHEE";"207";"SPWHEELEDMORTAR";"S*G*UCFMSW*****";"(null)";"(null)";"(null)"
"516";"FIELD ARTILLERY MORTAR TOWED";"208";"TOWEDMORTAR";"S*G*UCFMT-*****";"(null)";"(null)";"(null)"
"518";"FIELD ARTILLERY MORTAR TOWED A";"210";"TOWEDAIRASSAULTMORTAR";"S*G*UCFMTS*****";"(null)";"(null)";"(null)"
"517";"FIELD ARTILLERY MORTAR TOWED A";"209";"TOWEDAIRBORNEMORTAR";"S*G*UCFMTA*****";"(null)";"(null)";"(null)"
"519";"FIELD ARTILLERY MORTAR TOWED M";"212";"TOWEDMOUNTAINMORTAR";"S*G*UCFMTO*****";"(null)";"(null)";"(null)"
"524";"FIELD ARTILLERY OBERSERVER";"225";"OBERSERVER";"S*G*UCF---*****";"(null)";"(null)";"(null)"
"502";"FIELD ARTILLERY ROCKET MULTI R";"194";"MULTIROCKETSELFPROPELLED";"S*G*UCFRMS*****";"(null)";"(null)";"(null)"
"504";"FIELD ARTILLERY ROCKET MULTI ROCKET LAUNCER MULTI";"196";"MULTIROCKETTOWED";"S*G*UCFRMT*****";"(null)";"(null)";"(null)"
"503";"FIELD ARTILLERY ROCKET MULTI ROCKET LAUNCER MULTI";"195";"MULTIROCKETTRUCK";"S*G*UCFRMR*****";"(null)";"(null)";"(null)"
"501";"FIELD ARTILLERY ROCKET MULTI ROCKET LAUNCHER";"193";"MULTIROCKETLAUNCHER";"S*G*UCFRM-*****";"(null)";"(null)";"(null)"
"497";"FIELD ARTILLERY ROCKET SINGLE";"189";"SINGLEROCKETLAUNCHER";"S*G*UCFRS-*****";"(null)";"(null)";"(null)"
"499";"FIELD ARTILLERY ROCKET SINGLE ROCKET LAUNCHER SING";"191";"SINGLEROCKETTRUCK";"S*G*UCFRSR*****";"(null)";"(null)";"(null)"
"500";"FIELD ARTILLERY ROCKET SINGLE ROCKET LAUNCHER SING";"192";"SINGLEROCKETTOWED";"S*G*UCFRST*****";"(null)";"(null)";"(null)"
"506";"FIELD ARTILLERY TARGET ACQUISI";"198";"RADAR";"S*G*UCFTR-*****";"(null)";"(null)";"(null)"
"505";"FIELD ARTILLERY TARGET ACQUISITION";"197";"TARGETACQUISITION";"S*G*UCFT--*****";"(null)";"(null)";"(null)"
"510";"FIELD ARTILLERY TARGET ACQUISITION DISMOUNTED";"202";"TARGETACQUISITIONDISMOUNTED";"S*G*UCFTCD*****";"(null)";"(null)";"(null)"
"508";"FIELD ARTILLERY TARGET ACQUISITION FLASH (OPTICAL)";"200";"FLASH(OPTICAL)";"S*G*UCFTF-*****";"(null)";"(null)";"(null)"
"509";"FIELD ARTILLERY TARGET ACQUISITION MOUNTED";"201";"TARGETACQUISITIONMOUNTED";"S*G*UCFTC-*****";"(null)";"(null)";"(null)"
"512";"FIELD ARTILLERY TARGET ACQUISITION NAVAL GUNFIRE";"204";"TARGETACQUISITIONNAVALGUNFIRE";"S*G*UCFTA-*****";"(null)";"(null)";"(null)"
"507";"FIELD ARTILLERY TARGET ACQUISITION SOUND";"199";"SOUND";"S*G*UCFTS-*****";"(null)";"(null)";"(null)"
"511";"FIELD ARTILLERY TARGET ACQUISITION TRACKED";"203";"TARGETACQUISITIONTRACKED";"S*G*UCFTCM*****";"(null)";"(null)";"(null)"
"345";"FIXED WING DRONE (RPV/UAE)";"36";"DRONE(RPV/UAV)";"S*A*MFQ---*****";"(null)";"(null)";"(null)"
"761";"FLAME THROWER";"572";"FLAMETHROWER";"S*G*EXF---*****";"(null)";"(null)";"(null)"
"660";"GENERAL HEADQUATERS AND SERVICE";"466";"GENERALHEADQUARTERSANDSERVICE";"S*G*UH----*****";"(null)";"(null)";"(null)"
"779";"GOVERNMENT LEADERSHIP";"603";"GOVERNMENTLEADERSHIP";"S*G*IG----H****";"(null)";"(null)";"(null)"
"703";"GRENADE LAUNCHER";"500";"GRENADELAUNCHER";"S*G*EWZ---*****";"(null)";"(null)";"(null)"
"706";"GRENADE LAUNCHER HEAVY";"503";"GRENADELAUNCHERHEAVY";"S*G*EWZH--*****";"(null)";"(null)";"(null)"
"704";"GRENADE LAUNCHER LIGHT";"501";"GRENADELAUNCHERLIGHT";"S*G*EWZL--*****";"(null)";"(null)";"(null)"
"705";"GRENADE LAUNCHER MEDIUM";"502";"GRENADELAUNCHERMEDIUM";"S*G*EWZM--*****";"(null)";"(null)";"(null)"
"662";"GROUND TRACK EQUIPMENT";"468";"GROUNDTRACKEQUIPMENT";"S*G*E-----*****";"(null)";"(null)";"(null)"
"358";"GROUND TRACK UNIT";"77";"UNIT";"S*G*U-----*****";"217";"Soldier (Role Player)";"358"
"358";"GROUND TRACK UNIT";"77";"UNIT";"S*G*U-----*****";"106";"Soldier";"358"
"363";"GROUND TRACK UNIT COMBAT";"78";"COMBAT";"S*G*UC----*****";"(null)";"(null)";"(null)"
"520";"GROUND TRACK UNIT COMBAT FIELD ARTILLERY MORTAR AM";"213";"AMPHIBIOUSMORTAR";"S*G*UCFML-*****";"(null)";"(null)";"(null)"
"659";"GROUND TRACK UNIT GENERAL HEADQUATERS";"465";"UNITGENERALHEADQUARTERS";"S*G*UH----*****";"(null)";"(null)";"(null)"
"723";"GROUND VEHICLE";"531";"GROUNDVEHICLE";"S*G*EV----*****";"(null)";"(null)";"(null)"
"702";"HEAVY MACHINE GUN";"499";"HEAVYMACHINEGUN";"S*G*EWRH--*****";"129";"Soldier HMG";"702"
"785";"HOSPITAL";"609";"HOSPITAL";"S*G*IXH---H****";"(null)";"(null)";"(null)"
"711";"HOWITZER";"508";"HOWITZER";"S*G*EWH---*****";"(null)";"(null)";"(null)"
"716";"HOWITZER HEAVY";"513";"HOWITZERHEAVY";"S*G*EWHH--*****";"(null)";"(null)";"(null)"
"717";"HOWITZER HEAVY SELF-PROPELLED";"514";"HOWITZERHEAVYSELF-PROPELLED";"S*G*EWHHS-*****";"(null)";"(null)";"(null)"
"712";"HOWITZER LIGHT";"509";"HOWITZERLIGHT";"S*G*EWHL--*****";"(null)";"(null)";"(null)"
"713";"HOWITZER LIGHT SELF-PROPELLED";"510";"HOWITZERLIGHTSELF-PROPELLED";"S*G*EWHLS-*****";"(null)";"(null)";"(null)"
"714";"HOWITZER MEDIUM";"511";"HOWITZERMEDIUM";"S*G*EWHM--*****";"(null)";"(null)";"(null)"
"715";"HOWITZER MEDIUM SELF-PROPELLED";"512";"HOWITZERMEDIUMSELF-PROPELLED";"S*G*EWHMS-*****";"(null)";"(null)";"(null)"
"449";"INFANTRY";"149";"INFANTRY";"S*G*UCI---*****";"161";"TM";"449"
"449";"INFANTRY";"149";"INFANTRY";"S*G*UCI---*****";"226";"TEST PLAYER";"449"
"449";"INFANTRY";"149";"INFANTRY";"S*G*UCI---*****";"232";"0Soldier";"449"
"449";"INFANTRY";"149";"INFANTRY";"S*G*UCI---*****";"128";"TM Leader";"449"
"463";"INFANTRY AIR ASSAULT";"154";"INFANTRYAIRASSAULT";"S*G*UCIS--*****";"(null)";"(null)";"(null)"
"462";"INFANTRY AIRBORNE";"153";"INFANTRYAIRBORNE";"S*G*UCIA--*****";"(null)";"(null)";"(null)"
"466";"INFANTRY FIGHTING VEHICLE";"157";"INFANTRYFIGHTINGVEHICLE";"S*G*UCII--*****";"(null)";"(null)";"(null)"
"454";"INFANTRY LIGHT";"150";"INFANTRYLIGHT";"S*G*UCIL--*****";"(null)";"(null)";"(null)"
"464";"INFANTRY MECHANIZED";"155";"INFANTRYMECHANIZED";"S*G*UCIZ--*****";"(null)";"(null)";"(null)"
"456";"INFANTRY MOTORIZED";"151";"INFANTRYMOTORIZED";"S*G*UCIM--*****";"(null)";"(null)";"(null)"
"461";"INFANTRY MOUNTAIN";"152";"INFANTRYMOUNTAIN";"S*G*UCIO--*****";"(null)";"(null)";"(null)"
"465";"INFANTRY NAVAL";"156";"INFANTRYNAVAL";"S*G*UCIN--*****";"(null)";"(null)";"(null)"
"600";"INFORMATION OPERATIONS";"315";"INFORMATIONWARFAREUNIT";"S*G*UUI---*****";"(null)";"(null)";"(null)"
"765";"INSTALLATION";"576";"INSTALLATION";"S*G*I-----H****";"225";"MEU";"765"
"765";"INSTALLATION";"576";"INSTALLATION";"S*G*I-----H****";"224";"Building";"765"
"666";"INTERMEDIATE RANGE AD MISSILE";"473";"INTERMEDIATERANGEADMISSILELAUNCH";"S*G*EWMAI-*****";"(null)";"(null)";"(null)"
"670";"INTERMEDIATE RANGE SS MISSILE";"478";"INTERMEDIATERANGESSMISSILELAUNCH";"S*G*EWMSI-*****";"(null)";"(null)";"(null)"
"382";"INTERNAL SECURITY FORCES";"246";"INTERNALSECURITYFORCES";"S*G*UCS---*****";"(null)";"(null)";"(null)"
"390";"INTERNAL SECURITY FORCES AVIAT";"254";"AVIATION";"S*G*UCSA--*****";"(null)";"(null)";"(null)"
"387";"INTERNAL SECURITY FORCES GROUN";"251";"MECHANIZEDGROUND";"S*G*UCSGA-*****";"(null)";"(null)";"(null)"
"384";"INTERNAL SECURITY FORCES GROUND";"248";"GROUND";"S*G*UCSG--*****";"(null)";"(null)";"(null)"
"385";"INTERNAL SECURITY FORCES GROUND DISMOUNTED";"249";"DISMOUNTEDGROUND";"S*G*UCSGD-*****";"(null)";"(null)";"(null)"
"386";"INTERNAL SECURITY FORCES GROUND MOTORIZED";"250";"MOTORIZEDGROUND";"S*G*UCSGM-*****";"(null)";"(null)";"(null)"
"389";"INTERNAL SECURITY FORCES RAILROAD";"253";"RAILROAD";"S*G*UCSR--*****";"(null)";"(null)";"(null)"
"383";"INTERNAL SECURITY FORCES RIVERINE";"247";"RIVERINE";"S*G*UCSW--*****";"(null)";"(null)";"(null)"
"388";"INTERNAL SECURITY FORCES WHEEL";"252";"WHEELEDMECHANIZED";"S*G*UCSM--*****";"(null)";"(null)";"(null)"
"791";"LANDING CRAFT";"623";"LANDINGCRAFT";"S*S*CALC--*****";"(null)";"(null)";"(null)"
"790";"LANDING SHIP";"622";"LANDINGSHIP";"S*S*CALS--*****";"(null)";"(null)";"(null)"
"601";"LANDING SUPPORT";"316";"LANDINGSUPPORT";"S*G*UUX---*****";"(null)";"(null)";"(null)"
"762";"LAND MINES";"573";"LANDMINES";"S*G*EXM---*****";"(null)";"(null)";"(null)"
"763";"LAND MINES, LETHAL";"574";"LANDMINES,LETHAL";"S*G*EXMC--*****";"(null)";"(null)";"(null)"
"759";"LASER";"570";"LASER";"S*G*EXL---*****";"(null)";"(null)";"(null)"
"584";"LAW ENFORCEMENT UNIT";"292";"LAWENFORCEMENTUNIT";"S*G*UUL---*****";"(null)";"(null)";"(null)"
"587";"LAW ENFORCEMENT UNIT CIVILIAN LAW ENFORCEMENT";"295";"CIVILIANLAWENFORCEMENT";"S*G*UULC--*****";"(null)";"(null)";"(null)"
"588";"LAW ENFORCEMENT UNIT CRIMINAL INVESTIGATION DIVISI";"297";"CENTRALINTELLIGENCEDIVISION(CID)";"S*G*UULD--*****";"(null)";"(null)";"(null)"
"586";"LAW ENFORCEMENT UNIT MILITARY POLICE";"294";"MILITARYPOLICE";"S*G*UULM--*****";"(null)";"(null)";"(null)"
"585";"LAW ENFORCEMENT UNIT SHORE PATROL";"293";"SHOREPATROL";"S*G*UULS--*****";"(null)";"(null)";"(null)"
"794";"LEISURE CRAFT";"665";"LEISURECRAFT";"S*S*XR----*****";"(null)";"(null)";"(null)"
"764";"LESS THAN LETHAL";"575";"LESSTHANLETHAL";"S*G*EXML--*****";"(null)";"(null)";"(null)"
"737";"LIGHT ARMOURED VEHICLE";"545";"LIGHTARMOUREDVEHICLE";"S*G*EVAL--*****";"(null)";"(null)";"(null)"
"701";"LIGHT MACHINE GUN";"498";"LIGHTMACHINEGUN";"S*G*EWRL--*****";"131";"Soldier LMG";"701"
"741";"LIMITED CROSS-COUNTRY TRUCK";"549";"LIMITEDCROSS-COUNTRYTRUCK";"S*G*EVUL--*****";"(null)";"(null)";"(null)"
"667";"LONG RANGE AD MISSILE LAUNCH";"474";"LONGRANGEADMISSILELAUNCH";"S*G*EWMAL-*****";"(null)";"(null)";"(null)"
"671";"LONG RANGE SS MISSILE LAUNCH";"479";"LONGRANGESSMISSILELAUNCH";"S*G*EWMSL-*****";"(null)";"(null)";"(null)"
"648";"MAINTENANCE";"442";"MAINTENANCE";"S*G*USX---*****";"(null)";"(null)";"(null)"
"654";"MAINTENANCE BATTLE DAMAGE REPA";"460";"BATTLEDAMAGEREPAIR";"S*G*USXBDR*****";"(null)";"(null)";"(null)"
"653";"MAINTENANCE ELECTRO-OPTICAL";"457";"ELECTRO-OPTICAL";"S*G*USXE--*****";"(null)";"(null)";"(null)"
"649";"MAINTENANCE HEAVY";"445";"MAINTENANCEHEAVY";"S*G*USXH--*****";"(null)";"(null)";"(null)"
"651";"MAINTENANCE ORDINANCE";"451";"ORDINANCE";"S*G*USXO--*****";"(null)";"(null)";"(null)"
"652";"MAINTENANCE ORDINANCE MISSILE";"454";"ORDINANCEMISSILE";"S*G*USXOM-*****";"(null)";"(null)";"(null)"
"655";"MAINTENANCE PREVENTIVE MAINTEN";"461";"PREVENTIVEMAINTANANCE";"S*G*USXPM-*****";"(null)";"(null)";"(null)"
"650";"MAINTENANCE RECOVERY";"448";"MAINTENANCERECOVERY";"S*G*USXR--*****";"(null)";"(null)";"(null)"
"623";"MEDICAL DENTAL";"373";"MEDICALDENTAL";"S*G*USMD--*****";"(null)";"(null)";"(null)"
"784";"MEDICAL FACILITY";"608";"MEDICALFACILITY";"S*G*IX----H****";"(null)";"(null)";"(null)"
"624";"MEDICAL PSYCHOLOGICAL";"376";"MEDICALPSYCHOLOGICAL";"S*G*USMP--*****";"(null)";"(null)";"(null)"
"621";"MEDICAL TREATMENT FACILITY";"367";"MEDICALTREATMENTFACILITY";"S*G*USMM--*****";"(null)";"(null)";"(null)"
"622";"MEDICAL VETERINARY";"370";"MEDICALVETERINARY";"S*G*USMV--*****";"(null)";"(null)";"(null)"
"343";"MILITARY";"7";"MILITARY";"S*A*M-----*****";"(null)";"(null)";"(null)"
"780";"MILITARY BASE/FACILITY";"604";"MILITARYBASE/FACILITY";"S*G*IB----H****";"(null)";"(null)";"(null)"
"344";"MILITARY FIXED WING";"8";"FIXEDWING";"S*A*MF----*****";"(null)";"(null)";"(null)"
"567";"MILITARY INTELLIGENCE";"271";"MILITARYINTELLIGENCE";"S*G*UUM---*****";"(null)";"(null)";"(null)"
"568";"MILITARY INTELLIGENCE AERIAL EXPLOITATION";"272";"AERIALEXPLOITATION";"S*G*UUMA--*****";"(null)";"(null)";"(null)"
"577";"MILITARY INTELLIGENCE COUNTER INTELLIGENCE";"281";"COUNTERINTELLIGENCE";"S*G*UUMC--*****";"(null)";"(null)";"(null)"
"573";"MILITARY INTELLIGENCE ELECTRON";"277";"INTERCEPT";"S*G*UUMSEI*****";"(null)";"(null)";"(null)"
"572";"MILITARY INTELLIGENCE ELECTRON";"276";"DIRECTIONFINDING";"S*G*UUMSED*****";"(null)";"(null)";"(null)"
"571";"MILITARY INTELLIGENCE ELECTRON";"275";"ARMOUREDWHEELEDVEHICLE";"S*G*UUMSEA*****";"(null)";"(null)";"(null)"
"570";"MILITARY INTELLIGENCE ELECTRONIC WARFARE";"274";"ELECTRONICWARFARE";"S*G*UUMSE-*****";"(null)";"(null)";"(null)"
"574";"MILITARY INTELLIGENCE ELECTRONIC WARFARE JAMMING";"278";"JAMMING";"S*G*UUMSEJ*****";"(null)";"(null)";"(null)"
"582";"MILITARY INTELLIGENCE INTERROGATION";"290";"INTERROGATION";"S*G*UUMQ--*****";"(null)";"(null)";"(null)"
"583";"MILITARY INTELLIGENCE JOINT INTELLIGENCE CENTRE";"291";"JOINTINTELLIGENCECENTRE";"S*G*UUMJ--*****";"(null)";"(null)";"(null)"
"581";"MILITARY INTELLIGENCE OPERATIONS";"288";"OPERATIONS";"S*G*UUMO--*****";"(null)";"(null)";"(null)"
"569";"MILITARY INTELLIGENCE SIGNALS";"273";"SIGNALINTELLIGENCE(SIGINT)";"S*G*UUMS--*****";"(null)";"(null)";"(null)"
"579";"MILITARY INTELLIGENCE SURVEILL";"283";"GROUNDSURVEILLANCERADAR";"S*G*UUMRG-*****";"(null)";"(null)";"(null)"
"578";"MILITARY INTELLIGENCE SURVEILLANCE";"282";"SURVEILLANCE";"S*G*UUMR--*****";"(null)";"(null)";"(null)"
"580";"MILITARY INTELLIGENCE SURVEILLANCE SENSOR";"284";"SENSOR";"S*G*UUMRS-*****";"(null)";"(null)";"(null)"
"346";"MILITARY ROTARY WING";"39";"ROTARYWING";"S*A*MH----*****";"195";"Apache";"346"
"766";"MINE";"578";"MINE";"S*G*IRM---H****";"(null)";"(null)";"(null)"
"749";"MINE LAYING VEHICLE";"557";"MINELAYINGVEHICLE";"S*G*EVEM--*****";"4";"Trailer, Minelaying";"749"
"675";"MISSILE LAUNCHER AT HEAVY";"483";"MISSILELAUNCHERATHEAVY";"S*G*EWMTH-*****";"(null)";"(null)";"(null)"
"674";"MISSILE LAUNCHER AT MEDIUM";"482";"MISSILELAUNCHERATMEDIUM";"S*G*EWMTM-*****";"(null)";"(null)";"(null)"
"663";"MISSILE LAUNCHERS";"470";"MISSILELAUNCHERS";"S*G*EWM---*****";"(null)";"(null)";"(null)"
"672";"MISSILE LAUNCHERS ANTI TANK (A";"480";"MISSILELAUNCHERSANTITANK(AT)";"S*G*EWMT--*****";"(null)";"(null)";"(null)"
"673";"MISSILE LAUNCHERS AT LIGHT";"481";"MISSILELAUNCHERSATLIGHT";"S*G*EWMTL-*****";"(null)";"(null)";"(null)"
"544";"MISSILE (SURF-SURF)";"243";"MISSILE(SURFACE-SURFACE)";"S*G*UCM---*****";"(null)";"(null)";"(null)"
"546";"MISSILE (SURF-SURF) STRATEGIC";"245";"MISSILE(SURFACE-SURFACE)STRATEGIC";"S*G*UCMS--*****";"(null)";"(null)";"(null)"
"545";"MISSILE (SURF-SURF) TACTICAL";"244";"MISSILE(SURFACE-SURFACE)TACTICAL";"S*G*UCMT--*****";"(null)";"(null)";"(null)"
"707";"MORTAR";"504";"MORTAR";"S*G*EWO---*****";"209";"Soldier Mortar";"707"
"710";"MORTAR HEAVY";"507";"MORTARHEAVY";"S*G*EWOH--*****";"(null)";"(null)";"(null)"
"708";"MORTAR LIGHT";"505";"MORTARLIGHT";"S*G*EWOL--*****";"(null)";"(null)";"(null)"
"709";"MORTAR MEDIUM";"506";"MORTARMEDIUM";"S*G*EWOM--*****";"(null)";"(null)";"(null)"
"747";"MULTIFUNCTIONAL EARTHMOVER/DIG";"555";"MULTIFUNCTIONALEARTHMOVER/DIGGER";"S*G*EVEE--*****";"(null)";"(null)";"(null)"
"691";"MULTIPLE ROCKET LAUNCHER";"488";"MULTIPLEROCKETLAUNCHER";"S*G*EWX---*****";"(null)";"(null)";"(null)"
"694";"MULTIPLE ROCKET LAUNCHER HEAVY";"491";"MULTIPLEROCKETLAUNCHERHEAVY";"S*G*EWXH--*****";"(null)";"(null)";"(null)"
"692";"MULTIPLE ROCKET LAUNCHER LIGHT";"489";"MULTIPLEROCKETLAUNCHERLIGHT";"S*G*EWXL--*****";"(null)";"(null)";"(null)"
"693";"MULTIPLE ROCKET LAUNCHER MEDIU";"490";"MULTIPLEROCKETLAUNCHERMEDIUM";"S*G*EWXM--*****";"(null)";"(null)";"(null)"
"771";"NUCLEAR";"583";"NUCLEAR";"S*G*IRNN--H****";"(null)";"(null)";"(null)"
"188";"O/C Force";"5";"SPACESTATION";"S*P*T-----*****";"113";"O/C Staff";"188"
"188";"O/C Force";"5";"SPACESTATION";"S*P*T-----*****";"180";"O/C TM";"188"
"188";"O/C Force";"5";"SPACESTATION";"S*P*T-----*****";"114";"O/C Force";"188"
"807";"O/C Force CE";"5";"SPACESTATION";"S*P*T-----*****";"(null)";"(null)";"(null)"
"793";"OILER/TANKER";"655";"OILER/TANKER";"S*S*XMO---*****";"(null)";"(null)";"(null)"
"792";"PATROL";"630";"PATROL";"S*S*CP----*****";"(null)";"(null)";"(null)"
"767";"PETROLEUM/GAS/OIL";"579";"PETROLEUM/GAS/OIL";"S*G*IRP---H****";"(null)";"(null)";"(null)"
"656";"PIPELINE";"462";"PIPELINE";"S*G*USXP--*****";"(null)";"(null)";"(null)"
"775";"PUBLIC WATER SERVICES";"591";"PUBLICWATERSERVICES";"S*G*IUP---H****";"(null)";"(null)";"(null)"
"757";"RADAR";"567";"RADAR";"S*G*ESR---*****";"(null)";"(null)";"(null)"
"525";"RECONNAISSANCE";"226";"RECONNAISSANCE";"S*G*UCR---*****";"(null)";"(null)";"(null)"
"535";"RECONNAISSANCE AIR ASSAULT";"234";"RECONNAISSANCEAIRASSAULT";"S*G*UCRS--*****";"(null)";"(null)";"(null)"
"536";"RECONNAISSANCE AIRBORNE";"235";"RECONNAISSANCEAIRBORNE";"S*G*UCRA--*****";"(null)";"(null)";"(null)"
"539";"RECONNAISSANCE AMPHIBIOUS";"238";"RECONNAISSANCEMARINE";"S*G*UCRR--*****";"(null)";"(null)";"(null)"
"540";"RECONNAISSANCE AMPHIBIOUS DIVI";"239";"RECONNAISSANCEMARINEDIVISION";"S*G*UCRRD-*****";"(null)";"(null)";"(null)"
"541";"RECONNAISSANCE AMPHIBIOUS FORC";"240";"RECONNAISSANCEMARINEFORCE";"S*G*UCRRF-*****";"(null)";"(null)";"(null)"
"530";"RECONNAISSANCE CAVALRY";"228";"RECONNAISSANCECAVALRY";"S*G*UCRV--*****";"(null)";"(null)";"(null)"
"534";"RECONNAISSANCE CAVALRY AIR";"232";"RECONNAISSANCECAVALRYAIR";"S*G*UCRVO-*****";"(null)";"(null)";"(null)"
"531";"RECONNAISSANCE CAVALRY ARMOURE";"229";"RECONNAISSANCECAVALRYARMOURED";"S*G*UCRVA-*****";"(null)";"(null)";"(null)"
"533";"RECONNAISSANCE CAVALRY GROUND";"231";"RECONNAISSANCECAVALRYGROUND";"S*G*UCRVG-*****";"(null)";"(null)";"(null)"
"532";"RECONNAISSANCE CAVALRY MOTORIZ";"230";"RECONNAISSANCECAVALRYMOTORIZED";"S*G*UCRVM-*****";"(null)";"(null)";"(null)"
"538";"RECONNAISSANCE LIGHT";"237";"RECONNAISSANCELIGHT";"S*G*UCRLL--*****";"(null)";"(null)";"(null)"
"542";"RECONNAISSANCE MARINE LIGHT AR";"241";"RECONNAISSANCEMARINELIGHTARMOUREDRECONNAISSANCE(LA";"S*G*UCRRL-*****";"(null)";"(null)";"(null)"
"537";"RECONNAISSANCE MOUNTAIN";"236";"RECONNAISSANCEMOUNTAIN";"S*G*UCRO--*****";"(null)";"(null)";"(null)"
"543";"RECONNAISSANCE SURVEILLANCE LO";"242";"RECONNAISSANCELONGRANGESURVEILLANCE(LRS)";"S*G*UCRX--*****";"(null)";"(null)";"(null)"
"700";"RIFLE";"497";"RIFLE";"S*G*EWRR--*****";"210";"Soldier Assault Rifle";"700"
"699";"RIFLE/AUTOMATIC WEAPON";"496";"RIFLE/AUTOMATICWEAPON";"S*G*EWR---*****";"205";"Soldier Tgt";"699"
"699";"RIFLE/AUTOMATIC WEAPON";"496";"RIFLE/AUTOMATICWEAPON";"S*G*EWR---*****";"216";"Soldier M203";"699"
"699";"RIFLE/AUTOMATIC WEAPON";"496";"RIFLE/AUTOMATICWEAPON";"S*G*EWR---*****";"153";"Soldier MP";"699"
"438";"ROTARY WING ATTACK";"131";"ATTACKROTARYWING";"S*G*UCVRA-*****";"(null)";"(null)";"(null)"
"347";"ROTARY WING ATTACK";"40";"ATTACK";"S*A*MHA---*****";"(null)";"(null)";"(null)"
"352";"ROTARY WING DRONE (RPV/UAV)";"49";"DRONE(RPV/UAV)";"S*A*MHQ---*****";"(null)";"(null)";"(null)"
"348";"ROTARY WING MEDEVAC";"55";"MEDEVAC";"S*A*MHO---*****";"(null)";"(null)";"(null)"
"351";"ROTARY WING RECCE";"48";"RECONNAISSANCE";"S*A*MHR---*****";"(null)";"(null)";"(null)"
"349";"ROTARY WING SOF";"56";"SPECIALOPERATIONSFORCE(SOF)";"S*A*MHM---*****";"(null)";"(null)";"(null)"
"350";"ROTARY WING UTILITY";"42";"UTILITY";"S*A*MHU---*****";"(null)";"(null)";"(null)"
"782";"SEAPORT/NAVAL BASE";"606";"SEAPORT/NAVALBASE";"S*G*IBN---H****";"(null)";"(null)";"(null)"
"786";"SEA SURFACE INSTALLATION, OIL RIG / PLATFORM";"611";"SEASURFACEINSTALLATION,OILRIG/PLATFORM";"S*G*IRR---H****";"(null)";"(null)";"(null)"
"787";"SEA SURFACE TRACK";"612";"SEASURFACETRACK";"S*S*------*****";"(null)";"(null)";"(null)"
"740";"SEMI";"548";"SEMI";"S*G*EVUS--*****";"(null)";"(null)";"(null)"
"756";"SENSOR";"566";"SENSOR";"S*G*ES----*****";"(null)";"(null)";"(null)"
"616";"SERVICE SUPPORT MEDICAL";"364";"MEDICAL";"S*G*USM---*****";"(null)";"(null)";"(null)"
"641";"SERVICE SUPPORT TRANSPORTATION";"424";"TRANSPORTATION";"S*G*UST---*****";"53";"TATRA Logistics Carrier";"641"
"665";"SHORT RANGE AD MISSILE LAUNCHE";"472";"SHORTRANGEADMISSILELAUNCHERS";"S*G*EWMAS-*****";"(null)";"(null)";"(null)"
"669";"SHORT RANGE SS MISSILE LAUNCH";"477";"SHORTRANGESSMISSILELAUNCH";"S*G*EWMSS-*****";"(null)";"(null)";"(null)"
"593";"SIGNALS UNIT FORWARD COMMUNICATIONS";"303";"FORWARDCOMMUNICATIONS";"S*G*UUSF--*****";"(null)";"(null)";"(null)"
"597";"SIGNALS UNIT SIGNAL SUPPORT";"312";"SIGNALSUPPORT";"S*G*UUSS--*****";"(null)";"(null)";"(null)"
"589";"SIGNAL UNIT";"298";"SIGNALUNIT";"S*G*UUS---*****";"(null)";"(null)";"(null)"
"590";"SIGNAL UNIT AREA";"299";"AREA";"S*G*UUSA--*****";"(null)";"(null)";"(null)"
"592";"SIGNAL UNIT COMMAND OPERATIONS";"302";"COMMANDOPERATIONS";"S*G*UUSO--*****";"(null)";"(null)";"(null)"
"591";"SIGNAL UNIT COMMUNICATION CONF";"300";"COMMUNICATIONCONFIGUREDPACKAGE";"S*G*UUSC--*****";"(null)";"(null)";"(null)"
"599";"SIGNAL UNIT ELECTRONIC RANGING";"314";"ELECTRONICRANGING";"S*G*UUSX--*****";"(null)";"(null)";"(null)"
"594";"SIGNAL UNIT RADIO UNIT";"308";"RADIOUNIT";"S*G*UUSR--*****";"(null)";"(null)";"(null)"
"596";"SIGNAL UNIT RADIO UNIT RELAY";"311";"RELAY";"S*G*UUSRW-*****";"(null)";"(null)";"(null)"
"595";"SIGNAL UNIT RADIO UNIT TACTICA";"309";"TACTICALSATELLITE";"S*G*UUSRS-*****";"(null)";"(null)";"(null)"
"598";"SIGNAL UNIT TELEPHONE SWITCH";"313";"TELEPHONESWITCH";"S*G*UUSW--*****";"(null)";"(null)";"(null)"
"687";"SINGLE ROCKET LAUNCHER";"484";"SINGLEROCKETLAUNCHER";"S*G*EWS---*****";"(null)";"(null)";"(null)"
"690";"SINGLE ROCKET LAUNCHER HEAVY";"487";"SINGLEROCKETLAUNCHERHEAVY";"S*G*EWSH--*****";"(null)";"(null)";"(null)"
"688";"SINGLE ROCKET LAUNCHER LIGHT";"485";"SINGLEROCKETLAUNCHERLIGHT";"S*G*EWSL--*****";"(null)";"(null)";"(null)"
"689";"SINGLE ROCKET LAUNCHER MEDIUM";"486";"SINGLEROCKETLAUNCHERMEDIUM";"S*G*EWSM--*****";"(null)";"(null)";"(null)"
"796";"SOF AVIATION FIXED WING";"707";"SOFUNITFIXEDWING";"S*F*AF----*****";"(null)";"(null)";"(null)"
"797";"SOF AVIATION FIXED WING ATTACK";"708";"SOFUNITATTACK";"S*F*AFA---*****";"(null)";"(null)";"(null)"
"798";"SOF AVIATION FIXED WING UTILIT";"710";"SOFUNITUTILITY";"S*F*AFU---*****";"(null)";"(null)";"(null)"
"799";"SOF AVIATION FIXED WING UTILIT";"711";"SOFUNITUTILITY(LIGHT)";"S*F*AFUL--*****";"(null)";"(null)";"(null)"
"800";"SOF AVIATION ROTARY WING";"715";"SOFUNITROTARYWING";"S*F*AH----*****";"(null)";"(null)";"(null)"
"803";"SOF UNIT GROUND";"727";"SOFUNITGROUND";"S*F*G-----*****";"(null)";"(null)";"(null)"
"805";"SOF UNIT GROUND RANGER";"729";"SOFUNITRANGER";"S*F*GSR---*****";"(null)";"(null)";"(null)"
"804";"SOF UNIT GROUND SPECIAL FORCES";"728";"SOFUNITSPECIALFORCES";"S*F*GS----*****";"(null)";"(null)";"(null)"
"801";"SOF UNIT NAVAL";"722";"SOFUNITSOFUNITNAVAL";"S*F*SN----*****";"(null)";"(null)";"(null)"
"802";"SOF UNIT NAVAL SPECIAL BOAT";"725";"SOFUNITSPECIALBOAT";"S*F*SNB---*****";"(null)";"(null)";"(null)"
"806";"SOF UNIT PSYCHOLOGICAL OPERATI";"730";"SOFUNITPSYCHOLOGICALOPERATIONS(PSYOPS)";"S*F*GSP---*****";"(null)";"(null)";"(null)"
"658";"SPECIAL C2 HEADQUATERS COMPONE";"464";"SPECIALC2HEADQUARTERSCOMPONENT";"S*G*UH----*****";"(null)";"(null)";"(null)"
"795";"SPECIAL OPERATIONS FORCE (SOF)";"705";"SPECIALOPERATIONSFORCE(SOF)UNIT";"S*F*------*****";"(null)";"(null)";"(null)"
"625";"SUPPLY";"379";"SUPPLY";"S*G*USS---*****";"(null)";"(null)";"(null)"
"633";"SUPPLY CLASS I";"382";"SUPPLYCLASSI";"S*G*USS1--*****";"(null)";"(null)";"(null)"
"634";"SUPPLY CLASS II";"385";"SUPPLYCLASSII";"S*G*USS2--*****";"(null)";"(null)";"(null)"
"635";"SUPPLY CLASS III";"388";"SUPPLYCLASSIII";"S*G*USS3--*****";"(null)";"(null)";"(null)"
"636";"SUPPLY CLASS III AVIATION";"391";"SUPPLYCLASSIIIAVIATION";"S*G*USS3A-*****";"(null)";"(null)";"(null)"
"637";"SUPPLY CLASS IV";"394";"SUPPLYCLASSIV";"S*G*USS4--*****";"(null)";"(null)";"(null)"
"627";"SUPPLY CLASS IX";"409";"SUPPLYCLASSIX";"S*G*USS9--*****";"(null)";"(null)";"(null)"
"638";"SUPPLY CLASS V";"397";"SUPPLYCLASSV";"S*G*USS5--*****";"(null)";"(null)";"(null)"
"639";"SUPPLY CLASS VI";"400";"SUPPLYCLASSVI";"S*G*USS6--*****";"(null)";"(null)";"(null)"
"640";"SUPPLY CLASS VII";"403";"SUPPLYCLASSVII";"S*G*USS7--*****";"(null)";"(null)";"(null)"
"626";"SUPPLY CLASS VIII";"406";"SUPPLYCLASSVIII";"S*G*USS8--*****";"(null)";"(null)";"(null)"
"628";"SUPPLY CLASS X";"412";"SUPPLYCLASSX";"S*G*USSX--*****";"(null)";"(null)";"(null)"
"629";"SUPPLY LAUNDRY/BATH";"415";"SUPPLYLAUNDRY/BATH";"S*G*USSL--*****";"(null)";"(null)";"(null)"
"632";"SUPPLY MATERIEL (STOCK)";"1335";"SUPPLYMATERIEL(STOCK)";"S*G*US**--*****";"(null)";"(null)";"(null)"
"630";"SUPPLY WATER";"418";"SUPPLYWATER";"S*G*USSW--*****";"(null)";"(null)";"(null)"
"631";"SUPPLY WATER PURIFICATION";"421";"SUPPLYWATERPURIFICATION";"S*G*USSWP-*****";"(null)";"(null)";"(null)"
"668";"SURFACE- SURFACE (SS) MISSILE";"476";"SURFACE-SURFACE(SS)MISSILELAUNCHER";"S*G*EWMS--*****";"(null)";"(null)";"(null)"
"355";"SURFACE TO AIR MISSILE";"65";"SURFACETOAIRMISSILE(SAM)";"S*A*WMSA--*****";"(null)";"(null)";"(null)"
"354";"SURFACE TO SURFACE MISSILE";"64";"SURFACETOSURFACEMISSILE(SSM)";"S*A*WMSS--*****";"(null)";"(null)";"(null)"
"391";"SURVEILLANCE";"1334";"SURVEILLANCE";"S*G*F-S---*****";"(null)";"(null)";"(null)"
"725";"TANK";"533";"TANK";"S*G*EVAT--*****";"233";"0Vehicle";"725"
"725";"TANK";"533";"TANK";"S*G*EVAT--*****";"43";"MBT";"725"
"725";"TANK";"533";"TANK";"S*G*EVAT--*****";"230";"LEOPARD 2A5";"725"
"730";"TANK HEAVY";"538";"TANKHEAVY";"S*G*EVATH-*****";"(null)";"(null)";"(null)"
"731";"TANK HEAVY RECOVERY";"539";"TANKHEAVYRECOVERY";"S*G*EVATY-*****";"(null)";"(null)";"(null)"
"726";"TANK LIGHT";"534";"TANKLIGHT";"S*G*EVATL-*****";"(null)";"(null)";"(null)"
"727";"TANK LIGHT RECOVERY";"535";"TANKLIGHTRECOVERY";"S*G*EVATW-*****";"110";"BMP3 Recovery";"727"
"728";"TANK MEDIUM";"536";"TANKMEDIUM";"S*G*EVATM-*****";"(null)";"(null)";"(null)"
"729";"TANK MEDIUM RECOVERY";"537";"TANKMEDIUMRECOVERY";"S*G*EVATX-*****";"(null)";"(null)";"(null)"
"773";"TELECOMMUNICATIONS FACILITY";"589";"TELECOMMUNICATIONSFACILITY";"S*G*IUT---H****";"(null)";"(null)";"(null)"
"603";"TOPOGRAPHIC";"318";"TOPOGRAPHIC";"S*G*UUT---*****";"(null)";"(null)";"(null)"
"751";"TRAILER MOUNTED";"559";"TRAILERMOUNTED";"S*G*EVEMT-*****";"(null)";"(null)";"(null)"
"754";"TRAIN LOCOMOTIVE";"564";"TRAINLOCOMOTIVE";"S*G*EVST--*****";"(null)";"(null)";"(null)"
"645";"TRANSPORTATION APOD/APOE";"436";"APOD/APOE";"S*G*USTA--*****";"(null)";"(null)";"(null)"
"647";"TRANSPORTATION INTERMODAL";"1328";"TRANSPORTATIONINTERMODAL";"S*G*UST---*****";"(null)";"(null)";"(null)"
"646";"TRANSPORTATION MISSILE";"439";"MISSILE";"S*G*USTI--*****";"(null)";"(null)";"(null)"
"642";"TRANSPORTATION MOVEMENT CONTRO";"427";"MOVEMENTCONTROLCENTRE(MCC)";"S*G*USTM--*****";"(null)";"(null)";"(null)"
"643";"TRANSPORTATION RAILHEAD";"430";"RAILHEAD";"S*G*USTR--*****";"(null)";"(null)";"(null)"
"644";"TRANSPORTATION SPOD/SPOE";"433";"SPOD/SPOE";"S*G*USTS--*****";"(null)";"(null)";"(null)"
"783";"TRANSPORT FACILITY";"607";"TRANSPORTFACILITY";"S*G*IT----H****";"(null)";"(null)";"(null)"
"661";"UNITS GENERAL LIAISON";"467";"UNITGENERALLIAISON";"S*G*UHGL--*****";"(null)";"(null)";"(null)"
"738";"UTILITY VEHICLE";"546";"UTILITYVEHICLE";"S*G*EVU---*****";"54";"HMMWV Utility";"738"
"738";"UTILITY VEHICLE";"546";"UTILITYVEHICLE";"S*G*EVU---*****";"221";"Vehicle Tgt";"738"
"743";"WATER CRAFT";"551";"WATERCRAFT";"S*G*EVUR--*****";"213";"TATRA Tanker Water";"743"
"353";"WEAPON";"61";"WEAPON";"S*A*W-----*****";"(null)";"(null)";"(null)"
1 id name sym_klassifiz_id name symbol_id_code id name def_symbol_id
2 611 ADMINISTRATIVE FINANCE 331 FINANCE S*G*USAF--***** (null) (null) (null)
3 609 ADMINISTRATIVE JUDGE ADVOCATE GENERAL (JAG) 325 JUDGEADVOCATEGENERAL(JAG) S*G*USAJ--***** (null) (null) (null)
4 606 ADMINISTRATIVE LABOUR 355 LABOUR S*G*USAL--***** (null) (null) (null)
5 607 ADMINISTRATIVE MORAL, WELFARE, RECREATION (MWR) 358 MORAL,WELFARE,RECREATION(MWR) S*G*USAW--***** (null) (null) (null)
6 613 ADMINISTRATIVE MORTUARY/GRAVE REGISTRY 337 MORTUARY/GRAVESREGISTRY S*G*USAM--***** (null) (null) (null)
7 612 ADMINISTRATIVE PERSONNEL SERVICES 334 PERSONNELSERVICES S*G*USAS--***** (null) (null) (null)
8 610 ADMINISTRATIVE POSTAL 328 POSTAL S*G*USAO--***** (null) (null) (null)
9 615 ADMINISTRATIVE PUPLIC AFFAIRS 343 PUBLICAFFAIRS S*G*USAP--***** (null) (null) (null)
10 608 ADMINISTRATIVE QUARTERMASTER ( 361 QUARTERMASTER(SUPPLY) S*G*USAQ--***** (null) (null) (null)
11 614 ADMINISTRATIVE RELIGIOUS/CHAPLAIN 340 RELIGIOUS/CHAPLAIN S*G*USAR--***** (null) (null) (null)
12 605 ADMINISTRATIVE REPLACEMENT HOLDING UNIT (RHV) 352 REPLACEMENTHOLDINGUNIT(RHU) S*G*USAX--***** (null) (null) (null)
13 364 AIR DEFENCE 79 AIRDEFENCE S*G*UCD---***** (null) (null) (null)
14 664 AIR DEFENCE (AD) MISSILE LAUNC 471 AIRDEFENCE(AD)MISSILELAUNCH S*G*EWMA--***** (null) (null) (null)
15 379 AIR DEFENCE COMPOSITE 90 COMPOSITE S*G*UCDC--***** (null) (null) (null)
16 367 Air Defence COY 79 AIRDEFENCE S*G*UCD---***** (null) (null) (null)
17 683 AIR DEFENCE GUN 527 AIRDEFENCEGUN S*G*EWA---***** (null) (null) (null)
18 686 AIR DEFENCE GUN HEAVY 530 AIRDEFENCEGUNHEAVY S*G*EWAH--***** (null) (null) (null)
19 684 AIR DEFENCE GUN LIGHT 528 AIRDEFENCEGUNLIGHT S*G*EWAL--***** (null) (null) (null)
20 685 AIR DEFENCE GUN MEDIUM 529 AIRDEFENCEGUNMEDIUM S*G*EWAM--***** 44 Soldier Air Defence 685
21 378 AIR DEFENCE GUN UNIT 89 GUNUNIT S*G*UCDG--***** (null) (null) (null)
22 377 AIR DEFENCE H/MAD 88 H/MAD S*G*UCDH--***** (null) (null) (null)
23 372 AIR DEFENCE MISSILE 83 AIRDEFENCEMISSILE S*G*UCDM--***** (null) (null) (null)
24 376 AIR DEFENCE MISSILE HEAVY 87 AIRDEFENCEMISSILEHEAVY S*G*UCDMH-***** (null) (null) (null)
25 373 AIR DEFENCE MISSILE LIGHT 84 AIRDEFENCEMISSILELIGHT S*G*UCDML-***** 229 Legatus Wiesel 373
26 375 AIR DEFENCE MISSILE MEDIUM 86 AIRDEFENCEMISSILEMEDIUM S*G*UCDMM-***** (null) (null) (null)
27 374 AIR DEFENCE MISSILE MOTORIZED 85 AIRDEFENCEMISSILEMOTORIZED S*G*UCDMLA***** (null) (null) (null)
28 369 AIR DEFENCE SHORT RANGE 80 SHORTRANGE S*G*UCDS--***** (null) (null) (null)
29 371 AIR DEFENCE SHORT RANGE GUN 82 GUN S*G*UCDS--***** (null) (null) (null)
30 370 AIR DEFENCE SHORT RANGE MISSILE 81 MISSILE S*G*UCDS--***** (null) (null) (null)
31 380 AIR DEFENCE TARGETING UNIT 91 TARGETINGUNIT S*G*UCDT--***** (null) (null) (null)
32 381 AIR DEFENCE THEATRE MISSILE DEFENCE UNIT 92 THEATREMISSILEDEFENCEUNIT S*G*UCDO--***** (null) (null) (null)
33 781 AIRPORT/AIRBASE 605 AIRPORT/AIRBASE S*G*IBA---H**** (null) (null) (null)
34 342 AIR TRACK 6 AIRTRACK S*A*------***** (null) (null) (null)
35 777 AMMUNITION AND EXPLOSIVES PRODUCTION 595 AMMUNITIONANDEXPLOSIVESPRODUCTION S*G*IME---H**** (null) (null) (null)
36 788 AMPHIBIOUS WARFARE SHIP 620 AMPHIBIOUSWARFARESHIP S*S*CA----***** (null) (null) (null)
37 414 ANTI ARMOUR 110 ANTIARMOUR S*G*UCAA--***** (null) (null) (null)
38 422 ANTI ARMOUR AIR ASSAULT 114 ANTIARMOURAIRASSAULT S*G*UCAAS-***** (null) (null) (null)
39 421 ANTI ARMOUR AIRBORNE 113 ANTIARMOURAIRBORNE S*G*UCAAM-***** (null) (null) (null)
40 424 ANTI ARMOUR ARMOURED 117 ANTIARMOURARMOURED S*G*UCAAA-***** (null) (null) (null)
41 427 ANTI ARMOUR ARMOURED AIR ASSAU 120 ANTIARMOURARMOUREDAIRASSAULT S*G*UCAAAS***** (null) (null) (null)
42 425 ANTI ARMOUR ARMOURED TRACKED 118 ANTIARMOURARMOUREDTRACKED S*G*UCAAAT***** (null) (null) (null)
43 426 ANTI ARMOUR ARMOURED WHEELED 119 ANTIARMOURARMOUREDWHEELED S*G*UCAAAW***** (null) (null) (null)
44 419 ANTI ARMOUR DISMOUNTED 111 ANTIARMOURDISMOUNTED S*G*UCAAD-***** (null) (null) (null)
45 420 ANTI ARMOUR LIGHT 112 ANTIARMOURLIGHT S*G*UCAAL-***** (null) (null) (null)
46 428 ANTI ARMOUR MOTORIZED 121 ANTIARMOURMOTORIZED S*G*UCAAO-***** (null) (null) (null)
47 429 ANTI ARMOUR MOTORIZED AIR ASSA 122 ANTIARMOURMOTORIZEDAIRASSAULT S*G*UCAAOS***** (null) (null) (null)
48 423 ANTI ARMOUR MOUNTAIN 115 ANTIARMOURMOUNTAIN S*G*UCAAU-***** (null) (null) (null)
49 718 ANTITANK GUN 515 ANTITANKGUN S*G*EWG---***** 130 Soldier AT (RPG7) 718
50 722 ANTITANK GUN HEAVY 519 ANTITANKGUNHEAVY S*G*EWGH--***** (null) (null) (null)
51 720 ANTITANK GUN LIGHT 517 ANTITANKGUNLIGHT S*G*EWGL--***** (null) (null) (null)
52 721 ANTITANK GUN MEDIUM 518 ANTITANKGUNMEDIUM S*G*EWGM--***** (null) (null) (null)
53 719 ANTITANK GUN RECOILLESS 516 ANTITANKGUNRECOILLESS S*G*EWGR--***** (null) (null) (null)
54 695 ANTITANK ROCKET LAUNCHER 492 ANTITANKROCKETLAUNCHER S*G*EWT---***** (null) (null) (null)
55 698 ANTITANK ROCKET LAUNCHER HEAVY 495 ANTITANKROCKETLAUNCHERHEAVY S*G*EWTH--***** (null) (null) (null)
56 696 ANTITANK ROCKET LAUNCHER LIGHT 493 ANTITANKROCKETLAUNCHERLIGHT S*G*EWTL--***** (null) (null) (null)
57 697 ANTITANK ROCKET LAUNCHER MEDIU 494 ANTITANKROCKETLAUNCHERMEDIUM S*G*EWTM--***** (null) (null) (null)
58 392 ARMOUR 93 ARMOUR S*G*UCA---***** (null) (null) (null)
59 752 ARMOURED CARRIER WITH SCATTERA 561 ARMOUREDCARRIERWITHSCATTERABLEMINES S*G*EVEMSM***** (null) (null) (null)
60 734 ARMOURED INFANTRY 542 ARMOUREDINFANTRY S*G*EVAI--***** (null) (null) (null)
61 732 ARMOURED PERSONNEL CARRIER 540 ARMOUREDPERSONNELCARRIER S*G*EVAA--***** (null) (null) (null)
62 733 ARMOURED PERSONNEL CARRIER REC 541 ARMOUREDPERSONNELCARRIERRECOVERY S*G*EVAAR-***** (null) (null) (null)
63 724 ARMOURED VEHICLE 532 ARMOUREDVEHICLE S*G*EVA---***** 231 Marder 724
64 750 ARMOURED VEHICLE MOUNTED 558 ARMOUREDVEHICLEMOUNTED S*G*EVEMA-***** (null) (null) (null)
65 397 ARMOUR TRACK 94 ARMOURTRACK S*G*UCAT--***** (null) (null) (null)
66 398 ARMOUR TRACK AIRBORNE 95 ARMOURTRACKAIRBORNE S*G*UCATA-***** (null) (null) (null)
67 399 ARMOUR TRACK AMPHIBIOUS 96 ARMOURTRACKAMPHIBIOUS S*G*UCATW-***** (null) (null) (null)
68 400 ARMOUR TRACK AMPHIBIOUS RECOVE 97 ARMOURTRACKAMPHIBIOUSRECOVERY S*G*UCATWR***** (null) (null) (null)
69 403 ARMOUR TRACK HEAVY 100 ARMOURTRACK,HEAVY S*G*UCATH-***** (null) (null) (null)
70 401 ARMOUR TRACK LIGHT 98 ARMOURTRACK,LIGHT S*G*UCATL-***** (null) (null) (null)
71 402 ARMOUR TRACK MEDIUM 99 ARMOURTRACK,MEDIUM S*G*UCATM-***** (null) (null) (null)
72 404 ARMOUR TRACK RECOVERY 101 ARMOURTRACK,RECOVERY S*G*UCATR-***** (null) (null) (null)
73 405 ARMOUR WHEELED 102 ARMOUR,WHEELED S*G*UCAW--***** (null) (null) (null)
74 406 ARMOUR WHEELED AIR ASSAULT 103 ARMOUR,WHEELEDAIRASSAULT S*G*UCAWS-***** (null) (null) (null)
75 407 ARMOUR WHEELED AIRBORNE 104 ARMOUR,WHEELEDAIRBORNE S*G*UCAWA-***** 227 BMP3 IFV 407
76 408 ARMOUR WHEELED AMPHIBIOUS 105 ARMOUR,WHEELEDAMPHIBIOUS S*G*UCAWA-***** (null) (null) (null)
77 409 ARMOUR WHEELED AMPHIBIOUS RECO 1325 ARMOURWHEELEDAMPHIBIOUSRECOVERY S*G*UCAWWR***** (null) (null) (null)
78 412 ARMOUR WHEELED HEAVY 108 ARMOUR,WHEELEDHEAVY S*G*UCAWH-***** (null) (null) (null)
79 410 ARMOUR WHEELED LIGHT 106 ARMOUR,WHEELEDLIGHT S*G*UCAWL-***** (null) (null) (null)
80 411 ARMOUR WHEELED MEDIUM 107 ARMOUR,WHEELEDMEDIUM S*G*UCAWM-***** (null) (null) (null)
81 413 ARMOUR WHEELED RECOVERY 109 ARMOUR,WHEELEDRECOVERY S*G*UCAWR-***** 10 Armored Recovery Vehicle 413
82 789 ASSAULT VESSEL 621 ASSAULTVESSEL S*S*CALA--***** (null) (null) (null)
83 776 ATOMIC ENERGY PRODUCTION 593 ATOMICENERGYPRODUCTION S*G*IMF---H**** (null) (null) (null)
84 430 AVIATION 123 AVIATION S*G*UCV---***** (null) (null) (null)
85 431 AVIATION FIXED WING 124 FIXEDWING S*G*UCVF--***** (null) (null) (null)
86 433 AVIATION FIXED WING ATTACK 126 ATTACKFIXEDWING S*G*UCVFA-***** (null) (null) (null)
87 436 AVIATION FIXED WING RECON 129 RECONFIXEDWING S*G*UCVFR-***** (null) (null) (null)
88 432 AVIATION FIXED WING UTILITY 125 UTILITYFIXEDWING S*G*UCVFU-***** (null) (null) (null)
89 435 AVIATION FORWARD AIR CONTROLLER (FAC) 128 FORWARDAIRCONTROLLER(FAC) S*G*UCVUFC***** (null) (null) (null)
90 437 AVIATION ROTARY WING 130 ROTARYWING S*G*UCVR--***** (null) (null) (null)
91 440 AVIATION ROTARY WING C2 138 C2ROTARYWING S*G*UCVRUC***** (null) (null) (null)
92 441 AVIATION ROTARY WING MEDEVAC 139 MEDEVACROTARYWING S*G*UCVRUE***** (null) (null) (null)
93 439 AVIATION ROTARY WING UTILITY 134 UTILITYROTARYWING S*G*UCVRU-***** (null) (null) (null)
94 434 AVIATION TACTICAL AIR CONTROL 127 TACTICALAIRCONTROLPARTY(TACP) S*G*UCVUTP***** (null) (null) (null)
95 445 AVIATION UAV CONTROL 1326 AVIATIONUAVCONTROL S*G*UCVU--***** (null) (null) (null)
96 446 AVIATION UAV LAUNCHER 1327 AVIATIONUAVLAUNCHER S*G*UCVU--***** (null) (null) (null)
97 447 AVIATION UAV RECOVERY 1337 AVIATIONUAVRECOVERY S*G*UCVU--***** (null) (null) (null)
98 444 AVIATION UNMANNED AERIAL VEHIC 145 UNMANNEDAERIALVEHICLEFIXEDWING S*G*UCVUF-***** (null) (null) (null)
99 448 AVIATION UNMANNED AERIAL VEHICLE ROTARY WING 146 UNMANNEDAERIALVEHICLEROTARYWING S*G*UCVUR-***** (null) (null) (null)
100 443 AVIATION UNMANNED AVIATION VEH 144 UNMANNEDAERIALVEHICLE S*G*UCVU--***** (null) (null) (null)
101 442 AVIATION VERTICAL/SHORT TAKEOF 143 VERTICAL/SHORTTAKEOFFANDLANDING(V/STOL) S*G*UCVV--***** (null) (null) (null)
102 769 BIOLOGICAL 581 BIOLOGICAL S*G*IRNB--H**** (null) (null) (null)
103 745 BRIDGE 553 BRIDGE S*G*EVEB--***** (null) (null) (null)
104 778 BRIDGE 599 BRIDGE S*G*IMNB--H**** (null) (null) (null)
105 739 BUS 547 BUS S*G*EVUB--***** (null) (null) (null)
106 735 C2V/ACV 543 C2V/ACV S*G*EVAC--***** (null) (null) (null)
107 548 CBRN 256 COMBATSUPPORTCBRN S*G*UUA---***** (null) (null) (null)
108 768 CBRN 580 CBRN S*G*IRN---H**** (null) (null) (null)
109 560 CBRN BIOLOGICAL 268 BIOLOGICAL S*G*UUAB--***** (null) (null) (null)
110 561 CBRN BIOLOGICAL RECON EQUIPPED 269 RECONEQUIPPED S*G*UUABR-***** (null) (null) (null)
111 549 CBRN CHEMICAL 257 CHEMICAL S*G*UUAC--***** (null) (null) (null)
112 556 CBRN CHEMICAL RECON 264 CHEMICALRECON S*G*UUACR-***** (null) (null) (null)
113 553 CBRN CHEMICAL SMOKE 261 SMOKE S*G*UUACS-***** (null) (null) (null)
114 555 CBRN CHEMICAL SMOKE ARMOUR 263 ARMOURSMOKE S*G*UUACSA***** (null) (null) (null)
115 550 CBRN CHEMICAL SMOKE/DECON 258 SMOKE/DECON S*G*UUACC-***** (null) (null) (null)
116 551 CBRN CHEMICAL SMOKE/DECON MECHANIZED 259 MECHANIZEDSMOKE/DECON S*G*UUACCK***** (null) (null) (null)
117 552 CBRN CHEMICAL SMOKE/DECON MOTO 260 MOTORIZEDSMOKE/DECON S*G*UUACCM***** (null) (null) (null)
118 554 CBRN CHEMICAL SMOKE MOTORIZED 262 MOTORIZEDSMOKE S*G*UUACSM***** (null) (null) (null)
119 557 CBRN CHEMICAL WHEELED ARMOURED VEHICLE 265 CHEMICALWHEELEDARMOUREDVEHICLE S*G*UUACRW***** (null) (null) (null)
120 558 CBRN CHEMICAL WHEELED ARMOURED VEHICLE RECONNAISAN 266 CHEMICALWHEELEDARMOUREDVEHICLERECONNAISSANCESURVEI S*G*UUACRS***** (null) (null) (null)
121 562 CBRN DECON 270 DECONTAMINATION S*G*UUAD--***** (null) (null) (null)
122 564 CBRN DECON EQUIPMENT 1330 CBRNDECONEQUIPMENT S*G*UUADE-***** (null) (null) (null)
123 565 CBRN DECON EQUIPMENT/TROOP 1331 CBRNDECONEQUIPMENT/TROOP S*G*UUADET***** (null) (null) (null)
124 563 CBRN DECON TROOP 1329 CBRNDECONTROOP S*G*UUADT-***** (null) (null) (null)
125 760 CBRN EQUIPMENT 571 CBRNEQUIPMENT S*G*EXN---***** (null) (null) (null)
126 566 CBRN LABORATORY 1332 CBRNLABORATORY S*G*UUAL--***** (null) (null) (null)
127 559 CBRN NUCLEAR 267 NUCLEAR S*G*UUAN--***** (null) (null) (null)
128 770 CHEMICAL 582 CHEMICAL S*G*IRNC--H**** (null) (null) (null)
129 356 CIVIL FIXED WING 73 FIXEDWING S*A*CF----***** (null) (null) (null)
130 755 CIVILIAN VEHICLE 565 CIVILIANVEHICLE S*G*EVC---***** (null) (null) (null)
131 357 CIVIL ROTARY WING 74 ROTARYWING S*A*CH----***** (null) (null) (null)
132 604 COMBAT SERVICE SUPPORT 321 COMBATSERVICESUPPORT S*G*US----***** (null) (null) (null)
133 736 COMBAT SERVICE SUPPORT VEHICLE 544 COMBATSERVICESUPPORTVEHICLE S*G*EVAS--***** (null) (null) (null)
134 547 COMBAT SUPPORT 255 COMBATSUPPORT S*G*UU----***** (null) (null) (null)
135 748 CONSTRUCTION VEHICLE 556 CONSTRUCTIONVEHICLE S*G*EVEC--***** (null) (null) (null)
136 742 CROSS-COUNTRY TRUCK 550 CROSS-COUNTRYTRUCK S*G*EVUX--***** 212 TATRA Tanker Fuel 742
137 742 CROSS-COUNTRY TRUCK 550 CROSS-COUNTRYTRUCK S*G*EVUX--***** 50 Truck 2t off-road 742
138 772 DECON 585 DECON S*G*IPD---H**** (null) (null) (null)
139 676 DIRECT FIRE GUN 520 DIRECTFIREGUN S*G*EWD---***** (null) (null) (null)
140 681 DIRECT FIRE GUN HEAVY 525 DIRECTFIREGUNHEAVY S*G*EWDH--***** (null) (null) (null)
141 682 DIRECT FIRE GUN HEAVY SELF-PRO 526 DIRECTFIREGUNHEAVYSELF-PROPELLED S*G*EWDHS-***** (null) (null) (null)
142 677 DIRECT FIRE GUN LIGHT 521 DIRECTFIREGUNLIGHT S*G*EWDL--***** (null) (null) (null)
143 678 DIRECT FIRE GUN LIGHT SELF PRO 522 DIRECTFIREGUNLIGHTSELF-PROPELLED S*G*EWDLS-***** (null) (null) (null)
144 679 DIRECT FIRE GUN MEDIUM 523 DIRECTFIREGUNMEDIUM S*G*EWDM--***** (null) (null) (null)
145 680 DIRECT FIRE GUN MEDIUM SELF-PR 524 DIRECTFIREGUNMEDIUMSELF-PROPELLED S*G*EWDMS-***** (null) (null) (null)
146 753 DOZER 562 DOZER S*G*EVED--***** 215 CAT Excavator 753
147 746 EARTHMOVER 554 EARTHMOVER S*G*EVEE--***** (null) (null) (null)
148 774 ELCECTRIC POWER FACILITY 590 ELECTRICPOWERFACILITY S*G*IUE---H**** (null) (null) (null)
149 758 EMPLACED SENSOR 568 EMPLACEDSENSOR S*G*ESE---***** (null) (null) (null)
150 467 ENGINEER 159 ENGINEER S*G*UCE---***** (null) (null) (null)
151 472 ENGINEER COMBAT 160 ENGINEERCOMBAT S*G*UCEC--***** (null) (null) (null)
152 473 ENGINEER COMBAT AIR ASSAULT 161 ENGINEERCOMBATAIRASSAULT S*G*UCECS-***** (null) (null) (null)
153 478 ENGINEER COMBAT AIRBORNE 162 ENGINEERCOMBATAIRBORNE S*G*UCECA-***** (null) (null) (null)
154 475 ENGINEER COMBAT BRIDGING 171 ENGINEERCOMBATBRIDGING S*G*UCEC--***** (null) (null) (null)
155 481 ENGINEER COMBAT HEAVY 166 ENGINEERCOMBATHEAVY S*G*UCECH-***** (null) (null) (null)
156 479 ENGINEER COMBAT LIGHT 164 ENGINEERCOMBATLIGHT S*G*UCECL-***** (null) (null) (null)
157 482 ENGINEER COMBAT MECH (TRACK) 167 ENGINEERCOMBATMECHANIZED(TRACK) S*G*UCECT-***** (null) (null) (null)
158 480 ENGINEER COMBAT MEDIUM 165 ENGINEERCOMBATMEDIUM S*G*UCECM-***** (null) (null) (null)
159 476 ENGINEER COMBAT MINE CLEARING 172 ENGINEERCOMBATMINECLEARING S*G*UCEC--***** (null) (null) (null)
160 477 ENGINEER COMBAT MINE LAYING 173 ENGINEERCOMBATMINELAYING S*G*UCEC--***** (null) (null) (null)
161 483 ENGINEER COMBAT MOTORIZED 168 ENGINEERCOMBATMOTORIZED S*G*UCECW-***** (null) (null) (null)
162 484 ENGINEER COMBAT MOUNTAIN 169 ENGINEERCOMBATMOUNTAIN S*G*UCECO-***** (null) (null) (null)
163 474 ENGINEER COMBAT RECON 170 ENGINEERCOMBATRECON S*G*UCECR-***** (null) (null) (null)
164 485 ENGINEER CONSTRUCTION 175 ENGINEERCONSTRUCTION S*G*UCEN--***** (null) (null) (null)
165 744 ENGINEER VEHICLE 552 ENGINEERVEHICLE S*G*EVE---***** (null) (null) (null)
166 657 ENVIRONMENTAL PROTECTION 463 ENVIRONMENTALPROTECTION S*G*USXEP-***** (null) (null) (null)
167 576 EW CORPS 280 CORPS S*G*UUMSEC***** (null) (null) (null)
168 575 EW THEATRE 279 THEATRE S*G*UUMSET***** (null) (null) (null)
169 602 EXPLOSIVE ORDNANCE DISPOSAL 317 EXPLOSIVEORDINANCEDISPOSAL S*G*UUE---***** (null) (null) (null)
170 490 FIELD ARTELLERY HOWITZER/GUN AIRBORNE 181 AIRBORNE S*G*UCFHA-***** (null) (null) (null)
171 495 FIELD ARTELLERY HOWITZER/GUN AMPHIBIOUS 187 AMPHIBIOUS S*G*UCFHX-***** (null) (null) (null)
172 494 FIELD ARTELLERY HOWITZER/GUN HEAVY 186 HEAVY S*G*UCFHH-***** (null) (null) (null)
173 492 FIELD ARTELLERY HOWITZER/GUN LIGHT 184 LIGHT S*G*UCFHL-***** (null) (null) (null)
174 493 FIELD ARTELLERY HOWITZER/GUN MEDIUM 185 MEDIUM S*G*UCFHM-***** (null) (null) (null)
175 491 FIELD ARTELLERY HOWITZER/GUN MOUNTAIN 183 MOUNTAIN S*G*UCFHO-***** (null) (null) (null)
176 496 FIELD ARTELLERY ROCKET 188 ROCKET S*G*UCFR--***** (null) (null) (null)
177 498 FIELD ARTILEERY ROCKET SINGLE 190 SINGLEROCKETSELFPROPELLED S*G*UCFRSS***** (null) (null) (null)
178 486 FIELD ARTILLERY 177 FIELDARTILLERY S*G*UCF---***** (null) (null) (null)
179 521 FIELD ARTILLERY ARTILLERY SURV 214 ARTILLERYSURVEY S*G*UCFS--***** (null) (null) (null)
180 523 FIELD ARTILLERY FIRE DIRECTION CENTRE 224 FIREDIRECTIONCENTRE S*G*UCF---***** (null) (null) (null)
181 487 FIELD ARTILLERY HOWITZER/GUN 178 HOWITZER/GUN S*G*UCFH--***** (null) (null) (null)
182 489 FIELD ARTILLERY HOWITZER/GUN AIR ASSAULT 180 AIRASSAULT S*G*UCFHS-***** (null) (null) (null)
183 488 FIELD ARTILLERY HOWITZER/GUN SELF-PROPELLED 179 SELFPROPELLED S*G*UCFHE-***** (null) (null) (null)
184 522 FIELD ARTILLERY METEOROLOGICAL 219 METEOROLOGICAL S*G*UCFO--***** (null) (null) (null)
185 513 FIELD ARTILLERY MORTAR 205 MORTAR S*G*UCFM--***** (null) (null) (null)
186 514 FIELD ARTILLERY MORTAR SP TRAC 206 SELFPROPELLED(SP)TRACKEDMORTAR S*G*UCFMS-***** (null) (null) (null)
187 515 FIELD ARTILLERY MORTAR SP WHEE 207 SPWHEELEDMORTAR S*G*UCFMSW***** (null) (null) (null)
188 516 FIELD ARTILLERY MORTAR TOWED 208 TOWEDMORTAR S*G*UCFMT-***** (null) (null) (null)
189 518 FIELD ARTILLERY MORTAR TOWED A 210 TOWEDAIRASSAULTMORTAR S*G*UCFMTS***** (null) (null) (null)
190 517 FIELD ARTILLERY MORTAR TOWED A 209 TOWEDAIRBORNEMORTAR S*G*UCFMTA***** (null) (null) (null)
191 519 FIELD ARTILLERY MORTAR TOWED M 212 TOWEDMOUNTAINMORTAR S*G*UCFMTO***** (null) (null) (null)
192 524 FIELD ARTILLERY OBERSERVER 225 OBERSERVER S*G*UCF---***** (null) (null) (null)
193 502 FIELD ARTILLERY ROCKET MULTI R 194 MULTIROCKETSELFPROPELLED S*G*UCFRMS***** (null) (null) (null)
194 504 FIELD ARTILLERY ROCKET MULTI ROCKET LAUNCER MULTI 196 MULTIROCKETTOWED S*G*UCFRMT***** (null) (null) (null)
195 503 FIELD ARTILLERY ROCKET MULTI ROCKET LAUNCER MULTI 195 MULTIROCKETTRUCK S*G*UCFRMR***** (null) (null) (null)
196 501 FIELD ARTILLERY ROCKET MULTI ROCKET LAUNCHER 193 MULTIROCKETLAUNCHER S*G*UCFRM-***** (null) (null) (null)
197 497 FIELD ARTILLERY ROCKET SINGLE 189 SINGLEROCKETLAUNCHER S*G*UCFRS-***** (null) (null) (null)
198 499 FIELD ARTILLERY ROCKET SINGLE ROCKET LAUNCHER SING 191 SINGLEROCKETTRUCK S*G*UCFRSR***** (null) (null) (null)
199 500 FIELD ARTILLERY ROCKET SINGLE ROCKET LAUNCHER SING 192 SINGLEROCKETTOWED S*G*UCFRST***** (null) (null) (null)
200 506 FIELD ARTILLERY TARGET ACQUISI 198 RADAR S*G*UCFTR-***** (null) (null) (null)
201 505 FIELD ARTILLERY TARGET ACQUISITION 197 TARGETACQUISITION S*G*UCFT--***** (null) (null) (null)
202 510 FIELD ARTILLERY TARGET ACQUISITION DISMOUNTED 202 TARGETACQUISITIONDISMOUNTED S*G*UCFTCD***** (null) (null) (null)
203 508 FIELD ARTILLERY TARGET ACQUISITION FLASH (OPTICAL) 200 FLASH(OPTICAL) S*G*UCFTF-***** (null) (null) (null)
204 509 FIELD ARTILLERY TARGET ACQUISITION MOUNTED 201 TARGETACQUISITIONMOUNTED S*G*UCFTC-***** (null) (null) (null)
205 512 FIELD ARTILLERY TARGET ACQUISITION NAVAL GUNFIRE 204 TARGETACQUISITIONNAVALGUNFIRE S*G*UCFTA-***** (null) (null) (null)
206 507 FIELD ARTILLERY TARGET ACQUISITION SOUND 199 SOUND S*G*UCFTS-***** (null) (null) (null)
207 511 FIELD ARTILLERY TARGET ACQUISITION TRACKED 203 TARGETACQUISITIONTRACKED S*G*UCFTCM***** (null) (null) (null)
208 345 FIXED WING DRONE (RPV/UAE) 36 DRONE(RPV/UAV) S*A*MFQ---***** (null) (null) (null)
209 761 FLAME THROWER 572 FLAMETHROWER S*G*EXF---***** (null) (null) (null)
210 660 GENERAL HEADQUATERS AND SERVICE 466 GENERALHEADQUARTERSANDSERVICE S*G*UH----***** (null) (null) (null)
211 779 GOVERNMENT LEADERSHIP 603 GOVERNMENTLEADERSHIP S*G*IG----H**** (null) (null) (null)
212 703 GRENADE LAUNCHER 500 GRENADELAUNCHER S*G*EWZ---***** (null) (null) (null)
213 706 GRENADE LAUNCHER HEAVY 503 GRENADELAUNCHERHEAVY S*G*EWZH--***** (null) (null) (null)
214 704 GRENADE LAUNCHER LIGHT 501 GRENADELAUNCHERLIGHT S*G*EWZL--***** (null) (null) (null)
215 705 GRENADE LAUNCHER MEDIUM 502 GRENADELAUNCHERMEDIUM S*G*EWZM--***** (null) (null) (null)
216 662 GROUND TRACK EQUIPMENT 468 GROUNDTRACKEQUIPMENT S*G*E-----***** (null) (null) (null)
217 358 GROUND TRACK UNIT 77 UNIT S*G*U-----***** 217 Soldier (Role Player) 358
218 358 GROUND TRACK UNIT 77 UNIT S*G*U-----***** 106 Soldier 358
219 363 GROUND TRACK UNIT COMBAT 78 COMBAT S*G*UC----***** (null) (null) (null)
220 520 GROUND TRACK UNIT COMBAT FIELD ARTILLERY MORTAR AM 213 AMPHIBIOUSMORTAR S*G*UCFML-***** (null) (null) (null)
221 659 GROUND TRACK UNIT GENERAL HEADQUATERS 465 UNITGENERALHEADQUARTERS S*G*UH----***** (null) (null) (null)
222 723 GROUND VEHICLE 531 GROUNDVEHICLE S*G*EV----***** (null) (null) (null)
223 702 HEAVY MACHINE GUN 499 HEAVYMACHINEGUN S*G*EWRH--***** 129 Soldier HMG 702
224 785 HOSPITAL 609 HOSPITAL S*G*IXH---H**** (null) (null) (null)
225 711 HOWITZER 508 HOWITZER S*G*EWH---***** (null) (null) (null)
226 716 HOWITZER HEAVY 513 HOWITZERHEAVY S*G*EWHH--***** (null) (null) (null)
227 717 HOWITZER HEAVY SELF-PROPELLED 514 HOWITZERHEAVYSELF-PROPELLED S*G*EWHHS-***** (null) (null) (null)
228 712 HOWITZER LIGHT 509 HOWITZERLIGHT S*G*EWHL--***** (null) (null) (null)
229 713 HOWITZER LIGHT SELF-PROPELLED 510 HOWITZERLIGHTSELF-PROPELLED S*G*EWHLS-***** (null) (null) (null)
230 714 HOWITZER MEDIUM 511 HOWITZERMEDIUM S*G*EWHM--***** (null) (null) (null)
231 715 HOWITZER MEDIUM SELF-PROPELLED 512 HOWITZERMEDIUMSELF-PROPELLED S*G*EWHMS-***** (null) (null) (null)
232 449 INFANTRY 149 INFANTRY S*G*UCI---***** 161 TM 449
233 449 INFANTRY 149 INFANTRY S*G*UCI---***** 226 TEST PLAYER 449
234 449 INFANTRY 149 INFANTRY S*G*UCI---***** 232 0Soldier 449
235 449 INFANTRY 149 INFANTRY S*G*UCI---***** 128 TM Leader 449
236 463 INFANTRY AIR ASSAULT 154 INFANTRYAIRASSAULT S*G*UCIS--***** (null) (null) (null)
237 462 INFANTRY AIRBORNE 153 INFANTRYAIRBORNE S*G*UCIA--***** (null) (null) (null)
238 466 INFANTRY FIGHTING VEHICLE 157 INFANTRYFIGHTINGVEHICLE S*G*UCII--***** (null) (null) (null)
239 454 INFANTRY LIGHT 150 INFANTRYLIGHT S*G*UCIL--***** (null) (null) (null)
240 464 INFANTRY MECHANIZED 155 INFANTRYMECHANIZED S*G*UCIZ--***** (null) (null) (null)
241 456 INFANTRY MOTORIZED 151 INFANTRYMOTORIZED S*G*UCIM--***** (null) (null) (null)
242 461 INFANTRY MOUNTAIN 152 INFANTRYMOUNTAIN S*G*UCIO--***** (null) (null) (null)
243 465 INFANTRY NAVAL 156 INFANTRYNAVAL S*G*UCIN--***** (null) (null) (null)
244 600 INFORMATION OPERATIONS 315 INFORMATIONWARFAREUNIT S*G*UUI---***** (null) (null) (null)
245 765 INSTALLATION 576 INSTALLATION S*G*I-----H**** 225 MEU 765
246 765 INSTALLATION 576 INSTALLATION S*G*I-----H**** 224 Building 765
247 666 INTERMEDIATE RANGE AD MISSILE 473 INTERMEDIATERANGEADMISSILELAUNCH S*G*EWMAI-***** (null) (null) (null)
248 670 INTERMEDIATE RANGE SS MISSILE 478 INTERMEDIATERANGESSMISSILELAUNCH S*G*EWMSI-***** (null) (null) (null)
249 382 INTERNAL SECURITY FORCES 246 INTERNALSECURITYFORCES S*G*UCS---***** (null) (null) (null)
250 390 INTERNAL SECURITY FORCES AVIAT 254 AVIATION S*G*UCSA--***** (null) (null) (null)
251 387 INTERNAL SECURITY FORCES GROUN 251 MECHANIZEDGROUND S*G*UCSGA-***** (null) (null) (null)
252 384 INTERNAL SECURITY FORCES GROUND 248 GROUND S*G*UCSG--***** (null) (null) (null)
253 385 INTERNAL SECURITY FORCES GROUND DISMOUNTED 249 DISMOUNTEDGROUND S*G*UCSGD-***** (null) (null) (null)
254 386 INTERNAL SECURITY FORCES GROUND MOTORIZED 250 MOTORIZEDGROUND S*G*UCSGM-***** (null) (null) (null)
255 389 INTERNAL SECURITY FORCES RAILROAD 253 RAILROAD S*G*UCSR--***** (null) (null) (null)
256 383 INTERNAL SECURITY FORCES RIVERINE 247 RIVERINE S*G*UCSW--***** (null) (null) (null)
257 388 INTERNAL SECURITY FORCES WHEEL 252 WHEELEDMECHANIZED S*G*UCSM--***** (null) (null) (null)
258 791 LANDING CRAFT 623 LANDINGCRAFT S*S*CALC--***** (null) (null) (null)
259 790 LANDING SHIP 622 LANDINGSHIP S*S*CALS--***** (null) (null) (null)
260 601 LANDING SUPPORT 316 LANDINGSUPPORT S*G*UUX---***** (null) (null) (null)
261 762 LAND MINES 573 LANDMINES S*G*EXM---***** (null) (null) (null)
262 763 LAND MINES, LETHAL 574 LANDMINES,LETHAL S*G*EXMC--***** (null) (null) (null)
263 759 LASER 570 LASER S*G*EXL---***** (null) (null) (null)
264 584 LAW ENFORCEMENT UNIT 292 LAWENFORCEMENTUNIT S*G*UUL---***** (null) (null) (null)
265 587 LAW ENFORCEMENT UNIT CIVILIAN LAW ENFORCEMENT 295 CIVILIANLAWENFORCEMENT S*G*UULC--***** (null) (null) (null)
266 588 LAW ENFORCEMENT UNIT CRIMINAL INVESTIGATION DIVISI 297 CENTRALINTELLIGENCEDIVISION(CID) S*G*UULD--***** (null) (null) (null)
267 586 LAW ENFORCEMENT UNIT MILITARY POLICE 294 MILITARYPOLICE S*G*UULM--***** (null) (null) (null)
268 585 LAW ENFORCEMENT UNIT SHORE PATROL 293 SHOREPATROL S*G*UULS--***** (null) (null) (null)
269 794 LEISURE CRAFT 665 LEISURECRAFT S*S*XR----***** (null) (null) (null)
270 764 LESS THAN LETHAL 575 LESSTHANLETHAL S*G*EXML--***** (null) (null) (null)
271 737 LIGHT ARMOURED VEHICLE 545 LIGHTARMOUREDVEHICLE S*G*EVAL--***** (null) (null) (null)
272 701 LIGHT MACHINE GUN 498 LIGHTMACHINEGUN S*G*EWRL--***** 131 Soldier LMG 701
273 741 LIMITED CROSS-COUNTRY TRUCK 549 LIMITEDCROSS-COUNTRYTRUCK S*G*EVUL--***** (null) (null) (null)
274 667 LONG RANGE AD MISSILE LAUNCH 474 LONGRANGEADMISSILELAUNCH S*G*EWMAL-***** (null) (null) (null)
275 671 LONG RANGE SS MISSILE LAUNCH 479 LONGRANGESSMISSILELAUNCH S*G*EWMSL-***** (null) (null) (null)
276 648 MAINTENANCE 442 MAINTENANCE S*G*USX---***** (null) (null) (null)
277 654 MAINTENANCE BATTLE DAMAGE REPA 460 BATTLEDAMAGEREPAIR S*G*USXBDR***** (null) (null) (null)
278 653 MAINTENANCE ELECTRO-OPTICAL 457 ELECTRO-OPTICAL S*G*USXE--***** (null) (null) (null)
279 649 MAINTENANCE HEAVY 445 MAINTENANCEHEAVY S*G*USXH--***** (null) (null) (null)
280 651 MAINTENANCE ORDINANCE 451 ORDINANCE S*G*USXO--***** (null) (null) (null)
281 652 MAINTENANCE ORDINANCE MISSILE 454 ORDINANCEMISSILE S*G*USXOM-***** (null) (null) (null)
282 655 MAINTENANCE PREVENTIVE MAINTEN 461 PREVENTIVEMAINTANANCE S*G*USXPM-***** (null) (null) (null)
283 650 MAINTENANCE RECOVERY 448 MAINTENANCERECOVERY S*G*USXR--***** (null) (null) (null)
284 623 MEDICAL DENTAL 373 MEDICALDENTAL S*G*USMD--***** (null) (null) (null)
285 784 MEDICAL FACILITY 608 MEDICALFACILITY S*G*IX----H**** (null) (null) (null)
286 624 MEDICAL PSYCHOLOGICAL 376 MEDICALPSYCHOLOGICAL S*G*USMP--***** (null) (null) (null)
287 621 MEDICAL TREATMENT FACILITY 367 MEDICALTREATMENTFACILITY S*G*USMM--***** (null) (null) (null)
288 622 MEDICAL VETERINARY 370 MEDICALVETERINARY S*G*USMV--***** (null) (null) (null)
289 343 MILITARY 7 MILITARY S*A*M-----***** (null) (null) (null)
290 780 MILITARY BASE/FACILITY 604 MILITARYBASE/FACILITY S*G*IB----H**** (null) (null) (null)
291 344 MILITARY FIXED WING 8 FIXEDWING S*A*MF----***** (null) (null) (null)
292 567 MILITARY INTELLIGENCE 271 MILITARYINTELLIGENCE S*G*UUM---***** (null) (null) (null)
293 568 MILITARY INTELLIGENCE AERIAL EXPLOITATION 272 AERIALEXPLOITATION S*G*UUMA--***** (null) (null) (null)
294 577 MILITARY INTELLIGENCE COUNTER INTELLIGENCE 281 COUNTERINTELLIGENCE S*G*UUMC--***** (null) (null) (null)
295 573 MILITARY INTELLIGENCE ELECTRON 277 INTERCEPT S*G*UUMSEI***** (null) (null) (null)
296 572 MILITARY INTELLIGENCE ELECTRON 276 DIRECTIONFINDING S*G*UUMSED***** (null) (null) (null)
297 571 MILITARY INTELLIGENCE ELECTRON 275 ARMOUREDWHEELEDVEHICLE S*G*UUMSEA***** (null) (null) (null)
298 570 MILITARY INTELLIGENCE ELECTRONIC WARFARE 274 ELECTRONICWARFARE S*G*UUMSE-***** (null) (null) (null)
299 574 MILITARY INTELLIGENCE ELECTRONIC WARFARE JAMMING 278 JAMMING S*G*UUMSEJ***** (null) (null) (null)
300 582 MILITARY INTELLIGENCE INTERROGATION 290 INTERROGATION S*G*UUMQ--***** (null) (null) (null)
301 583 MILITARY INTELLIGENCE JOINT INTELLIGENCE CENTRE 291 JOINTINTELLIGENCECENTRE S*G*UUMJ--***** (null) (null) (null)
302 581 MILITARY INTELLIGENCE OPERATIONS 288 OPERATIONS S*G*UUMO--***** (null) (null) (null)
303 569 MILITARY INTELLIGENCE SIGNALS 273 SIGNALINTELLIGENCE(SIGINT) S*G*UUMS--***** (null) (null) (null)
304 579 MILITARY INTELLIGENCE SURVEILL 283 GROUNDSURVEILLANCERADAR S*G*UUMRG-***** (null) (null) (null)
305 578 MILITARY INTELLIGENCE SURVEILLANCE 282 SURVEILLANCE S*G*UUMR--***** (null) (null) (null)
306 580 MILITARY INTELLIGENCE SURVEILLANCE SENSOR 284 SENSOR S*G*UUMRS-***** (null) (null) (null)
307 346 MILITARY ROTARY WING 39 ROTARYWING S*A*MH----***** 195 Apache 346
308 766 MINE 578 MINE S*G*IRM---H**** (null) (null) (null)
309 749 MINE LAYING VEHICLE 557 MINELAYINGVEHICLE S*G*EVEM--***** 4 Trailer, Minelaying 749
310 675 MISSILE LAUNCHER AT HEAVY 483 MISSILELAUNCHERATHEAVY S*G*EWMTH-***** (null) (null) (null)
311 674 MISSILE LAUNCHER AT MEDIUM 482 MISSILELAUNCHERATMEDIUM S*G*EWMTM-***** (null) (null) (null)
312 663 MISSILE LAUNCHERS 470 MISSILELAUNCHERS S*G*EWM---***** (null) (null) (null)
313 672 MISSILE LAUNCHERS ANTI TANK (A 480 MISSILELAUNCHERSANTITANK(AT) S*G*EWMT--***** (null) (null) (null)
314 673 MISSILE LAUNCHERS AT LIGHT 481 MISSILELAUNCHERSATLIGHT S*G*EWMTL-***** (null) (null) (null)
315 544 MISSILE (SURF-SURF) 243 MISSILE(SURFACE-SURFACE) S*G*UCM---***** (null) (null) (null)
316 546 MISSILE (SURF-SURF) STRATEGIC 245 MISSILE(SURFACE-SURFACE)STRATEGIC S*G*UCMS--***** (null) (null) (null)
317 545 MISSILE (SURF-SURF) TACTICAL 244 MISSILE(SURFACE-SURFACE)TACTICAL S*G*UCMT--***** (null) (null) (null)
318 707 MORTAR 504 MORTAR S*G*EWO---***** 209 Soldier Mortar 707
319 710 MORTAR HEAVY 507 MORTARHEAVY S*G*EWOH--***** (null) (null) (null)
320 708 MORTAR LIGHT 505 MORTARLIGHT S*G*EWOL--***** (null) (null) (null)
321 709 MORTAR MEDIUM 506 MORTARMEDIUM S*G*EWOM--***** (null) (null) (null)
322 747 MULTIFUNCTIONAL EARTHMOVER/DIG 555 MULTIFUNCTIONALEARTHMOVER/DIGGER S*G*EVEE--***** (null) (null) (null)
323 691 MULTIPLE ROCKET LAUNCHER 488 MULTIPLEROCKETLAUNCHER S*G*EWX---***** (null) (null) (null)
324 694 MULTIPLE ROCKET LAUNCHER HEAVY 491 MULTIPLEROCKETLAUNCHERHEAVY S*G*EWXH--***** (null) (null) (null)
325 692 MULTIPLE ROCKET LAUNCHER LIGHT 489 MULTIPLEROCKETLAUNCHERLIGHT S*G*EWXL--***** (null) (null) (null)
326 693 MULTIPLE ROCKET LAUNCHER MEDIU 490 MULTIPLEROCKETLAUNCHERMEDIUM S*G*EWXM--***** (null) (null) (null)
327 771 NUCLEAR 583 NUCLEAR S*G*IRNN--H**** (null) (null) (null)
328 188 O/C Force 5 SPACESTATION S*P*T-----***** 113 O/C Staff 188
329 188 O/C Force 5 SPACESTATION S*P*T-----***** 180 O/C TM 188
330 188 O/C Force 5 SPACESTATION S*P*T-----***** 114 O/C Force 188
331 807 O/C Force CE 5 SPACESTATION S*P*T-----***** (null) (null) (null)
332 793 OILER/TANKER 655 OILER/TANKER S*S*XMO---***** (null) (null) (null)
333 792 PATROL 630 PATROL S*S*CP----***** (null) (null) (null)
334 767 PETROLEUM/GAS/OIL 579 PETROLEUM/GAS/OIL S*G*IRP---H**** (null) (null) (null)
335 656 PIPELINE 462 PIPELINE S*G*USXP--***** (null) (null) (null)
336 775 PUBLIC WATER SERVICES 591 PUBLICWATERSERVICES S*G*IUP---H**** (null) (null) (null)
337 757 RADAR 567 RADAR S*G*ESR---***** (null) (null) (null)
338 525 RECONNAISSANCE 226 RECONNAISSANCE S*G*UCR---***** (null) (null) (null)
339 535 RECONNAISSANCE AIR ASSAULT 234 RECONNAISSANCEAIRASSAULT S*G*UCRS--***** (null) (null) (null)
340 536 RECONNAISSANCE AIRBORNE 235 RECONNAISSANCEAIRBORNE S*G*UCRA--***** (null) (null) (null)
341 539 RECONNAISSANCE AMPHIBIOUS 238 RECONNAISSANCEMARINE S*G*UCRR--***** (null) (null) (null)
342 540 RECONNAISSANCE AMPHIBIOUS DIVI 239 RECONNAISSANCEMARINEDIVISION S*G*UCRRD-***** (null) (null) (null)
343 541 RECONNAISSANCE AMPHIBIOUS FORC 240 RECONNAISSANCEMARINEFORCE S*G*UCRRF-***** (null) (null) (null)
344 530 RECONNAISSANCE CAVALRY 228 RECONNAISSANCECAVALRY S*G*UCRV--***** (null) (null) (null)
345 534 RECONNAISSANCE CAVALRY AIR 232 RECONNAISSANCECAVALRYAIR S*G*UCRVO-***** (null) (null) (null)
346 531 RECONNAISSANCE CAVALRY ARMOURE 229 RECONNAISSANCECAVALRYARMOURED S*G*UCRVA-***** (null) (null) (null)
347 533 RECONNAISSANCE CAVALRY GROUND 231 RECONNAISSANCECAVALRYGROUND S*G*UCRVG-***** (null) (null) (null)
348 532 RECONNAISSANCE CAVALRY MOTORIZ 230 RECONNAISSANCECAVALRYMOTORIZED S*G*UCRVM-***** (null) (null) (null)
349 538 RECONNAISSANCE LIGHT 237 RECONNAISSANCELIGHT S*G*UCRLL--***** (null) (null) (null)
350 542 RECONNAISSANCE MARINE LIGHT AR 241 RECONNAISSANCEMARINELIGHTARMOUREDRECONNAISSANCE(LA S*G*UCRRL-***** (null) (null) (null)
351 537 RECONNAISSANCE MOUNTAIN 236 RECONNAISSANCEMOUNTAIN S*G*UCRO--***** (null) (null) (null)
352 543 RECONNAISSANCE SURVEILLANCE LO 242 RECONNAISSANCELONGRANGESURVEILLANCE(LRS) S*G*UCRX--***** (null) (null) (null)
353 700 RIFLE 497 RIFLE S*G*EWRR--***** 210 Soldier Assault Rifle 700
354 699 RIFLE/AUTOMATIC WEAPON 496 RIFLE/AUTOMATICWEAPON S*G*EWR---***** 205 Soldier Tgt 699
355 699 RIFLE/AUTOMATIC WEAPON 496 RIFLE/AUTOMATICWEAPON S*G*EWR---***** 216 Soldier M203 699
356 699 RIFLE/AUTOMATIC WEAPON 496 RIFLE/AUTOMATICWEAPON S*G*EWR---***** 153 Soldier MP 699
357 438 ROTARY WING ATTACK 131 ATTACKROTARYWING S*G*UCVRA-***** (null) (null) (null)
358 347 ROTARY WING ATTACK 40 ATTACK S*A*MHA---***** (null) (null) (null)
359 352 ROTARY WING DRONE (RPV/UAV) 49 DRONE(RPV/UAV) S*A*MHQ---***** (null) (null) (null)
360 348 ROTARY WING MEDEVAC 55 MEDEVAC S*A*MHO---***** (null) (null) (null)
361 351 ROTARY WING RECCE 48 RECONNAISSANCE S*A*MHR---***** (null) (null) (null)
362 349 ROTARY WING SOF 56 SPECIALOPERATIONSFORCE(SOF) S*A*MHM---***** (null) (null) (null)
363 350 ROTARY WING UTILITY 42 UTILITY S*A*MHU---***** (null) (null) (null)
364 782 SEAPORT/NAVAL BASE 606 SEAPORT/NAVALBASE S*G*IBN---H**** (null) (null) (null)
365 786 SEA SURFACE INSTALLATION, OIL RIG / PLATFORM 611 SEASURFACEINSTALLATION,OILRIG/PLATFORM S*G*IRR---H**** (null) (null) (null)
366 787 SEA SURFACE TRACK 612 SEASURFACETRACK S*S*------***** (null) (null) (null)
367 740 SEMI 548 SEMI S*G*EVUS--***** (null) (null) (null)
368 756 SENSOR 566 SENSOR S*G*ES----***** (null) (null) (null)
369 616 SERVICE SUPPORT MEDICAL 364 MEDICAL S*G*USM---***** (null) (null) (null)
370 641 SERVICE SUPPORT TRANSPORTATION 424 TRANSPORTATION S*G*UST---***** 53 TATRA Logistics Carrier 641
371 665 SHORT RANGE AD MISSILE LAUNCHE 472 SHORTRANGEADMISSILELAUNCHERS S*G*EWMAS-***** (null) (null) (null)
372 669 SHORT RANGE SS MISSILE LAUNCH 477 SHORTRANGESSMISSILELAUNCH S*G*EWMSS-***** (null) (null) (null)
373 593 SIGNALS UNIT FORWARD COMMUNICATIONS 303 FORWARDCOMMUNICATIONS S*G*UUSF--***** (null) (null) (null)
374 597 SIGNALS UNIT SIGNAL SUPPORT 312 SIGNALSUPPORT S*G*UUSS--***** (null) (null) (null)
375 589 SIGNAL UNIT 298 SIGNALUNIT S*G*UUS---***** (null) (null) (null)
376 590 SIGNAL UNIT AREA 299 AREA S*G*UUSA--***** (null) (null) (null)
377 592 SIGNAL UNIT COMMAND OPERATIONS 302 COMMANDOPERATIONS S*G*UUSO--***** (null) (null) (null)
378 591 SIGNAL UNIT COMMUNICATION CONF 300 COMMUNICATIONCONFIGUREDPACKAGE S*G*UUSC--***** (null) (null) (null)
379 599 SIGNAL UNIT ELECTRONIC RANGING 314 ELECTRONICRANGING S*G*UUSX--***** (null) (null) (null)
380 594 SIGNAL UNIT RADIO UNIT 308 RADIOUNIT S*G*UUSR--***** (null) (null) (null)
381 596 SIGNAL UNIT RADIO UNIT RELAY 311 RELAY S*G*UUSRW-***** (null) (null) (null)
382 595 SIGNAL UNIT RADIO UNIT TACTICA 309 TACTICALSATELLITE S*G*UUSRS-***** (null) (null) (null)
383 598 SIGNAL UNIT TELEPHONE SWITCH 313 TELEPHONESWITCH S*G*UUSW--***** (null) (null) (null)
384 687 SINGLE ROCKET LAUNCHER 484 SINGLEROCKETLAUNCHER S*G*EWS---***** (null) (null) (null)
385 690 SINGLE ROCKET LAUNCHER HEAVY 487 SINGLEROCKETLAUNCHERHEAVY S*G*EWSH--***** (null) (null) (null)
386 688 SINGLE ROCKET LAUNCHER LIGHT 485 SINGLEROCKETLAUNCHERLIGHT S*G*EWSL--***** (null) (null) (null)
387 689 SINGLE ROCKET LAUNCHER MEDIUM 486 SINGLEROCKETLAUNCHERMEDIUM S*G*EWSM--***** (null) (null) (null)
388 796 SOF AVIATION FIXED WING 707 SOFUNITFIXEDWING S*F*AF----***** (null) (null) (null)
389 797 SOF AVIATION FIXED WING ATTACK 708 SOFUNITATTACK S*F*AFA---***** (null) (null) (null)
390 798 SOF AVIATION FIXED WING UTILIT 710 SOFUNITUTILITY S*F*AFU---***** (null) (null) (null)
391 799 SOF AVIATION FIXED WING UTILIT 711 SOFUNITUTILITY(LIGHT) S*F*AFUL--***** (null) (null) (null)
392 800 SOF AVIATION ROTARY WING 715 SOFUNITROTARYWING S*F*AH----***** (null) (null) (null)
393 803 SOF UNIT GROUND 727 SOFUNITGROUND S*F*G-----***** (null) (null) (null)
394 805 SOF UNIT GROUND RANGER 729 SOFUNITRANGER S*F*GSR---***** (null) (null) (null)
395 804 SOF UNIT GROUND SPECIAL FORCES 728 SOFUNITSPECIALFORCES S*F*GS----***** (null) (null) (null)
396 801 SOF UNIT NAVAL 722 SOFUNITSOFUNITNAVAL S*F*SN----***** (null) (null) (null)
397 802 SOF UNIT NAVAL SPECIAL BOAT 725 SOFUNITSPECIALBOAT S*F*SNB---***** (null) (null) (null)
398 806 SOF UNIT PSYCHOLOGICAL OPERATI 730 SOFUNITPSYCHOLOGICALOPERATIONS(PSYOPS) S*F*GSP---***** (null) (null) (null)
399 658 SPECIAL C2 HEADQUATERS COMPONE 464 SPECIALC2HEADQUARTERSCOMPONENT S*G*UH----***** (null) (null) (null)
400 795 SPECIAL OPERATIONS FORCE (SOF) 705 SPECIALOPERATIONSFORCE(SOF)UNIT S*F*------***** (null) (null) (null)
401 625 SUPPLY 379 SUPPLY S*G*USS---***** (null) (null) (null)
402 633 SUPPLY CLASS I 382 SUPPLYCLASSI S*G*USS1--***** (null) (null) (null)
403 634 SUPPLY CLASS II 385 SUPPLYCLASSII S*G*USS2--***** (null) (null) (null)
404 635 SUPPLY CLASS III 388 SUPPLYCLASSIII S*G*USS3--***** (null) (null) (null)
405 636 SUPPLY CLASS III AVIATION 391 SUPPLYCLASSIIIAVIATION S*G*USS3A-***** (null) (null) (null)
406 637 SUPPLY CLASS IV 394 SUPPLYCLASSIV S*G*USS4--***** (null) (null) (null)
407 627 SUPPLY CLASS IX 409 SUPPLYCLASSIX S*G*USS9--***** (null) (null) (null)
408 638 SUPPLY CLASS V 397 SUPPLYCLASSV S*G*USS5--***** (null) (null) (null)
409 639 SUPPLY CLASS VI 400 SUPPLYCLASSVI S*G*USS6--***** (null) (null) (null)
410 640 SUPPLY CLASS VII 403 SUPPLYCLASSVII S*G*USS7--***** (null) (null) (null)
411 626 SUPPLY CLASS VIII 406 SUPPLYCLASSVIII S*G*USS8--***** (null) (null) (null)
412 628 SUPPLY CLASS X 412 SUPPLYCLASSX S*G*USSX--***** (null) (null) (null)
413 629 SUPPLY LAUNDRY/BATH 415 SUPPLYLAUNDRY/BATH S*G*USSL--***** (null) (null) (null)
414 632 SUPPLY MATERIEL (STOCK) 1335 SUPPLYMATERIEL(STOCK) S*G*US**--***** (null) (null) (null)
415 630 SUPPLY WATER 418 SUPPLYWATER S*G*USSW--***** (null) (null) (null)
416 631 SUPPLY WATER PURIFICATION 421 SUPPLYWATERPURIFICATION S*G*USSWP-***** (null) (null) (null)
417 668 SURFACE- SURFACE (SS) MISSILE 476 SURFACE-SURFACE(SS)MISSILELAUNCHER S*G*EWMS--***** (null) (null) (null)
418 355 SURFACE TO AIR MISSILE 65 SURFACETOAIRMISSILE(SAM) S*A*WMSA--***** (null) (null) (null)
419 354 SURFACE TO SURFACE MISSILE 64 SURFACETOSURFACEMISSILE(SSM) S*A*WMSS--***** (null) (null) (null)
420 391 SURVEILLANCE 1334 SURVEILLANCE S*G*F-S---***** (null) (null) (null)
421 725 TANK 533 TANK S*G*EVAT--***** 233 0Vehicle 725
422 725 TANK 533 TANK S*G*EVAT--***** 43 MBT 725
423 725 TANK 533 TANK S*G*EVAT--***** 230 LEOPARD 2A5 725
424 730 TANK HEAVY 538 TANKHEAVY S*G*EVATH-***** (null) (null) (null)
425 731 TANK HEAVY RECOVERY 539 TANKHEAVYRECOVERY S*G*EVATY-***** (null) (null) (null)
426 726 TANK LIGHT 534 TANKLIGHT S*G*EVATL-***** (null) (null) (null)
427 727 TANK LIGHT RECOVERY 535 TANKLIGHTRECOVERY S*G*EVATW-***** 110 BMP3 Recovery 727
428 728 TANK MEDIUM 536 TANKMEDIUM S*G*EVATM-***** (null) (null) (null)
429 729 TANK MEDIUM RECOVERY 537 TANKMEDIUMRECOVERY S*G*EVATX-***** (null) (null) (null)
430 773 TELECOMMUNICATIONS FACILITY 589 TELECOMMUNICATIONSFACILITY S*G*IUT---H**** (null) (null) (null)
431 603 TOPOGRAPHIC 318 TOPOGRAPHIC S*G*UUT---***** (null) (null) (null)
432 751 TRAILER MOUNTED 559 TRAILERMOUNTED S*G*EVEMT-***** (null) (null) (null)
433 754 TRAIN LOCOMOTIVE 564 TRAINLOCOMOTIVE S*G*EVST--***** (null) (null) (null)
434 645 TRANSPORTATION APOD/APOE 436 APOD/APOE S*G*USTA--***** (null) (null) (null)
435 647 TRANSPORTATION INTERMODAL 1328 TRANSPORTATIONINTERMODAL S*G*UST---***** (null) (null) (null)
436 646 TRANSPORTATION MISSILE 439 MISSILE S*G*USTI--***** (null) (null) (null)
437 642 TRANSPORTATION MOVEMENT CONTRO 427 MOVEMENTCONTROLCENTRE(MCC) S*G*USTM--***** (null) (null) (null)
438 643 TRANSPORTATION RAILHEAD 430 RAILHEAD S*G*USTR--***** (null) (null) (null)
439 644 TRANSPORTATION SPOD/SPOE 433 SPOD/SPOE S*G*USTS--***** (null) (null) (null)
440 783 TRANSPORT FACILITY 607 TRANSPORTFACILITY S*G*IT----H**** (null) (null) (null)
441 661 UNITS GENERAL LIAISON 467 UNITGENERALLIAISON S*G*UHGL--***** (null) (null) (null)
442 738 UTILITY VEHICLE 546 UTILITYVEHICLE S*G*EVU---***** 54 HMMWV Utility 738
443 738 UTILITY VEHICLE 546 UTILITYVEHICLE S*G*EVU---***** 221 Vehicle Tgt 738
444 743 WATER CRAFT 551 WATERCRAFT S*G*EVUR--***** 213 TATRA Tanker Water 743
445 353 WEAPON 61 WEAPON S*A*W-----***** (null) (null) (null)
+42
View File
@@ -0,0 +1,42 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# PlanModel
SET(GeometryModel_SRCS
geometry_model.dtd
geometry_model.cpp
geometry_model.h
geometry_model_export.h
geometry_model_factory.cpp
geometry_model_factory.h
geometry_model_q_dom.cpp
geometry_model_q_dom.h
geometry_node_visitor.cpp
geometry_node_visitor.h
geometry_pixelTextBox.cpp
)
SOURCE_GROUP(GeometryModel FILES ${GeometryModel_SRCS})
NGL_ADD_LIBRARY(WS situationMapGeometryModel SHARED ${GeometryModel_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES( situationMapGeometryModel
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/..
)
NGL_TARGET_LINK_LIBRARIES(situationMapGeometryModel
PRIVATE
NGLLogger
PUBLIC
situationMapCommon
Qt5::Core
Qt5::Gui
Qt5::Xml
)
NGL_INSTALL_TARGET(situationMapGeometryModel)
+38
View File
@@ -0,0 +1,38 @@
/**
**
** @RDE_HEADER@
** GeometryModel to write and read PlanEditor plans.
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 11.11.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "geometry_model.h"
namespace SituationMap
{
GeometryModel::GeometryModel(QObject *parent) : QObject(parent) {;}
GeometryModel::GeometryModel(const GeometryModel &) : QObject() {;}
} // namespace SituationMap
+400
View File
@@ -0,0 +1,400 @@
<!--
DTD fuer Plan-Formate
(c)RDE 2009
Stephan Kuhagen
-->
<!--
The Top-Element of the Plan. Defines global variables in the Attributes.
-->
<!ELEMENT GeometryModelDocument (GeometryModel|MapSettings) >
<!ELEMENT GeometryModel (dictionarySymbol|ellipse|line|polyline|rectangle|spline|symbol|text|node)>
<!ELEMENT MapSettings EMPTY>
<!--
utm_zone: UTM-zone and band (two digits, one char)
utm_grid: UTM-grid-Square (two chars)
utm_east: UTM-easting-value (int)
utm_north: UTM-northing-value (int)
pe_show_utm: bool to indicate, if the PE should display the UTM-grid
pe_map_saturation: saturation in % of the map in the PE
pe_map_brightness: brightness in % of the map in the PE
pe_map_zoom: zoom-value of the map in the PE
pe_map_rotation: The rotation of the map (double)
pe_map_type: The type of the map (Raster, Vector, Contour, Elevation, RasterElevation)
pe_map_centerx: center-x of the map in the PE
pe_map_centery: center-y of the map in the PE
-->
<!ATTLIST MapSettings
utm_zone CDATA #REQUIRED
utm_grid CDATA #REQUIRED
utm_east CDATA #REQUIRED
utm_north CDATA #REQUIRED
pe_show_utm CDATA #REQUIRED
pe_map_saturation CDATA #REQUIRED
pe_map_brightness CDATA #REQUIRED
pe_map_zoom CDATA #REQUIRED
pe_map_rotation CDATA #REQUIRED
pe_map_type CDATA #REQUIRED
pe_map_centerx CDATA #REQUIRED
pe_map_centery CDATA #REQUIRED
pe_symbol_transparency CDATA #IMPLIED
pe_symbol_fill_type CDATA #IMPLIED
pe_symbol_scale CDATA #IMPLIED>
<!--
A node is a grouping element, which can hold any number of primitives or
other nodes, thus creating a tree.
-->
<!ELEMENT node (dictionarySymbol|ellipse|line|polyline|rectangle|spline|symbol|text|node)*>
<!--
The symbology library provides a symbol dictionary. Each symbol is defined by a list of coordinates and one non-ambiguous SIDC code. The SIDC
is a string with 15 character. See symbology library for further details.
-->
<!ELEMENT dictionarySymbol (point+)>
<!ATTLIST dictionarySymbol
GuiDisplayName CDATA #IMPLIED
SIDC CDATA #REQUIRED
SIDC_Norm CDATA #REQUIRED >
<!--
Defines ellipsis and circles. Can have start-angle and extent for sections of
circles/ellipsis. The point defines the center of the primitive. The
Attributes width and height define the metric dimensions, resulting in a
centered bounding box. The primitive can be rotated with attribute
rotate. Start-angle and extent are defined for the axis-parallel bounding-box
and are rotated with the box. Rotation is done around the center-point.
The optional text-tag is used for text directly assigned to this primitive.
-->
<!ELEMENT ellipse (point,text?)>
<!--
width: The metric width of the ellipse.
height: The metric height of the ellipse.
rotate: The bounding rectangle, that defines the ellipse is rotated according
to the angle here (360° for full rotation). Double-Value.
start: Sets the start-angle of an open ellipse before (!) rotation. Double-Value.
extent: Sets the extent of the ellipse. For a full ellipse this must be
360. Double-Value.
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
linewidth: Line-width. Double-Value.
linestyle: An enum defining the line-style
fill: A bool, if true, the primitive should be filled with the given color and pattern.
fill_color: Fill-Color in 32-Bit hex RGBA (#RRGGBBAA)
fill_pattern: An enum defining the fill-pattern.
fill_style: An enum defining the style for a filles ellipse:
- "chord": A straight line between the start-point and end-point
defines the inner region to be filled.
- "pieslice": A line from the start-point to the center and from the
center to the end-point define the inner region to be filled.
-->
<!ATTLIST ellipse
GuiDisplayName CDATA #IMPLIED
rotate CDATA #IMPLIED
width CDATA #REQUIRED
height CDATA #REQUIRED
start CDATA #IMPLIED
extent CDATA #IMPLIED
color CDATA #REQUIRED
linewidth CDATA #REQUIRED
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED
fill CDATA #IMPLIED
fill_color CDATA #IMPLIED
fill_pattern (none|dots|hor1|hor2|ver1|ver2|diag1|diag2|solid) #IMPLIED
fill_style (chord|pieslice) #IMPLIED>
<!--
Defines a line with start- and endpoint.
The optional text-tag is used for text directly assigned to this primitive.
-->
<!ELEMENT line (point,point,text?)>
<!--
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
arrows: Enum defining, if and where to add arrows to the line.
arrow_height: The height of the arrow from the arrow-head to the outer points,
parallel to the middle axis of the arrow.
arrow_clamp_height: The height from the the arrow-neck to the outer points,
parallel to the middle axis of the arrow.
arrow_width: The distance between the outer points of the arrow.
arrow_line_width: The line width of the line used to draw the arrow.
linewidth: Line-width. Double-Value.
linestyle: An enum defining the line-style
-->
<!ATTLIST line
GuiDisplayName CDATA #IMPLIED
color CDATA #REQUIRED
arrows (none|start|end|both) #IMPLIED
arrow_height CDATA #IMPLIED
arrow_clamp_height CDATA #IMPLIED
arrow_width CDATA #IMPLIED
arrow_line_width CDATA #IMPLIED
linewidth CDATA #REQUIRED
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED>
<!--
Defines a polyline with at least three points.
The optional text-tag is used for text directly assigned to this primitive.
-->
<!ELEMENT polyline (point,point,point+,text?)>
<!--
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
linewidth: Line-width. Double-Value.
linestyle: An enum defining the line-style
arrows: Enum defining, if and where to add arrows to the line. If the
primitive is closed, no arrows should be drawn.
arrow_height: The height of the arrow from the arrow-head to the outer points,
parallel to the middle axis of the arrow.
arrow_clamp_height: The height from the the arrow-neck to the outer points,
parallel to the middle axis of the arrow.
arrow_width: The distance between the outer points of the arrow.
arrow_line_width: The line width of the line used to draw the arrow.
close: A bool. If true, connect the start- and end-point.
fill: A bool, if true, the primitive should be filled with the given color and pattern.
fill_color: Fill-Color in 32-Bit hex RGBA (#RRGGBBAA)
fill_pattern: An enum defining the fill-pattern.
-->
<!ATTLIST polyline
GuiDisplayName CDATA #IMPLIED
color CDATA #REQUIRED
linewidth CDATA #REQUIRED
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED
arrows (none|start|end|both) #IMPLIED
arrow_height CDATA #IMPLIED
arrow_clamp_height CDATA #IMPLIED
arrow_width CDATA #IMPLIED
arrow_line_width CDATA #IMPLIED
close CDATA #REQUIRED
fill CDATA #IMPLIED
fill_color CDATA #IMPLIED
fill_pattern (none|dots|hor1|hor2|ver1|ver2|diag1|diag2|solid) #IMPLIED>
<!--
Defines a rectangle with a center-point and width/height.
The optional text-tag is used for text directly assigned to this primitive.
-->
<!ELEMENT rectangle (point,text?)>
<!--
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
width: The metric width of the rectangle.
height: The metric height of the rectangle.
rotate: The rectangle is rotated according to the angle here (360° for full
rotation). Double-Value.
linewidth: Line-width. Double-Value.
linestyle: An enum defining the line-style
rounding: A percentage-value (double) for round edges
fill: A bool, if true, the primitive should be filled with the given color and pattern.
fill_color: Fill-Color in 32-Bit hex RGBA (#RRGGBBAA)
fill_pattern: An enum defining the fill-pattern.
-->
<!ATTLIST rectangle
GuiDisplayName CDATA #IMPLIED
color CDATA #REQUIRED
width CDATA #REQUIRED
height CDATA #REQUIRED
rotate CDATA #IMPLIED
linewidth CDATA #REQUIRED
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED
rounding CDATA #IMPLIED
fill CDATA #IMPLIED
fill_color CDATA #IMPLIED
fill_pattern (none|dots|hor1|hor2|ver1|ver2|diag1|diag2|solid) #IMPLIED>
<!--
Defines a spline with at least three points. The first and the last point
define the endpoints, all other points define the curve between them.
The optional text-tag is used for text directly assigned to this primitive.
-->
<!ELEMENT spline (point,point,point+,text?)>
<!--
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
linewidth: Line-width. Double-Value.
linestyle: An enum defining the line-style
arrows: Enum defining, if and where to add arrows to the line. If the
primitive is closed, no arrows should be drawn.
arrow_height: The height of the arrow from the arrow-head to the outer points,
parallel to the middle axis of the arrow.
arrow_clamp_height: The height from the the arrow-neck to the outer points,
parallel to the middle axis of the arrow.
arrow_width: The distance between the outer points of the arrow.
arrow_line_width: The line width of the line used to draw the arrow.
close: A bool. If true, connect the start- and end-point.
fill: A bool. If true, the primitive should be filled with the given color and
pattern. This also means, that the start-point is automatically
connected to the end-point to get a closed shape to fill.
fill_color: Fill-Color in 32-Bit hex RGBA (#RRGGBBAA)
fill_pattern: An enum defining the fill-pattern.
-->
<!ATTLIST spline
GuiDisplayName CDATA #IMPLIED
color CDATA #REQUIRED
linewidth CDATA #REQUIRED
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED
arrows (none|start|end|both) #IMPLIED
arrow_height CDATA #IMPLIED
arrow_clamp_height CDATA #IMPLIED
arrow_width CDATA #IMPLIED
arrow_line_width CDATA #IMPLIED
close CDATA #REQUIRED
fill CDATA #IMPLIED
fill_color CDATA #IMPLIED
fill_pattern (none|dots|hor1|hor2|ver1|ver2|diag1|diag2|solid) #IMPLIED>
<!--
A symbol to display in the plan.
position, offsetx (in Pixel), offsety (in Pixel), direction of movement
-->
<!ELEMENT symbol (point)>
<!--
text_w: Text for symbols text-field w.
text_xy: Text for symbols text-field xy.
text_v: Text for symbols text-field v.
text_t: Text for symbols text-field t.
text_z: Text for symbols text-field z.
text_ef: Text for symbols text-field ef.
text_g: Text for symbols text-field g.
text_h: Text for symbols text-field h.
text_m: Text for symbols text-field m.
text_jklnp: Text for symbols text-field jklnp.
symbol_id: ID of the symbol (int).
force_id: Force-ID of the symbol (int).
abc_protection: Flag for abc_protection (bool).
affil: Enum for affiliation of the symbol.
mobility: Enum for the mobility of the symbol.
w_vbg_et: Enum for tactical state of the symbol. Corresponds to enum w_vbg_et
in zskssmal_teilnehmer.h.
rotate: The Symbol is rotated according
to the angle here (360° for full rotation). Double-Value.
-->
<!ATTLIST symbol
GuiDisplayName CDATA #IMPLIED
text_w CDATA #IMPLIED
text_xy CDATA #IMPLIED
text_v CDATA #IMPLIED
text_t CDATA #IMPLIED
text_z CDATA #IMPLIED
text_ef CDATA #IMPLIED
text_g CDATA #IMPLIED
text_h CDATA #IMPLIED
text_m CDATA #IMPLIED
text_jklnp CDATA #IMPLIED
symbol_id CDATA #IMPLIED
symbol_offsetX CDATA #IMPLIED
symbol_offsetY CDATA #IMPLIED
symbol_direction CDATA #IMPLIED
force_id CDATA #IMPLIED
symbol_state CDATA #IMPLIED
symbol_uncertainty CDATA #IMPLIED
damage_force_id CDATA #IMPLIED
abc_protection CDATA #IMPLIED
affil (unknown|friend|neutral|enemy) #REQUIRED
mobility (wheel|wheel_all_terrain|chain|chain_all_terrain|trailer|train) #REQUIRED
w_vbg_et (einsatzbereit|treffer_ohne_wirkung|annaehender_treffer|zeitlicher_ausfall|leichter_treffer|mittlerer_treffer|schwerer_treffer|bewegungsunfaehig|bewegungsunfaehig_sichtb|ausfall_waffenanlage|ausfall_waffenanlage_sichtb|totalausfall) #REQUIRED
rotate CDATA #IMPLIED>
<!--
A one-line or multiline-text with optional background and frame.
If used as a child to another primitive, the point position of the text is
ignored. The alignment attributes define the text-position in relation to the
primitive instead.
-->
<!ELEMENT text (point,text_data)>
<!--
anchor_horizontal: Horizontal position of the text on its point
anchor_vertical: Vertical position of the text on its point
margin_horizontal: Horizontal margin in Pixels between the texts bounding box and the surrounding frame
margin_vertical: Vertical margin in Pixels between the texts bounding box and the surrounding frame
color: Color in 32-Bit hex RGBA (#RRGGBBAA)
font: Font-Type
font_size: Font-Size. Int.
font_italic: A bool. If true, the font should be italic.
font_bold: A bool. If true, the font should be bold.
box: A bool, if true, the primitive should be filled with the given color and pattern.
linewidth: Line-width for the box. Double-Value.
linestyle: An enum defining the line-style for the box.
linecolor: Color in 32-Bit hex RGBA (#RRGGBBAA) for the outline of the box.
fill: A bool, if true, the box should be filled with the given color and pattern.
fill_color: Fill-Color for the box in 32-Bit hex RGBA (#RRGGBBAA)
fill_pattern: An enum defining the fill-pattern for the box.
rotate: The bounding rectangle, that defines the ellipse is rotated according
to the angle here (360° for full rotation). Double-Value.
-->
<!ATTLIST text
GuiDisplayName CDATA #IMPLIED
anchor_horizontal (left|center|right) #REQUIRED
anchor_vertical (top|center|bottom) #REQUIRED
margin_horizontal CDATA #IMPLIED
margin_vertical CDATA #IMPLIED
color CDATA #REQUIRED
font (SansSerif|Serif|Fixed|Decorative) #REQUIRED
font_size CDATA #REQUIRED
font_italic CDATA #IMPLIED
font_bold CDATA #IMPLIED
box CDATA #IMPLIED
linewidth CDATA #IMPLIED
linestyle (solid|dashed|dotted|dashed_dotted) #IMPLIED
linecolor CDATA #IMPLIED
fill CDATA #IMPLIED
fill_color CDATA #IMPLIED
fill_pattern (none|dots|hor1|hor2|ver1|ver2|diag1|diag2|solid) #IMPLIED
rotate CDATA #IMPLIED>
<!--
A tag that contains the actual text-data of a text-tag.
-->
<!ELEMENT text_data (#PCDATA)>
<!--
alignment: If this text contains more than one line, this defines the
alignment of the text in the bounding box of all lines.
-->
<!ATTLIST text_data
alignment (left|center|right) #REQUIRED>
<!--
Defines a point with a double precision x and y-value.
-->
<!ELEMENT point EMPTY>
<!--
x: The x-coordinate of the point.
y: The y-coordinate of the point.
-->
<!ATTLIST point
x CDATA #REQUIRED
y CDATA #REQUIRED>
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,21 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <qglobal.h>
#ifndef GEOMETRYMODEL_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define GEOMETRYMODEL_EXPORT
# else
# if defined(MAKE_SITUATIONMAPGEOMETRYMODEL_LIB)
# define GEOMETRYMODEL_EXPORT Q_DECL_EXPORT
# else
# define GEOMETRYMODEL_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
@@ -0,0 +1,58 @@
/**
**
** @RDE_HEADER@
** GeometryModelFactory to create geometry model
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 20.11.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "geometry_model_factory.h"
#include "geometry_model_q_dom.h"
namespace SituationMap
{
GeometryModelFactory *GeometryModelFactory::singleton()
{
static GeometryModelFactory s_factory;
return &s_factory;
} /* GeometryModelFactory::singleton() */
GeometryModel *GeometryModelFactory::create()
{
return new GeometryModelQDom();
} // GeometryModelFactory::create()
GeometryModel *GeometryModelFactory::clone(GeometryModel *geoModel)
{
GeometryModelQDom * qdomModel = dynamic_cast<GeometryModelQDom*>(geoModel);
if (qdomModel)
return new GeometryModelQDom(*qdomModel);
return nullptr;
} // GeometryModelFactory::clone()
} /* namespace SituationMap */
@@ -0,0 +1,59 @@
/**
**
** @RDE_HEADER@
** GeometryModelFactory to create geometry model
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 20.11.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "geometry_model_q_dom.h"
namespace SituationMap
{
/**
@brief Factory class to create GeometryModels
@see GeometryModel GeometryModelQDom
*/
class GEOMETRYMODEL_EXPORT GeometryModelFactory
{
public:
static GeometryModelFactory *singleton();
GeometryModelFactory() = default;
~GeometryModelFactory() = default;
GeometryModelFactory(const GeometryModelFactory &) = delete;
GeometryModelFactory operator =(const GeometryModelFactory &) = delete;
GeometryModel *create();
GeometryModel *clone( GeometryModel * );
}; /* GeometryModelFactory */
} /* namespace SituationMap */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,374 @@
/**
**
** @RDE_HEADER@
** GeometryModel implementation to write and read PlanEditor plans from/to XML and manipulate DOM-tree.
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Stephan Kuhagen <kuhagen@rheinmetall-de.com>
** Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** ??.??.200?, SK : First edition for use with Qt4
** 11.11.2015, JT : Splitting interface and implementation
**
** -----------------------------------------------------------------------------------------------
*/
// clazy:excludeall=const-signal-or-slot
#pragma once
#include <QtGui/QColor>
#include <QtXml/QDomDocument>
#include <QtCore/QMultiMap>
#include <QtCore/QObject>
#include <QtCore/QPair>
#include <QtCore/QPointF>
#include <QtCore/QRectF>
#include <QtCore/QStack>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include "geometry_model.h"
class QTransform;
namespace SituationMap
{
// exported for unit test only
class GEOMETRYMODEL_EXPORT GeometryModelQDom : public GeometryModel, public QDomDocument
{
Q_OBJECT
public:
explicit GeometryModelQDom(QObject *parent = nullptr);
//! Copy-Constructor
GeometryModelQDom(const GeometryModelQDom &other);
~GeometryModelQDom();
GeometryModelQDom & operator = (const GeometryModelQDom &other);
QByteArray toByteArray() const override;
QByteArray toByteArrayDebug() const override;
bool fromByteArray(const QByteArray &content) override;
bool fromDevice(QIODevice *device) override;
bool fromByteArrayDebug(const QByteArray &content) override;
bool isEmpty() const override;
Node getRootNode() const override;
Node getMapDefaultSettingsNode() const override;
void setModelAttribute(GeometryModel::Attribute attribute, const QVariant &value) override;
void setModelEditorAttribute(GeometryModel::Attribute attribute, const QVariant &value) override;
void setPrimitiveAttribute(const GeometryModel::Node &node, GeometryModel::Attribute attribute, const QVariant &value) override;
void movePrimitiveIntoGroup(const GeometryModel::Node &primitive, const GeometryModel::Node &target) override;
void releaseGroup(const GeometryModel::Node &group) override;
void deleteGroup(const GeometryModel::Node &group) override;
void removePrimitive(const GeometryModel::Node &primitive) override;
void removePrimitivesByUserData(const QList<int> &userDataList) override;
void removeText(GeometryModel::Node &parent) override;
void setTextData(const GeometryModel::Node &textNode, const QString &data, GeometryModel::HorizontalAlign textAlign) override;
void clearModel() override;
void translateNode(const GeometryModel::Node &node, double x, double y) override;
void moveNode(const GeometryModel::Node &node, double x, double y) override;
void scaleNode(const GeometryModel::Node &node, double scaleX, double scaleY) override;
void rotateNode(const GeometryModel::Node &node, double angle) override;
void reorderPrimitives(const QList<GeometryModel::Node> &nodes, GeometryModel::PrimitivOrder order) override;
void merge(const GeometryModel::Node &other, bool skipUndo = false, bool intoNewGroup = false) override;
void merge(GeometryModel *other, bool skipUndo = false, bool intoNewGroup = false) override;
unsigned int modificationCounter() const override;
void resetModificationCounter() override;
void undo(unsigned int steps = 1) override;
void redo(unsigned int steps = 1) override;
void enableUndo(bool enable) override;
void startUndoBlock() override;
void endUndoBlock(const QString &eventDescription = QString()) override;
void abortUndoBlock() override;
void setMaxUndoSteps(unsigned int max) override;
unsigned int maxUndoSteps() const override;
void cleanModel() override;
GeometryModel::Node addPrimitive(GeometryModel::PrimitiveType type
, const QList<QPointF> &points
, const QList<QPair<GeometryModel::Attribute, QVariant> > &attributes
, int userData = -1
, const QString &textData = QString()
, GeometryModel::HorizontalAlign textAlign = HorizontalAlign::Left) override;
bool setPrimitivePoints(const GeometryModel::Node &node, const QList<QPointF> &points) override;
GeometryModel::Node addText(const GeometryModel::Node &parent
, const QString &textData
, GeometryModel::HorizontalAlign textAlign
, const QList<QPair<GeometryModel::Attribute, QVariant> > &attributes
, int userData) override;
GeometryModel::Node getText(const GeometryModel::Node &parent) const override;
QString getTextData(const GeometryModel::Node &textNode) const override;
QList<QPointF> getPrimitivePoints(const GeometryModel::Node &node) const override;
QRectF getBoundingBox(const GeometryModel::Node &node) const override;
void setNodeDisplayName(const Node &node, const QString &name) override;
QString getNodeDisplayName(const Node &node) const override;
QVariant getModelAttribute(Attribute attribute) const override;
QVariant getAttribute(const GeometryModel::Node &node, GeometryModel::Attribute attribute) const override;
template <class T> T getAttribute(const Node &node, Attribute attribute) const;
bool hasAttribute(const GeometryModel::Node &node, GeometryModel::Attribute attribute) const override;
QVariant::Type attributeType(const GeometryModel::Attribute &attribute) const override;
QList<GeometryModel::Attribute> supportedAttributes(GeometryModel::PrimitiveType type) const override;
GeometryModel::Node createGroup(const QList<GeometryModel::Node> &primitives) override;
GeometryModel::Node isInGroup(const GeometryModel::Node &primitive) const override;
GeometryModel::NodeList getGroupPrimitives(const GeometryModel::Node &node) override;
GeometryModel::Node findPrimitive(int userData) const override;
bool hasUserData(const Node &node) const override;
int getUserData(const GeometryModel::Node &node, bool *ok = nullptr) const override;
void setUserData(const GeometryModel::Node &node, int userData) override;
QMultiMap<int, GeometryModel::Node> userDataMap(const GeometryModel::Node &node = GeometryModel::Node()) override;
GeometryModel::Node copy(const GeometryModel::Node &node, int userData = 0) override;
GeometryModel::PrimitiveType getType(const GeometryModel::Node &node) const override;
unsigned int undoSteps() const override;
unsigned int redoSteps() const override;
QStringList undoHistory() const override { return _undoHistory.toList(); }
QStringList redoHistory() const override { return _redoHistory.toList(); }
void clearUndoStack() override
{
_undoStack.clear();
_undoHistory.clear();
} // clearUndoStack
void clearRedoStack() override
{
_redoStack.clear();
_redoHistory.clear();
} // clearRedoStack
QString attributeToString(const GeometryModel::Attribute &attribute) const override;
bool parseSymbolAttributeString(const QString &sidcAttributes, QMap<QString, QVariant> &attrMap) const override;
QString buildSymbolAttributeString(const QMap<QString, QVariant> &attrMap) const override;
static void cleanupStaticMember();
private:
static void valueFromVariant(const QVariant &v, QPointF &result);
static void valueFromVariant(const QVariant &v, QColor &result);
/**
convert to QString (with non locale-aware conversions)
*/
static QString variant2XmlString(const QVariant &v);
/**
Create a QColor from an attribute-value with alpha-channel (QVariant
ignores Alpha)
\param attColor: The QString-QVariant from an attribute of Type QColor
\return QColor with alpha-channel or invalid QColor, if the value could be parsed.
*/
static QColor colorFromString(const QString &attColor);
/**
Create a QPoint from an attribute-value
\param attPoint: The QString-QVariant from an attribute of Type QPointF
\return QPointF
*/
static QPointF pointFromString(const QString &attPoint);
//! A mapping between all primitives and the attributes they support
static QMultiMap<GeometryModel::PrimitiveType, GeometryModel::Attribute> _primitiveSupportedAttributes;
//! Mappings between all primitive-types and their string/tag-name
static QMap<QString, GeometryModel::PrimitiveType> _primitiveTagsTypes;
static QMap<GeometryModel::PrimitiveType, QString> _primitiveTagsStrings;
//! Default-Values for all supported attributes
static QMap<QPair<GeometryModel::PrimitiveType, GeometryModel::Attribute>, QString> _attributeDefaults;
//! Mapping between Attributes and their QVariant-Type.
static QMap<GeometryModel::Attribute, QVariant::Type> _attributeTypes;
//! Bool to check, if static class variables have been initialized
static bool _staticInitDone;
/**
Init data of the object
*/
void init();
/**
Transform the points of a primitive.
\sa {translateNode(), moveNode(), rotateNode(), scaleNode()}
\param node: The primitive to transform.
\param t: The transformation-matrix.
*/
void transformNode(const QDomNode &node, const QTransform &t);
GeometryModel::PrimitiveType getType(const QDomNode &node) const;
bool hasUserData(const QDomNode &node) const;
int getUserData(const QDomNode &node, bool *okPtr) const;
QRectF getBoundingBox(const QDomNode &node) const;
QList<QPointF> getPrimitivePoints(const QDomNode &node) const;
bool hasAttribute(const QDomNode &node, GeometryModel::Attribute attribute) const;
QVariant getAttribute(const QDomNode &node, GeometryModel::Attribute attribute) const;
void removePrimitive(const QDomNode &primitive);
void translateNode(const QDomNode &node, double x, double y);
void moveNode(const QDomNode &node, double x, double y);
void scaleNode(const QDomNode &node, double scaleX, double scaleY);
void rotateNode(const QDomNode &node, double angle);
void merge(const QDomNode &other, bool skipUndo = false, bool intoNewGroup = false);
QDomNode createGroup(const QList<QDomNode> &primitives);
QMultiMap<int, QDomNode> userDataMap(const QDomNode &node) const;
/**
Wrapper for signal changed(), checks _skipChangedSignal
!!! ATTENTION: Do not use the signal changed directly.
Use emitChangedSignal() instead !!!
\param what: Short description of the change for logging
\param node: the changed node (if this is a Null-Node, the Root-Node of
the plan has changed)
\param att: The attribute, that changed. If att==MaxAttributes, then
multiple attributes are changed
\param coordsChanged: if true, the coordinated of the primitive are changed
*/
void emitChangedSignal(const Node &node, Attribute att, bool coordsChanged);
//! Lock for temporarily blocking changed()-Signals
bool _skipChangedSignal;
//! Undo-Stack
bool _undoEnabled;
unsigned int _maxUndoSteps;
QStack<QDomNode> _undoStack;
QStack<QString> _undoHistory;
QStack<QDomNode> _redoStack;
QStack<QString> _redoHistory;
//! Undo-blocks
QDomNode _undoBlock;
QString _undoHistoryBlock;
bool _insideUndoBlock;
unsigned int _modificationCounter;
//! Push/pop current state to undo-stack, if not locked
void pushUndo(const QString &eventDescription = QString());
GeometryModel::Node popUndo();
}; // GeometryModelQDom
template <class T> T GeometryModelQDom::getAttribute(const Node &node, Attribute attribute) const
{
const QVariant &v = getAttribute(node, attribute);
switch (qMetaTypeId<T>())
{
case QMetaType::QPointF:
case QMetaType::QColor:
{
T result; valueFromVariant(v, result); return result;
} break;
default: break;
}
return v.value<T>();
} // template <class T> T GeometryModelQDom::getAttribute( const Node & node, Attribute attribute ) const
} // namespace SituationMap
@@ -0,0 +1,75 @@
/**
**
** @RDE_HEADER@
** Node visitor for GeometryModel.
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 07.07.2016, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "geometry_node_visitor.h"
namespace SituationMap
{
GeometryNodeVisitor::GeometryNodeVisitor(GeometryModel *geoModel) : m_geometryModel(geoModel) {;}
bool GeometryNodeVisitor::traverse()
{
if (!m_geometryModel)
return true;
return traverse(m_geometryModel->getRootNode());
} // bool GeometryNodeVisitor::traverse()
bool GeometryNodeVisitor::traverse(GeometryModel::Node node)
{
if (!m_geometryModel)
return true;
if (node.isValid())
{
const GeometryModel::PrimitiveType primitiveType = m_geometryModel->getType(node);
if ((GeometryModel::PrimitiveType::RootNode == primitiveType) || (GeometryModel::PrimitiveType::Node == primitiveType))
{
if (node.hasChildNodes())
{
node = node.firstChildNode();
while (node.isValid())
{
if (!traverse(node))
return false;
node = node.next();
}
}
}
if (!apply(m_geometryModel, node, primitiveType))
return false;
} // if
return true;
}
} // namespace SituationMap
@@ -0,0 +1,75 @@
/**
**
** @RDE_HEADER@
** Node visitor for GeometryModel.
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 07.07.2016, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "geometry_model.h"
namespace SituationMap
{
/**
GeometryNopdeVisitor implements visitor pattern to traverse geoemtry model tree. The apply function will be
called for each node in geometry model.
*/
class GEOMETRYMODEL_EXPORT GeometryNodeVisitor
{
public:
explicit GeometryNodeVisitor(GeometryModel *geoModel);
virtual ~GeometryNodeVisitor() = default;
GeometryNodeVisitor(const GeometryNodeVisitor &) = delete;
/**
Traversing the complete geometry model
*/
bool traverse();
/**
Traversing the sub-tree of node. Coming in deepth first.
*/
bool traverse(GeometryModel::Node node);
protected:
/**
For each node the apply function will be called. If apply returns false the traversal is aborted. In
other case if return value is true the traversel is continued.
@param geoModel Pointer to geometry model
@param node Node of geometry model
@param nodeType Type of node
@return false to abort traversael otherwise true
*/
virtual bool apply(GeometryModel *geoModel, const GeometryModel::Node &node, GeometryModel::PrimitiveType nodeType) = 0;
GeometryModel *m_geometryModel;
}; // GeometryNodeVisitor
} // namespace SituationMap
@@ -0,0 +1,215 @@
/**
* @RDE_HEADER@
* PixelTextBoxData as Addon to GeometryModel
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2023-04-27
*/
#include "geometry_pixelTextBox.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
#include <QDebug>
namespace SituationMap
{
PixelTextBoxData::PixelTextBoxData(const QString &htmlText, const QColor &backgroundColor)
: m_htmlText(htmlText), m_backgroundColor(backgroundColor)
{
}
void PixelTextBoxData::reset()
{
m_htmlText.clear();
m_backgroundColor = QColor();
m_position = QPoint();
m_size = QSize();
}
bool PixelTextBoxData::isEmpty() const
{
return m_htmlText.isEmpty();
}
QString PixelTextBoxData::toDebugString() const
{
QJsonDocument jDoc(toJson());
return QString::fromStdString(jDoc.toJson(QJsonDocument::JsonFormat::Compact).toStdString());
}
bool PixelTextBoxData::operator==(const PixelTextBoxData &o) const
{
return m_htmlText == o.m_htmlText &&
m_backgroundColor == o.m_backgroundColor &&
m_position == o.m_position &&
m_size == o.m_size;
}
QJsonObject PixelTextBoxData::toJson() const
{
QJsonObject obj;
obj[QStringLiteral("text")] = m_htmlText;
obj[QStringLiteral("backgroundColor")] = m_backgroundColor.name();
obj[QStringLiteral("position")] = QJsonObject({{QStringLiteral("x"), m_position.x()},
{QStringLiteral("y"), m_position.y()},
});
obj[QStringLiteral("size")] = QJsonObject({{QStringLiteral("width"), m_size.width()},
{QStringLiteral("height"), m_size.height()},
});
return obj;
}
bool get(const QJsonObject &obj, const QString &key, int &val)
{
const auto jVal = obj[key];
if (!jVal.isDouble())
{
qCritical() << " isDouble failed";
}
val = jVal.toInt();
return true;
}
PixelTextBoxData PixelTextBoxData::fromJson(const QJsonValue &json)
{
if (json.isUndefined())
return {};
if (!json.isObject())
return {};
PixelTextBoxData ret;
// text
ret.m_htmlText = json[QStringLiteral("text")].toString();
// backgroundColor
QString temp = json[QStringLiteral("backgroundColor")].toString();
ret.m_backgroundColor.setNamedColor(temp);
// position:
{
const auto jVal = json[QStringLiteral("position")];
get(jVal.toObject(), QStringLiteral("x"), ret.m_position.rx());
get(jVal.toObject(), QStringLiteral("y"), ret.m_position.ry());
}
// size:
{
const auto jVal = json[QStringLiteral("size")];
get(jVal.toObject(), QStringLiteral("width"), ret.m_size.rwidth());
get(jVal.toObject(), QStringLiteral("height"), ret.m_size.rheight());
}
return ret;
}
QString PixelTextBoxData::toJsonStr(QJsonDocument::JsonFormat format) const
{
QJsonObject obj = toJson();
QJsonDocument jDoc(obj);
return QString::fromStdString(jDoc.toJson(format).toStdString());
}
PixelTextBoxData PixelTextBoxData::fromJsonStr(const QString &jsonStr)
{
if (jsonStr.isEmpty())
return {};
QJsonParseError parseError;
QJsonDocument jDoc(QJsonDocument::fromJson(jsonStr.toStdString().c_str(), &parseError));
if (parseError.error != QJsonParseError::NoError)
{
qCritical() << " QJsonParseError->errorString: '" << parseError.errorString() << "'"
<< ", offset: " << parseError.offset;
return {};
}
QJsonObject jObj = jDoc.object();
if (jObj.isEmpty())
return {};
return PixelTextBoxData::fromJson(jObj);
}
//
// Container
//
QJsonObject PixelTextBoxData::pixelTextBoxContainerToJson(const QVector<PixelTextBoxData> &ptbdCont)
{
QJsonArray arr;
for (const PixelTextBoxData &item : qAsConst(ptbdCont))
arr.push_back(item.toJson());
QJsonObject jObj;
jObj[QStringLiteral("PixelTextBoxData")] = arr;
return jObj;
}
QVector<PixelTextBoxData> PixelTextBoxData::pixelTextBoxContainerFromJson(const QJsonValue &json)
{
QVector<PixelTextBoxData> ret;
if (!json.isObject())
return ret;
const QJsonObject jObj = json.toObject();
if (!jObj.contains(QStringLiteral("PixelTextBoxData")))
return ret;
const QJsonArray &array = jObj[QStringLiteral("PixelTextBoxData")].toArray();
ret.reserve(array.size());
for(int i = 0; i < array.size(); ++i)
ret.push_back(PixelTextBoxData::fromJson(array.at(i)));
return ret;
}
QString PixelTextBoxData::pixelTextBoxContainerToJsonStr(const QVector<PixelTextBoxData> &ptbdCont, QJsonDocument::JsonFormat format)
{
QJsonObject obj = pixelTextBoxContainerToJson(ptbdCont);
QJsonDocument jDoc(obj);
return QString::fromStdString(jDoc.toJson(format).toStdString());
}
QVector<PixelTextBoxData> PixelTextBoxData::pixelTextBoxContainerFromJsonStr(const QString &jsonStr)
{
if (jsonStr.isEmpty())
return {};
QJsonParseError parseError;
QJsonDocument jDoc(QJsonDocument::fromJson(jsonStr.toStdString().c_str(), &parseError));
if (parseError.error != QJsonParseError::NoError)
{
qCritical() << " QJsonParseError->errorString: '" << parseError.errorString() << "'"
<< ", offset: " << parseError.offset;
return {};
}
QJsonObject jObj = jDoc.object();
if (jObj.isEmpty())
return {};
return PixelTextBoxData::pixelTextBoxContainerFromJson(jObj);
}
//-----------------------------------------------------------------------------
// output operator:
//-----------------------------------------------------------------------------
GEOMETRYMODEL_EXPORT std::ostream &operator<<(std::ostream &stream, const PixelTextBoxData &value)
{
stream << value.toDebugString().toStdString().c_str();
return stream;
}
} // namespace SituationMap
@@ -0,0 +1,69 @@
/**
* @RDE_HEADER@
* PixelTextBoxData as Addon to GeometryModel
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2023-04-27
*/
#pragma once
#include <QString>
#include <QColor>
#include <QPoint>
#include <QSize>
#include <QJsonObject>
#include <QJsonDocument>
#include "geometry_model_export.h"
namespace SituationMap
{
class GEOMETRYMODEL_EXPORT PixelTextBoxData
{
public:
PixelTextBoxData() = default;
explicit PixelTextBoxData(const QString &htmlText, const QColor &backgroundColor);
void reset();
bool isEmpty() const;
QString toDebugString() const;
QString m_htmlText;
QColor m_backgroundColor;
QPoint m_position;
QSize m_size;
// operator
bool operator==(const PixelTextBoxData &o) const;
// Json:
QJsonObject toJson() const;
static PixelTextBoxData fromJson(const QJsonValue &json);
QString toJsonStr(QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented) const;
static PixelTextBoxData fromJsonStr(const QString &jsonStr);
static QJsonObject pixelTextBoxContainerToJson(const QVector<PixelTextBoxData> &ptbdCont);
static QVector<PixelTextBoxData> pixelTextBoxContainerFromJson(const QJsonValue &json);
static QString pixelTextBoxContainerToJsonStr(const QVector<PixelTextBoxData> &ptbdCont, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented);
static QVector<PixelTextBoxData> pixelTextBoxContainerFromJsonStr(const QString &jsonStr);
};
//-----------------------------------------------------------------------------
// output operator:
//-----------------------------------------------------------------------------
GEOMETRYMODEL_EXPORT std::ostream &operator<< (std::ostream &stream,
const PixelTextBoxData &value);
} // namespace SituationMap
@@ -0,0 +1,556 @@
/**
* @RDE_HEADER@
* AbstractGraphicalObject
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "abstract_graphical_object.h"
#include <Map/situation_map_utils.h> // operator<<
// ESRI
#include <arcgis/GeoView.h>
#include <arcgis/Graphic.h>
#include <arcgis/GraphicsOverlay.h>
#include <arcgis/Multipart.h>
// Qt
#include <QDebug>
#include <QSharedPointer>
#include <QApplication>
#include <QThread>
#include <QObject>
namespace SituationMap
{
AbstractGraphicalObject::AbstractGraphicalObject(const Esri::ArcGISRuntime::GeoView *geoView
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
, const QString &debugInfo
, const UniqueMapId &uniqueMapId)
: m_geoView(geoView)
, m_graphicsLayer(graphicsLayer)
, m_uniqueMapId(uniqueMapId)
, m_debugInfo(debugInfo)
, m_logger(getLogger("AbstractGraphicalObject"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
m_pickable = (m_uniqueMapId != INVALID_MAP_ID);
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
}
AbstractGraphicalObject::~AbstractGraphicalObject()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
<< ", m_graphicsLayer-overlayId=" << (m_graphicsLayer ? m_graphicsLayer->overlayId() : QString(QStringLiteral("unknown")));
#if ACRGIS_VERSION >= 0x640F00 // 100.15.0
// removeOne ist helpful to let ModuleTest succeed: 'situationMapModuleTest checkOverlayHandler3 none'
if (m_graphic && m_graphicsLayer && m_graphicsLayer->graphics())
m_graphicsLayer->graphics()->removeOne(m_graphic);
delete m_graphic;
m_graphic = nullptr;
#else
/*
// cleanup
// to make sure, the the graphic is removed from internal container BEFORE
// graphic is deleted, follow the documentation: use Layer::removeGraphic
// (instead 'delete m_graphic')
if (m_graphic && m_graphicsLayer && m_graphicsLayer->graphics())
m_graphicsLayer->graphics()->removeOne(m_graphic);
if (m_graphic)
{
delete m_graphic;
m_graphic = nullptr;
}
*/
// Race condition between removeOne() and delete m_graphic :
// BUG-000116867 is for the deadlock
// BUG-000117464 is for the crash
// Use following workaround until ESRI will release the fix (with 100.5!?)
if (m_graphic && m_graphicsLayer && m_graphicsLayer->graphics())
{
const int idx = m_graphicsLayer->graphics()->indexOf(m_graphic);
if (idx < 0)
ERROR_LOG(m_logger) << LOGFUNCTION << " indexOf failed, debugInfo='" << m_debugInfo << "'";
auto graphicCopy = m_graphic;
QObject::connect (m_graphicsLayer->graphics(), &Esri::ArcGISRuntime::GraphicListModel::graphicRemoved,
m_graphic, [idx, graphicCopy](int index)
{
if (idx == index)
delete graphicCopy;
});
m_graphicsLayer->graphics()->removeOne(m_graphic);
}
// : Race condition between removeOne() and delete m_graphic
// m_esriSimpleLineSymbol AND m_esriSimpleFillSymbol will be destroyed m_graphic
#endif // ACRGIS_VERSION >= 0x640F00
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
}
Esri::ArcGISRuntime::Graphic *AbstractGraphicalObject::graphic()
{
return m_graphic;
}
Esri::ArcGISRuntime::GraphicsOverlay *AbstractGraphicalObject::graphicsLayer()
{
return m_graphicsLayer;
}
Esri::ArcGISRuntime::Geometry AbstractGraphicalObject::getGraphicGeometry() const
{
if (! m_graphic)
return Esri::ArcGISRuntime::Geometry();
return m_graphic->geometry();
}
bool AbstractGraphicalObject::updateView()
{
if (!changed())
return true;
bool success = updateViewImpl();
resetChanged();
return success;
}
QString AbstractGraphicalObject::debugInfo() const
{
return m_debugInfo;
}
void AbstractGraphicalObject::setDebugInfo(const QString &debugInfo)
{
m_debugInfo = debugInfo;
}
int AbstractGraphicalObject::drawOrder() const
{
return m_drawOrder.value();
}
void AbstractGraphicalObject::setDrawOrder(int drawOrder)
{
m_drawOrder = drawOrder;
// if (m_graphic)
// m_graphic->setDrawOrder(m_drawOrder.value());
}
QString AbstractGraphicalObject::toString() const
{
QString str;
if (!m_debugInfo.isEmpty())
str.append(QStringLiteral("debugInfo=%1").arg(m_debugInfo));
if (m_graphicsLayer)
str.append(QStringLiteral(" layer='%1'").arg(m_graphicsLayer->objectName()));
str.append(QStringLiteral(" m_drawOrder='%1'").arg(m_drawOrder.value()));
if (m_graphic)
str.append(QStringLiteral(" zIndex='%1'").arg(m_graphic->zIndex()));
str.append(QStringLiteral(" visibility='%1'").arg(m_visibility.value()));
str.append(QStringLiteral(" selected='%1'").arg(m_selected.value()));
str.append(QStringLiteral(" scale='%1'").arg(m_scale.value()));
str.append(QStringLiteral(" positions.count='%1'").arg(m_positions.value().count()));
return str;
}
UniqueMapId AbstractGraphicalObject::uniqueMapId() const
{
return m_uniqueMapId;
}
void AbstractGraphicalObject::setUniqueMapId(UniqueMapId uniqueId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
<< " uniqueMapId=" << uniqueId;
m_uniqueMapId = uniqueId;
// use attribute to store application obj id (SimWorld) at graphic
if (m_graphic)
{
// use attributeModel to store application obj id (SimWorld) at graphic
Esri::ArcGISRuntime::AttributeListModel *attListModel = m_graphic->attributes();
if (attListModel)
attListModel->insertAttribute(QLatin1String(SituationMap::UniqueMapIdAttribute), m_uniqueMapId);
else
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'"
<< " uniqueMapId=" << m_uniqueMapId;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
<< " uniqueMapId=" << uniqueId;
}
Point3D AbstractGraphicalObject::origin() const
{
return m_positions.value().value(0); // value => if index is out of range -> default object
}
void AbstractGraphicalObject::setOrigin(const Point3D &origin)
{
// TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
// << " origin=" << origin;
if (m_positions.value().isEmpty())
m_positions.refValue().append(origin);
else
{
// https://stackoverflow.com/a/1573715/2352507
// Any comparison(except with "!=") with NaN returns false.
// NaN != NaN -> true!!!
if (m_positions.value().value(0) != origin) // NaN != NaN -> true!!!
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " value(0) = " << m_positions.value().value(0) << " origin = " << origin;
m_positions.refValue().clear();
m_positions.refValue().append(origin);
}
}
// TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
// << " origin=" << origin
// << " changed=" << m_positions.changed()
// << " SIZE=" << m_positions.value().size();
}
void AbstractGraphicalObject::setOrigin(const QPointF &origin)
{
setOrigin(Point3D(origin.x(), origin.y(), .0));
}
PositionCont AbstractGraphicalObject::positions() const
{
return m_positions.value();
}
void AbstractGraphicalObject::setPositions(const PositionCont &posCont)
{
m_positions = posCont;
// TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
// << " changed=" << m_positions.changed();
}
bool AbstractGraphicalObject::isSinglePoint() const
{
return m_positions.value().count() == 1;
}
bool AbstractGraphicalObject::isMultiPoint() const
{
return m_positions.value().count() > 1;
}
bool AbstractGraphicalObject::isArea() const
{
return m_positions.value().count() > 2;
}
LineStyle AbstractGraphicalObject::lineStyle() const
{
return m_lineStyle.value();
}
LineStyle &AbstractGraphicalObject::rLineStyle()
{
return m_lineStyle.refValue();
}
void AbstractGraphicalObject::setLineStyle(const LineStyle &lineStyle)
{
m_lineStyle = lineStyle;
}
FillStyle AbstractGraphicalObject::fillStyle() const
{
return m_fillStyle.value();
}
FillStyle &AbstractGraphicalObject::rFillStyle()
{
return m_fillStyle.refValue();
}
void AbstractGraphicalObject::setFillStyle(const FillStyle &fillStyle)
{
m_fillStyle = fillStyle;
}
bool AbstractGraphicalObject::visibility() const
{
return m_visibility.value();
}
void AbstractGraphicalObject::setVisibility(bool visibility)
{
m_visibility = visibility;
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " visibility=" << m_visibility;
}
bool AbstractGraphicalObject::selected() const
{
return m_selected.value();
}
void AbstractGraphicalObject::setSelected(bool selected)
{
m_selected = selected;
}
bool AbstractGraphicalObject::pickable() const
{
return m_pickable.value();
}
void AbstractGraphicalObject::setPickable(bool pickable)
{
// allow pickable only if m_uniqueMapId is valid:
m_pickable = pickable && (m_uniqueMapId != INVALID_MAP_ID);
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " pickable=" << m_pickable;
}
float AbstractGraphicalObject::scale() const
{
return m_scale.value();
}
void AbstractGraphicalObject::setScale(float scale)
{
m_scale = scale;
}
bool AbstractGraphicalObject::addUpdateGraphic()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " updateGraphic";
bool successGraphic = true;
if (! m_graphic)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " no m_graphic -> return true";
return true;
}
// append just once :-)
if (! m_graphicsLayer->graphics()->contains(m_graphic))
{
m_graphicsLayer->graphics()->append(m_graphic);
successGraphic = m_graphicsLayer->graphics()->contains(m_graphic);
}
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " successGraphic=" << successGraphic;
return successGraphic;
}
bool AbstractGraphicalObject::create()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
<< " uniqueMapId =" << m_uniqueMapId
<< " origin =" << this->origin()
<< " visibility=" << m_visibility;
bool success = true;
// some checks:
if (!m_graphicsLayer)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " no graphicsLayer";
return false;
}
if (!m_graphic)
{
m_graphic = new Esri::ArcGISRuntime::Graphic();
m_graphic->setObjectName(m_debugInfo);
m_graphic->setZIndex(m_drawOrder.value());
// use attributeModel to store application obj id (SimWorld) at graphic
Esri::ArcGISRuntime::AttributeListModel *attLisModel = m_graphic->attributes();
if (attLisModel)
attLisModel->insertAttribute(QLatin1String(SituationMap::UniqueMapIdAttribute), m_uniqueMapId);
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'"
<< " uniqueMapId=" << m_uniqueMapId;
}
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
<< " success=" << success;
return success;
}
bool AbstractGraphicalObject::updateViewImpl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
<< " uniqueMapId=" << m_uniqueMapId
<< " origin=" << this->origin()
<< " visibility=" << m_visibility
<< " selected=" << m_selected
<< " drawOrder=" << m_drawOrder
<< " pickable=" << m_pickable
<< " pickableCHG=" << m_pickable.changed();
if (QApplication::instance()->thread()->currentThreadId() != QThread::currentThreadId())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " wrong Thread, debugInfo='" << m_debugInfo << "'"
<< " uniqueMapId=" << m_uniqueMapId;
abort();
}
if (m_graphic)
{
m_graphic->setZIndex(m_drawOrder.value());
m_graphic->setVisible(m_visibility.value());
m_graphic->setSelected(m_selected.value());
// Picking:
if (m_pickable.changed())
{
// use attributeModel to store m_pickable at graphic
Esri::ArcGISRuntime::AttributeListModel *attLisModel = m_graphic->attributes();
if (attLisModel)
attLisModel->insertAttribute(QLatin1String(SituationMap::IsPickableAttribute), m_pickable.value());
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'"
<< " uniqueMapId=" << m_uniqueMapId;
}
}
m_pickable.reset();
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
<< " uniqueMapId =" << m_uniqueMapId;
return true;
}
bool AbstractGraphicalObject::assignLineStyleToGraphic()
{
if (!m_graphic)
return false;
const LineStyle &ls = m_lineStyle.value();
if (!m_esriSimpleLineSymbol)
{
m_esriSimpleLineSymbol =
new Esri::ArcGISRuntime::SimpleLineSymbol(convert(ls.linePattern()), ls.lineColor(), ls.lineWidth() * m_scale.value(), m_graphic);
} else {
m_esriSimpleLineSymbol->setStyle(convert(ls.linePattern()));
m_esriSimpleLineSymbol->setColor(ls.lineColor());
m_esriSimpleLineSymbol->setWidth(ls.lineWidth() * m_scale.value());
}
m_graphic->setSymbol(m_esriSimpleLineSymbol.data());
return true;
}
bool AbstractGraphicalObject::assignFillStyleToGraphic()
{
if (!m_graphic)
return false;
const LineStyle &ls = m_lineStyle.value();
const FillStyle &fs = m_fillStyle.value();
// 1. the Line
if (!m_esriSimpleLineSymbol)
{
m_esriSimpleLineSymbol =
new Esri::ArcGISRuntime::SimpleLineSymbol(convert(ls.linePattern()), ls.lineColor(), ls.lineWidth() * m_scale.value(), m_graphic);
} else {
m_esriSimpleLineSymbol->setStyle(convert(ls.linePattern()));
m_esriSimpleLineSymbol->setColor(ls.lineColor());
m_esriSimpleLineSymbol->setWidth(ls.lineWidth() * m_scale.value());
}
// 1. the Fill
if (!m_esriSimpleFillSymbol)
{
m_esriSimpleFillSymbol =
new Esri::ArcGISRuntime::SimpleFillSymbol(convert(fs.fillPattern()), fs.fillColor(), m_esriSimpleLineSymbol, m_graphic);
} else {
m_esriSimpleFillSymbol->setStyle(convert(fs.fillPattern()));
m_esriSimpleFillSymbol->setColor(fs.fillColor());
m_esriSimpleFillSymbol->setOutline(m_esriSimpleLineSymbol);
}
m_graphic->setSymbol(m_esriSimpleFillSymbol.data());
return true;
}
Esri::ArcGISRuntime::SimpleLineSymbolStyle AbstractGraphicalObject::convert(const LinePattern linePattern)
{
switch (linePattern)
{
case LinePattern::Dash: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Dash;
case LinePattern::DashDot: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::DashDot;
case LinePattern::DashDotDot: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::DashDotDot;
case LinePattern::Dot: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Dot;
case LinePattern::Null: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Null;
case LinePattern::Solid: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Solid;
} // switch
return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Solid;
}
Esri::ArcGISRuntime::SimpleFillSymbolStyle AbstractGraphicalObject::convert(const FillPattern fillPattern)
{
switch (fillPattern)
{
case FillPattern::BackwardDiagonal: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::BackwardDiagonal;
case FillPattern::Cross: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Cross;
case FillPattern::DiagonalCross: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::DiagonalCross;
case FillPattern::ForwardDiagonal: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::ForwardDiagonal;
case FillPattern::Horizontal: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Horizontal;
case FillPattern::Null: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Null;
case FillPattern::Solid: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Solid;
case FillPattern::Vertical: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Vertical;
} // switch
return Esri::ArcGISRuntime::SimpleFillSymbolStyle::BackwardDiagonal;
}
int AbstractGraphicalObject::countOfPolygonFirstPart(const Esri::ArcGISRuntime::Multipart &polylinePolygon)
{
if (polylinePolygon.isEmpty() || polylinePolygon.parts().isEmpty())
return -1;
return polylinePolygon.parts().part(0).pointCount();
}
const Esri::ArcGISRuntime::SpatialReference AbstractGraphicalObject::spatialReference() const
{
return m_geoView->spatialReference();
}
} // namespace SituationMap
@@ -0,0 +1,213 @@
/**
* @RDE_HEADER@
* AbstractGraphicalObject
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Own
#include <Map/situation_map_types.h>
#include <Map/line_style.h>
#include <Map/fill_style.h>
#include <Common/simple_value.h>
#include <Common/situation_map_logging.h>
// ESRI
#include <arcgis/SimpleLineSymbol.h>
#include <arcgis/SimpleFillSymbol.h>
// Qt
#include <QPointer>
// forward:
namespace Esri
{
namespace ArcGISRuntime
{
class GeoView;
class Graphic;
class GraphicsOverlay;
class Geometry;
class Multipart;
class SpatialReference;
}
}
//----------------------------------------------------------------------------
namespace SituationMap
{
//forward
class GraphicalObjectText;
class SITUATIONMAP_EXPORT AbstractGraphicalObject
{
public:
AbstractGraphicalObject(const Esri::ArcGISRuntime::GeoView *geoView
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
, const QString &debugInfo
, const UniqueMapId &uniqueMapId);
virtual ~AbstractGraphicalObject();
AbstractGraphicalObject(const AbstractGraphicalObject &other) = delete;
AbstractGraphicalObject &operator=(AbstractGraphicalObject &other) = delete;
virtual Esri::ArcGISRuntime::Graphic *graphic();
virtual Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer();
virtual QString toString() const;
virtual UniqueMapId uniqueMapId() const;
virtual void setUniqueMapId(UniqueMapId uniqueId);
virtual QString debugInfo() const;
virtual void setDebugInfo(const QString &debugInfo);
virtual int drawOrder() const;
virtual void setDrawOrder(int drawOrder);
// Data access:
// for SinglePoint:
virtual Point3D origin() const;
virtual void setOrigin(const Point3D &origin);
virtual void setOrigin(const QPointF &origin); // ToDO accept this??
// for MultiPoint:
virtual PositionCont positions() const;
virtual void setPositions(const PositionCont &posCont);
virtual bool isSinglePoint() const;
virtual bool isMultiPoint() const;
virtual bool isArea() const;
virtual LineStyle lineStyle() const;
virtual LineStyle &rLineStyle();
/**
* @brief setLineStyle (Font-)size is limited to 500.
* (High values can lead to coredump with 'SymbolDrawHelper::create_line_image FAILED, SkBitmap is NULL or empty')
* @param lineStyle to set.
*/
virtual void setLineStyle(const LineStyle &lineStyle);
virtual FillStyle fillStyle() const;
virtual FillStyle &rFillStyle();
virtual void setFillStyle(const FillStyle &fillStyle);
// Scale :
virtual float scale() const;
virtual void setScale(float scale);
// : Scale
// Visibility :
virtual bool visibility() const;
virtual void setVisibility(bool visibility);
// : Visibility
// Selection, Picking :
bool selected() const;
void setSelected(bool selected);
bool pickable() const;
/**
* @brief setPickable The method allows pickable=true only if uniqueMapIdis valid.
* @param pickable new value.
*/
void setPickable(bool pickable);
// : Selection, Picking
virtual Esri::ArcGISRuntime::Geometry getGraphicGeometry() const;
bool updateView();
bool addUpdateGraphic();
static Esri::ArcGISRuntime::SimpleLineSymbolStyle convert(const LinePattern linePattern);
static Esri::ArcGISRuntime::SimpleFillSymbolStyle convert(const FillPattern fillPattern);
bool assignLineStyleToGraphic();
bool assignFillStyleToGraphic();
static int countOfPolygonFirstPart(const Esri::ArcGISRuntime::Multipart &polylinePolygon);
protected:
// Internal/Admin
const Esri::ArcGISRuntime::SpatialReference spatialReference() const;
virtual bool changed()
{
return m_drawOrder.changed()
|| m_positions.changed()
|| m_visibility.changed()
|| m_selected.changed()
|| m_pickable.changed()
|| m_scale.changed()
|| m_lineStyle.changed()
|| m_fillStyle.changed();
}
virtual bool updateViewImpl() = 0;
virtual void resetChanged()
{
m_drawOrder.reset();
m_positions.reset();
m_visibility.reset();
m_selected.reset();
m_pickable.reset();
m_scale.reset();
m_lineStyle.reset();
m_fillStyle.reset();
}
virtual bool create() = 0;
const Esri::ArcGISRuntime::GeoView *m_geoView = nullptr;
Esri::ArcGISRuntime::GraphicsOverlay *m_graphicsLayer = nullptr;
Esri::ArcGISRuntime::Graphic *m_graphic = nullptr;
SimpleValue<int> m_drawOrder = 0;
// Data
UniqueMapId m_uniqueMapId;
QString m_debugInfo; ///< for debugging
SimpleValue<PositionCont> m_positions;
SimpleValue<bool> m_visibility = true;
SimpleValue<bool> m_selected = false;
SimpleValue<bool> m_pickable = true;
SimpleValue<float> m_scale = 1.0;
SimpleValue<LineStyle> m_lineStyle;
SimpleValue<FillStyle> m_fillStyle;
QPointer<Esri::ArcGISRuntime::SimpleLineSymbol> m_esriSimpleLineSymbol = nullptr;
QPointer<Esri::ArcGISRuntime::SimpleFillSymbol> m_esriSimpleFillSymbol = nullptr;
private:
LOGGER_T m_logger; ///< Interface of the Logging-Facility
};
} // namespace SituationMap
@@ -0,0 +1,96 @@
/**
* @RDE_HEADER@
* EllipseParameters
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "ellipse_parameters.h"
// ESRI
// Qt
#include <QString>
namespace SituationMap
{
float EllipseParameters::lengthX() const
{
return m_lengthX;
}
void EllipseParameters::setLengthX(float lengthX)
{
m_lengthX = lengthX;
}
float EllipseParameters::lengthY() const
{
return m_lengthY;
}
void EllipseParameters::setLengthY(float lengthY)
{
m_lengthY = lengthY;
}
float EllipseParameters::directionDegree() const
{
return m_directionDegree;
}
void EllipseParameters::setDirectionDegree(float directionDegree)
{
m_directionDegree = directionDegree;
}
int EllipseParameters::maxSegmentLength() const
{
return m_maxSegmentLength;
}
void EllipseParameters::setMaxSegmentLength(int value)
{
m_maxSegmentLength = value;
}
int EllipseParameters::maxPointCount() const
{
return m_maxPointCount;
}
void EllipseParameters::setMaxPointCount(int maxPointCount)
{
m_maxPointCount = maxPointCount;
}
bool EllipseParameters::isValid() const
{
return ((m_lengthX > 0) && (m_lengthY > 0)) ;
}
//-----------------------------------------------------------------------------
// output operator:
//-----------------------------------------------------------------------------
std::ostream &operator<< (std::ostream &stream,
const EllipseParameters &value)
{
QString str;
str.append(QStringLiteral(" lengthX=%1").arg(value.lengthX()));
str.append(QStringLiteral(" lengthY=%1").arg(value.lengthY()));
str.append(QStringLiteral(" directionDegree=%1").arg(value.directionDegree()));
str.append(QStringLiteral(" maxSegmentLength=%1").arg(value.maxSegmentLength()));
stream << str.toStdString();
return stream;
}
} // namespace SituationMap
@@ -0,0 +1,95 @@
/**
* @RDE_HEADER@
* EllipseParameters
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Own
#include <situation_map_export.h>
#include <ostream>
// Qt
//----------------------------------------------------------------------------
namespace SituationMap
{
//----------------------------------------------------------------------------
class SITUATIONMAP_EXPORT EllipseParameters
{
public:
static constexpr unsigned int MAX_POINT_COUNT_DEFAULT = 30;
EllipseParameters() = default;
float lengthX() const;
void setLengthX(float lengthX);
float lengthY() const;
void setLengthY(float lengthY);
float directionDegree() const;
void setDirectionDegree(float directionDegree);
int maxSegmentLength() const;
void setMaxSegmentLength(int value);
int maxPointCount() const;
void setMaxPointCount(int maxPointCount);
bool isValid() const;
/**
* @brief operator== Compare two objects
* @param other to be compared with
* @return true if identical, otherwise false.
*/
bool operator==(const EllipseParameters &other) const
{
return ((this->m_lengthX == other.m_lengthX) &&
(this->m_lengthY == other.m_lengthY) &&
(this->m_directionDegree == other.m_directionDegree) &&
(this->m_maxSegmentLength == other.m_maxSegmentLength) &&
(this->m_maxPointCount == other.m_maxPointCount)
);
}
/**
* @brief operator!= Compare two objects
* @param other to be compared with
* @return true if NOT identical, otherwise false.
*/
bool operator!=(const EllipseParameters &other) const
{
return !(*this == other);
}
private:
float m_lengthX = 0;
float m_lengthY = 0;
float m_directionDegree = 0;
int m_maxSegmentLength = 10; // meter
int m_maxPointCount = MAX_POINT_COUNT_DEFAULT;
};
//-----------------------------------------------------------------------------
// output operator:
//-----------------------------------------------------------------------------
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
const EllipseParameters &value);
} // namespace SituationMap
@@ -0,0 +1,190 @@
/**
* @RDE_HEADER@
* GraphicalObjectAttributes
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "graphical_object_attributes.h"
#include <MapImpl/map_impl.h>
#include <Map/situation_map_utils.h> // operator<<
#include <Common/simple_value.h>
// ESRI
#include <arcgis/Map.h>
#include <arcgis/GraphicsOverlay.h>
// Qt
namespace SituationMap
{
class GraphicalObjectAttributes::Private
{
public:
Private() = default;
~Private() = default;
// ESRI data:
MapImpl *m_mapImpl = nullptr;
QString m_logicalLayerName;
// OWN data:
SimpleValue<QVariantMap> m_attributes;
}; // class GraphicalObjectAttributes::Private
//-----------------------------------------------------------------------------
GraphicalObjectAttributes::GraphicalObjectAttributes(MapImpl *mapImpl,
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer,
const QString &debugInfo,
const UniqueMapId &uniqueMapId)
: BaseClass(mapImpl->getEsriGeoView(), graphicsLayer, debugInfo, uniqueMapId),
m_logger(getLogger("GraphicalObjectAttributes")),
d(new Private)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
}
GraphicalObjectAttributes::~GraphicalObjectAttributes()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
delete d;
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
}
bool GraphicalObjectAttributes::create()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
<< " m_visibility = " << m_visibility;
bool success = BaseClass::create();
if (!success)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " create failed";
return false;
}
bool successGraphic = addUpdateGraphic(); // CHECK
if (!successGraphic)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " addUpdateGraphic failed, debugInfo='" << m_debugInfo << "'" << " uniqueMapId=" << m_uniqueMapId;
return false;
}
// real work:
// empty
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
return success;
}
QVariantMap GraphicalObjectAttributes::attributes() const
{
return d->m_attributes.value();
}
void GraphicalObjectAttributes::setAttributes(const QVariantMap &attributes)
{
d->m_attributes = attributes;
}
bool GraphicalObjectAttributes::changed()
{
return BaseClass::changed()
|| d->m_attributes.changed();
}
void GraphicalObjectAttributes::resetChanged()
{
BaseClass::resetChanged();
d->m_attributes.reset();
}
Esri::ArcGISRuntime::Geometry GraphicalObjectAttributes::getGraphicGeometry() const
{
if (m_graphic) return m_graphic->geometry();
ERROR_LOG(m_logger) << LOGFUNCTION << "Geometry is undefined";
return Esri::ArcGISRuntime::Geometry();
} // Esri::ArcGISRuntime::Geometry GraphicalObjectAttributes::getGraphicGeometry() const
bool GraphicalObjectAttributes::updateViewImpl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
<< " visibility=" << m_visibility
<< " selected=" << m_selected
<< " origin=" << this->origin()
<< " scale=" << m_scale.value();
bool success = create();
if (!success)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " create failed";
return false;
}
if (!BaseClass::updateViewImpl())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " updateView failed";
return false;
}
// real work:
if (m_positions.changed())
{
const PositionCont &posCont = m_positions.value();
if (posCont.size() == 1)
{
const Point3D &origin = this->origin();
Esri::ArcGISRuntime::Point originGeometry(origin.x(),
origin.y(),
origin.z(),
spatialReference());
m_graphic->setGeometry(originGeometry);
}
}
if (d->m_attributes.changed())
{
QVariantMap rawAttributes = d->m_attributes.value();
// add basics:
rawAttributes[QLatin1String(SituationMap::UniqueMapIdAttribute)] = m_uniqueMapId;
rawAttributes[QLatin1String(SituationMap::IsPickableAttribute)] = m_pickable.value();
m_graphic->attributes()->setAttributesMap(rawAttributes);
if (m_logger.isDebugEnabled())
qCritical() << " XXXXX set rawAttributes " << rawAttributes;
}
if (m_graphic)
{
m_graphic->setZIndex(m_drawOrder.value());
m_graphic->setVisible(m_visibility.value());
m_graphic->setSelected(m_selected.value());
}
if (!success)
ERROR_LOG(m_logger) << LOGFUNCTION << " failure, debugInfo='" << m_debugInfo << "'";
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
<< " success = " << success
<< " visibility=" << m_visibility;
return success;
}
} // namespace SituationMap
@@ -0,0 +1,88 @@
/**
* @RDE_HEADER@
* GraphicalObjectAttributes
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Own
#include "abstract_graphical_object.h"
// Esri
// Qt
// forward:
//----------------------------------------------------------------------------
namespace SituationMap
{
// forward:
class MapImpl;
/**
* @brief The GraphicalObjectAttributes class
*/
class SITUATIONMAP_EXPORT GraphicalObjectAttributes : public AbstractGraphicalObject
{
using BaseClass = AbstractGraphicalObject;
public:
/**
* @brief GraphicalObjectAttributes
* @param mapImpl map to be used.
* @param logicalLayerName logical layer name to be used.
* @param debugInfo debugInfo to be used
* @param uniqueMapId uniqueMapId to be used. (Optional to fulfill rubberband requirements)
*/
GraphicalObjectAttributes(MapImpl *mapImpl,
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer,
const QString &debugInfo,
const UniqueMapId &uniqueMapId = INVALID_MAP_ID);
GraphicalObjectAttributes(const GraphicalObjectAttributes &other) = delete;
GraphicalObjectAttributes &operator=(GraphicalObjectAttributes &other) = delete;
virtual ~GraphicalObjectAttributes();
QVariantMap attributes() const;
void setAttributes(const QVariantMap &attributes);
Esri::ArcGISRuntime::Geometry getGraphicGeometry() const override;
protected:
// Internal/Admin
virtual bool create() override;
bool changed() override;
void resetChanged() override;
bool updateViewImpl() override;
// logical
private:
LOGGER_T m_logger; ///< Interface of the Logging-Facility
class Private;
/**
* The private d-pointer to not break BC when changing internals of this class
*/
Private *d = nullptr;
};
} // namespace SituationMap
@@ -0,0 +1,162 @@
/**
* @RDE_HEADER@
* GraphicalObjectCube
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "graphical_object_cube.h"
#include <Map/situation_map_utils.h> // operator<<
// ESRI
#include <arcgis/GraphicsOverlay.h>
#include <arcgis/PolygonBuilder.h>
// Qt
namespace SituationMap
{
GraphicalObjectCube::GraphicalObjectCube(const Esri::ArcGISRuntime::GeoView *geoView
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
, const QString &debugInfo
, const UniqueMapId &uniqueMapId)
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
, m_logger(getLogger("GraphicalObjectCube"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
}
GraphicalObjectCube::~GraphicalObjectCube()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
}
bool GraphicalObjectCube::create()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
bool success = BaseClass::create();
if (!success)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " create failed";
}
// real work:
// empty
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
// << " drawOrder = " << m_graphic->drawOrder()
<< " success = " << success;
return success;
}
bool GraphicalObjectCube::updateViewImpl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
// some checks:
if (!this->isArea())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " incorrect number of positions"
<< " (" << this->positions().count() << ")";
return false;
}
if (!create())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " create failed";
return false;
}
if (!BaseClass::updateViewImpl())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " updateView failed";
return false;
}
// real work:
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'";
// Attribute 'height':
QVariantMap attMap = m_graphic->attributes()->attributesMap();
attMap[QStringLiteral("height")] = QVariant(m_height.value());
//
// Attribute 'PartyName' is replaced by Attribute 'Extrusion_Color' to be more flexible
//
// Attribute 'Extrusion_Color':
if (m_extrusionColorName.value().isEmpty())
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " debugInfo='" << m_debugInfo << "'"
<< " m_extrusionColorName is empty";
// -> time for the defaultSymbol of the Renderer
attMap[QStringLiteral("Extrusion_Color")] = QStringLiteral("DOES_NOT_EXIST");
}
else
attMap[QStringLiteral("Extrusion_Color")] = QVariant(m_extrusionColorName.value());
m_graphic->attributes()->setAttributesMap(attMap);
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " attributesMap[height] ='" << attMap[QStringLiteral("height")].toDouble() << "'";
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " attributesMap[Extrusion_Color] ='" << attMap[QStringLiteral("Extrusion_Color")].toString() << "'";
// geometry:
Esri::ArcGISRuntime::PolygonBuilder builder(spatialReference());
const PositionCont &posCont = m_positions.value();
for (const Point3D &pos : posCont)
{
builder.addPoint(pos.x(), pos.y());
}
if (! builder.isSketchValid())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
<< " builder -> sketch invalid";
return false;
}
m_graphic->setGeometry(builder.toGeometry());
// add
bool successGraphic = addUpdateGraphic();
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
<< " drawOrder = " << m_graphic->zIndex();
return successGraphic;
}
//-----------------------------------------------------------------------------
// output operator:
//-----------------------------------------------------------------------------
std::ostream &operator<<(std::ostream &stream,
const GraphicalObjectCube &value)
{
stream << value.toString();
return stream;
}
} // namespace SituationMap
Loaded 100 of 16245 files, more files were not shown because too many files have changed in this diff. Show more