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

@@ -0,0 +1,38 @@
#
# monitoring of the target areas
# $Id$
# $HeadURL$
# $Author$
#
SET(SRCS
plugin.cpp
plugin.h
ces_building_model.cpp
ces_building_model.h
handler_building_ownership.cpp
handler_building_ownership.h
handler_building_model.cpp
handler_building_model.h
handler_aes_data.cpp
handler_aes_data.h
handler_contamination.cpp
handler_contamination.h
# logger.cpp
# logger.h
)
NGL_ADD_LIBRARY(AAR SV cesPluginCesBuildings MODULE ${SRCS})
NGL_TARGET_LINK_LIBRARIES(cesPluginCesBuildings
PUBLIC
Qt5::Network
Qt5::Widgets
LtsCoordinate
cesPluginInterface
ngldb
svcCesDDSCommon
# ProjectConfig
)
NGL_INSTALL_TARGET(cesPluginCesBuildings)
@@ -0,0 +1,378 @@
/**
* Building Model
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, ESZS, 2016-04-14
*/
#include "ces_building_model.h"
#include <Buildings/BuildingControlUnit/VWM/vwm_xml_reader.h>
#include <Buildings/BuildingControlUnit/VWM/vwm_math.h>
#include <LtsUtilsCore/dds_vector.h>
#include <float.h>
#include <QLineF>
#include <QDebug>
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
bool intersects(const QLineF &line1, const QLineF &line2)
{
const QPointF a = line1.p2() - line1.p1();
const QPointF b = line2.p1() - line2.p2();
const QPointF c = line1.p1() - line2.p1();
const qreal denominator = a.y() * b.x() - a.x() * b.y();
if (denominator == 0 || !std::isfinite(denominator))
return false;
const qreal reciprocal = 1 / denominator;
const qreal na = (b.y() * c.x() - b.x() * c.y()) * reciprocal;
if (na < 0 || na > 1)
return false;
const qreal nb = (a.x() * c.y() - a.y() * c.x()) * reciprocal;
if (nb < 0 || nb > 1)
return false;
return true;
}
#endif
namespace CesBuildings
{
/*************************************************************************************************
* Static methods *
*************************************************************************************************/
bool BuildingModel::isValid(const LtsUtils::QPoint3D &point)
{
return point != invalidPosition();
}
bool BuildingModel::isValid(const Core::GeoPosition &point)
{
return !qFuzzyIsNull(point.lon()) && !qFuzzyIsNull(point.lat()) && point.z() > invalidGeoPosition().z();
}
LtsUtils::QPoint3D BuildingModel::invalidPosition()
{
return BuildingControlUnit::VWM::Math::invalidPosition();
}
Core::GeoPosition BuildingModel::invalidGeoPosition()
{
return Core::GeoPosition(0., 0., -10000.);
}
/*************************************************************************************************
* Ctor, dtor and init *
*************************************************************************************************/
BuildingModel::BuildingModel(QObject *parent)
: QObject(parent)
, BuildingControlUnit::VWM::Building()
, m_logger(CentralEffectSimulation::getLogger(QStringLiteral("BuildingModel")))
{
}
BuildingModel::~BuildingModel()
{
}
bool BuildingModel::init(
const InfrastructureManagement::MainFootprint &mfp, const InfrastructureManagement::MainStructureElement &mse,
const QByteArray &vmd,
const int buildingId
)
{
m_buildingId = buildingId;
TRACE_LOG(m_logger) << LOGFUNCTION << " START, m_buildingId=" << m_buildingId;
m_angle = mse.angle() * M_PI / 180.;
m_refPosGeo = mse.geoPosition();
m_refPosUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(mse.geoPosition().lon(), mse.geoPosition().lat());
m_refPos = {m_refPosUtm.x, m_refPosUtm.y, m_refPosGeo.z()};
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, m_buildingId=" << m_buildingId
<< ", m_angle=" << m_angle
<< ", m_refPosGeo=" << m_refPosGeo
<< ", m_refPos=" << m_refPos;
for (const InfrastructureManagement::FootprintElement &footprintElement : qAsConst(mfp.elements()))
m_footprint << QPointF(footprintElement.relPosition().offsetX(), footprintElement.relPosition().offsetY());
if (m_footprint.isEmpty())
{
ERROR_LOG(m_logger) << "Error reading MainFootprint for building " << m_buildingId;
return false;
} // if
m_boundingRect = m_footprint.boundingRect();
// const std::vector<uint8_t> &data = vmd.vulnerabilityData();
// QByteArray array = qUncompress(QByteArray::fromRawData(reinterpret_cast<const char*>(&data[0]), data.size()));
if (!BuildingControlUnit::VWM::XmlReader::readBuilding(vmd, *this))
{
ERROR_LOG(m_logger) << "Error reading VulnerabilityModelData for building " << m_buildingId;
return false;
} // if
m_height = DBL_MIN;
const QMap<int, BuildingControlUnit::VWM::Room> &roomMap = rooms();
for (const BuildingControlUnit::VWM::Room &room : qAsConst(roomMap))
for (const BuildingControlUnit::VWM::OuterWall &outerWall : qAsConst(room.outerWalls()))
for (const BuildingControlUnit::VWM::WallElement &wallElement : qAsConst(outerWall.elements()))
for (const LtsUtils::QPoint3D &point : qAsConst(wallElement))
if (point.z() > m_height)
m_height = point.z();
TRACE_LOG(m_logger) << LOGFUNCTION << " END, m_buildingId=" << m_buildingId;
return true;
}
/*************************************************************************************************
* Intersection calculations *
*************************************************************************************************/
bool BuildingModel::hasIntersectionSimplified(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end) const
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_buildingId=" << m_buildingId
<< ", start=" << start << ", end=" << end;
// keep origin of QRect (topLeft) in mind:
static const QLineF topLine = QLineF(m_boundingRect.topRight(), m_boundingRect.topLeft());
static const QLineF leftLine = QLineF(m_boundingRect.topLeft(), m_boundingRect.bottomLeft());
static const QLineF bottomLine = QLineF(m_boundingRect.bottomLeft(), m_boundingRect.bottomRight());
static const QLineF rightLine = QLineF(m_boundingRect.bottomRight(), m_boundingRect.topRight());
// qCritical() << " topLine" << topLine;
// qCritical() << " leftLine" << leftLine;
// qCritical() << " bottomLine" << bottomLine;
// qCritical() << " rightLine" << rightLine;
// qCritical() << " start.z()" << start.z();
// qCritical() << " end.z()" << end.z();
// qCritical() << " m_height" << m_height;
// over the building?
if (start.z() > m_height && end.z() > m_height)
return false;
const QPointF start2D(start.x(), start.y());
const QPointF end2D(end.x(), end.y());
const QLineF startToEnd = QLineF(start2D, end2D);
// qCritical() << " startToEnd" << startToEnd;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QPointF dummy;
if (startToEnd.intersects(topLine, &dummy) != QLineF::BoundedIntersection &&
startToEnd.intersects(leftLine, &dummy) != QLineF::BoundedIntersection &&
startToEnd.intersects(bottomLine, &dummy) != QLineF::BoundedIntersection &&
startToEnd.intersects(rightLine, &dummy) != QLineF::BoundedIntersection &&
!m_boundingRect.contains(start2D) && !m_boundingRect.contains(end2D))
#else
if (!intersects(startToEnd, topLine) && !intersects(startToEnd, leftLine) &&
!intersects(startToEnd, bottomLine) && !intersects(startToEnd, rightLine) &&
!m_boundingRect.contains(start2D) && !m_boundingRect.contains(end2D))
#endif
return false;
// qCritical() << " intersects done";
QPolygonF poly;
poly << start2D;
poly << end2D;
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
if (!m_footprint.intersects(poly))
#else
if (m_footprint.intersected(poly).isEmpty())
#endif
return false;
// qCritical() << " hasIntersectionSimplified -> return true";
return true;
}
bool BuildingModel::hasIntersectionSimplified(const Core::GeoPosition &start, const Core::GeoPosition &end) const
{
return hasIntersectionSimplified(fromGeographic(start), fromGeographic(end));
}
bool BuildingModel::hasIntersectionSimplified(const QVector<LtsUtils::QPoint3D> &trajectory) const
{
for (int i = 1; i < trajectory.size(); ++i)
if (hasIntersectionSimplified(trajectory[i - 1], trajectory[i]))
return true;
return false;
}
bool BuildingModel::hasIntersectionSimplified(const std::vector<Core::GeoPosition> &trajectory) const
{
for (unsigned int i = 1; i < trajectory.size(); ++i)
if (hasIntersectionSimplified(trajectory[i - 1], trajectory[i]))
return true;
return false;
}
bool BuildingModel::hasIntersection(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end) const
{
if (!hasIntersectionSimplified(start, end))
return false;
bool bHasIntersection = BuildingControlUnit::VWM::Math::hasIntersection(start, end, rooms());
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_buildingId=" << m_buildingId
<< ", start=" << start << ", end=" << end
<< ", rooms().size()" << rooms().size()
<< ", bHasIntersection=" << bHasIntersection;
return bHasIntersection;
}
bool BuildingModel::hasIntersection(const Core::GeoPosition &start, const Core::GeoPosition &end) const
{
return hasIntersection(fromGeographic(start), fromGeographic(end));
}
bool BuildingModel::hasIntersection(const QVector<LtsUtils::QPoint3D> &trajectory) const
{
for (int i = 1; i < trajectory.size(); ++i)
if (hasIntersection(trajectory[i - 1], trajectory[i]))
return true;
return false;
}
bool BuildingModel::hasIntersection(const std::vector<Core::GeoPosition> &trajectory) const
{
for (unsigned int i = 1; i < trajectory.size(); ++i)
if (hasIntersection(trajectory[i - 1], trajectory[i]))
return true;
return false;
}
Core::GeoPosition BuildingModel::intersection(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end) const
{
const LtsUtils::QPoint3D point = BuildingControlUnit::VWM::Math::intersection(start, end, rooms());
return !isValid(point) ? invalidGeoPosition() : toGeographic(point);
}
Core::GeoPosition BuildingModel::intersection(const Core::GeoPosition &start, const Core::GeoPosition &end) const
{
return intersection(fromGeographic(start), fromGeographic(end));
}
Core::GeoPosition BuildingModel::intersection(const QVector<LtsUtils::QPoint3D> &trajectory) const
{
for (int i = 1; i < trajectory.size(); ++i)
{
Core::GeoPosition pos = intersection(trajectory[i - 1], trajectory[i]);
if (!isValid(pos))
continue;
return pos;
} // for
return {};
}
Core::GeoPosition BuildingModel::intersection(const std::vector<Core::GeoPosition> &trajectory) const
{
for (unsigned int i = 1; i < trajectory.size(); ++i)
{
Core::GeoPosition pos = intersection(fromGeographic(trajectory[i - 1]), fromGeographic(trajectory[i]));
if (!isValid(pos))
continue;
return pos;
} // for
return {};
}
/*************************************************************************************************
* Coordinate transformations *
*************************************************************************************************/
LtsUtils::QPoint3D BuildingModel::fromGeographic(const Core::GeoPosition &point) const
{
// qCritical() << " point.z = " << point.z();
// qCritical() << " m_refPos = " << m_refPos.x() << " - " << m_refPos.y() << " - " << m_refPos.z();
const LtsCoordTrans::UtmCoordinate utm = LtsCoordTrans::UtmCoordinate::fromGeographic(point.lon(), point.lat());
// qCritical() << " utm = " << utm.mgrs(7);
return toReference({utm.x, utm.y, point.z()});
}
QVector<LtsUtils::QPoint3D> BuildingModel::fromGeographic(const std::vector<Core::GeoPosition> &points) const
{
QVector<LtsUtils::QPoint3D> ret;
ret.reserve(points.size());
for (const Core::GeoPosition &point : qAsConst(points))
ret.append(fromGeographic(point));
return ret;
}
Core::GeoPosition BuildingModel::toGeographic(const LtsUtils::QPoint3D &point) const
{
const QPointF geoPos2D = m_refPosUtm.geographic(point.rotated(m_angle, LtsUtils::QPoint3D::Axis::Z).toPointF());
return Core::GeoPosition(geoPos2D.x(), geoPos2D.y(), point.z() + m_refPos.z());
}
std::vector<Core::GeoPosition> BuildingModel::toGeographic(const QVector<LtsUtils::QPoint3D> &points) const
{
std::vector<Core::GeoPosition> ret;
ret.reserve(points.size());
for (const LtsUtils::QPoint3D &point : qAsConst(points))
ret.push_back(toGeographic(point));
return ret;
}
LtsUtils::QPoint3D BuildingModel::fromReference(const LtsUtils::QPoint3D &point) const
{
return point.rotated(m_angle, LtsUtils::QPoint3D::Axis::Z) + m_refPos;
}
QVector<LtsUtils::QPoint3D> BuildingModel::fromReference(const QVector<LtsUtils::QPoint3D> &points) const
{
QVector<LtsUtils::QPoint3D> ret;
ret.reserve(points.size());
for (const LtsUtils::QPoint3D &point : qAsConst(points))
ret.append(fromReference(point));
return ret;
}
LtsUtils::QPoint3D BuildingModel::toReference(const LtsUtils::QPoint3D &point) const
{
return (point - m_refPos).rotated(-m_angle, LtsUtils::QPoint3D::Axis::Z);
}
QVector<LtsUtils::QPoint3D> BuildingModel::toReference(const QVector<LtsUtils::QPoint3D> &points) const
{
QVector<LtsUtils::QPoint3D> ret;
ret.reserve(points.size());
for (const LtsUtils::QPoint3D &point : qAsConst(points))
ret.append(toReference(point));
return ret;
}
/*************************************************************************************************
* Overloaded operators *
*************************************************************************************************/
bool BuildingModel::operator ==(const BuildingModel &other) const
{
return m_buildingId == other.m_buildingId;
}
bool BuildingModel::operator !=(const BuildingModel &other) const
{
return m_buildingId != other.m_buildingId;
}
} // namespace CesBuildings
@@ -0,0 +1,99 @@
/**
* Building Model
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, ESZS, 2016-04-14
*/
#pragma once
#include <CentralEffectSimulation/logger.h>
#include <Buildings/BuildingControlUnit/VWM/vwm_building.h>
#include <InfrastructureManagement/ism.hpp>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <QObject>
#include <QPolygonF>
using namespace CentralEffectSimulation;
namespace CesBuildings
{
///////////////////////////////////////////////////////////////////////////////////////////////////
// BuildingModel
//
class BuildingModel
: public QObject
, public BuildingControlUnit::VWM::Building
{
Q_OBJECT
public:
static bool isValid(const LtsUtils::QPoint3D &point);
static bool isValid(const Core::GeoPosition &point);
static LtsUtils::QPoint3D invalidPosition();
static Core::GeoPosition invalidGeoPosition();
explicit BuildingModel(QObject *parent = nullptr);
~BuildingModel();
bool init(const InfrastructureManagement::MainFootprint &mfp, const InfrastructureManagement::MainStructureElement &mse,
const QByteArray &vmd,
const int buildingId);
bool hasIntersectionSimplified(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end) const;
bool hasIntersectionSimplified(const Core::GeoPosition &start, const Core::GeoPosition &end) const;
bool hasIntersectionSimplified(const QVector<LtsUtils::QPoint3D> &trajectory) const;
bool hasIntersectionSimplified(const std::vector<Core::GeoPosition> &trajectory) const;
bool hasIntersection(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end) const;
bool hasIntersection(const Core::GeoPosition &start, const Core::GeoPosition &end) const;
bool hasIntersection(const QVector<LtsUtils::QPoint3D> &trajectory) const;
bool hasIntersection(const std::vector<Core::GeoPosition> &trajectory) const;
Core::GeoPosition intersection(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end) const;
Core::GeoPosition intersection(const Core::GeoPosition &start, const Core::GeoPosition &end) const;
Core::GeoPosition intersection(const QVector<LtsUtils::QPoint3D> &trajectory) const;
Core::GeoPosition intersection(const std::vector<Core::GeoPosition> &trajectory) const;
LtsUtils::QPoint3D fromGeographic(const Core::GeoPosition &point) const;
QVector<LtsUtils::QPoint3D> fromGeographic(const std::vector<Core::GeoPosition> &points) const;
Core::GeoPosition toGeographic(const LtsUtils::QPoint3D &point) const;
std::vector<Core::GeoPosition> toGeographic(const QVector<LtsUtils::QPoint3D> &points) const;
LtsUtils::QPoint3D fromReference(const LtsUtils::QPoint3D &point) const;
QVector<LtsUtils::QPoint3D> fromReference(const QVector<LtsUtils::QPoint3D> &points) const;
LtsUtils::QPoint3D toReference(const LtsUtils::QPoint3D &point) const;
QVector<LtsUtils::QPoint3D> toReference(const QVector<LtsUtils::QPoint3D> &points) const;
const int &buildingId() const { return m_buildingId; }
const double &height() const { return m_height; }
const double &angle() const { return m_angle; }
const Core::GeoPosition &refPosGeo() const { return m_refPosGeo; }
const LtsCoordTrans::UtmCoordinate &refPosUtm() const { return m_refPosUtm; }
const LtsUtils::QPoint3D &refPos() const { return m_refPos; }
const QPolygonF &footprint() const { return m_footprint; }
const QRectF &boundingRect() const { return m_boundingRect; }
bool operator ==(const BuildingModel &other) const;
bool operator !=(const BuildingModel &other) const;
private:
int m_buildingId{0};
double m_height{0.};
double m_angle{0.};
Core::GeoPosition m_refPosGeo;
LtsCoordTrans::UtmCoordinate m_refPosUtm;
LtsUtils::QPoint3D m_refPos; // UTM
QPolygonF m_footprint;
QRectF m_boundingRect;
LOGGER_T &m_logger;
}; // class BuildingModel
} // namespace CesBuildings
@@ -0,0 +1,997 @@
/**
* Handler for player data
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2017-02-20
*/
#include "handler_aes_data.h"
#include <CentralEffectSimulation/handler_participant.h>
#include <CentralEffectSimulation/handler_building_data.h>
#include <QPainterPath>
#include <QPointF>
#include <QPolygonF>
#include <QTimer>
#include <QTransform>
#include <LtsUtilsCore/dds_bitarray.h>
#include <LtsUtilsCore/qpoint3d.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#define TIMEDIFFVALID 3000
namespace CesBuildings
{
HandlerAesData::HandlerAesData(const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler,
const std::shared_ptr<CentralEffectSimulation::HandlerBuildingData> &buildingDataHandler,
QObject *parent)
: QObject(parent)
, m_ddsHandler(ddsHandler)
, m_handlerBuildingData(buildingDataHandler)
, m_logger(CentralEffectSimulation::getLogger("Plugin.Buildings.HandlerAesData"))
{
} // end of ctor()
//-----------------------------------------------------------------------------
HandlerAesData::~HandlerAesData()
{
} // end of dtor()
//-----------------------------------------------------------------------------
bool HandlerAesData::init()
{
auto dtcAes = m_ddsHandler->dtcAes();
dtcAes->enableChargeEffect();
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::chargeEffectChanged,
this, &HandlerAesData::onChargeEffectChanged);
dtcAes->enableExplosionSingle();
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleChanged,
this, &HandlerAesData::onExplosionSingleChanged);
dtcAes->enableAirSupportImpact();
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::airSupportImpactChanged,
this, &HandlerAesData::onAirSupportImpactChanged);
dtcAes->enableTriggeredImpacts();
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::triggeredImpactsChanged,
this, &HandlerAesData::onTriggeredImpactsChanged);
dtcAes->waitForHistoricalDataAesItemView(1000);
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
this, &HandlerAesData::onAesItemViewChanged);
dtcAes->enableEffects();
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::effectsChanged,
this, &HandlerAesData::onEffectsChanged, Qt::UniqueConnection);
dtcAes->enableBoobyTrap();
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::boobyTrapChanged,
this, &HandlerAesData::onBoobyTrapChanged, Qt::UniqueConnection);
// Get 'static' data for all AesItemView
{
auto cb = [this](const AreaEffectSimulation::AesItemView & aiv)
{
onAesItemViewChanged(aiv, DataModification::eAdded);
};
if (!dtcAes->aesItemViews(cb))
return false;
}
return true;
} // end of init()
void HandlerAesData::onBoobyTrapChanged(const AreaEffectSimulation::BoobyTrap &data, DataModification modType)
{
DEBUG_LOG(m_logger) << "onBoobyTrapChanged"
<< " id=" << data.id()
<< " impactPosition=" << data.impactPosition()
<< " impactRadius=" << data.impactRadius()
<< " effectStateId=" << data.effectStateId();
if (data.isDeleted()
|| data.effectStateId() == AreaEffectSimulation::AesEffectState::EsRemoved
|| modType == DataModification::eRemoved)
return;
if (!data.triggered())
return;
INFO_LOG(m_logger) << "HandlerParticipantBoobyTrap::onBoobyTrapChanged"
<< " data.id=" << data.id()
<< " effectStateId=" << data.effectStateId();
if (!data.effectStart().is_set())
return;
if ((m_ddsHandler->currentPartitionTime() - (data.effectStart().get() + data.effectDuration())) > 2000)
{
INFO_LOG(m_logger) << "onBoobyTrap outdated";
return;
}
AreaEffectSimulation::AesItemView itemView;
AreaEffectSimulation::AesType aesType = AreaEffectSimulation::AesType_def::AtBoobyTrap;
m_ddsHandler->dtcAes()->aesItemViewFromEntityId(data.id(), aesType, itemView);
checkBuildingsHit(itemView);
}
//-----------------------------------------------------------------------------
// ///////////////////////////////////
// A E S (AreaEffectSimulation)
// ///////////////////////////////////
void HandlerAesData::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
{
DEBUG_LOG(m_logger) << "onAesItemViewChanged"
<< " data.aesTypeId()=" << data.aesTypeId();
if (modType != DataModification::eAdded &&
modType != DataModification::eModified)
return;
DEBUG_LOG(m_logger) << "Got AesItemView: " << data.effectStateId();
if (data.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired)
{
INFO_LOG(m_logger) << "AesEffectState_def::EsExpired"
<< " currentPartitionTime=" << m_ddsHandler->currentPartitionTime()
<< " effectStart=" << data.effectStart()
<< " diff = " << m_ddsHandler->currentPartitionTime() - data.effectStart() ;
if (m_ddsHandler->currentPartitionTime() == 0)
return;
if ((data.aesTypeId() == AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary)
|| (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary))
{
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary)
{
DEBUG_LOG(m_logger) << "AtOffRouteMineSecondary id=" << data.id() / 1000;
auto offRouteMine = m_ddsHandler->dtcAes()->offRouteMine((int)(data.id() / 1000));
if (!offRouteMine.effectStart().is_set())
{
DEBUG_LOG(m_logger) << "!offRouteMine.effectStart().is_set()";
return;
}
DEBUG_LOG(m_logger) << " currentPartitionTime=" << m_ddsHandler->currentPartitionTime()
<< " effectStart=" << offRouteMine.effectStart()
<< " effectDuration=" << offRouteMine.effectDuration()
<< " diff = " << m_ddsHandler->currentPartitionTime() - (offRouteMine.effectStart().get() + offRouteMine.effectDuration()) ;
if ((m_ddsHandler->currentPartitionTime() - (offRouteMine.effectStart().get() + offRouteMine.effectDuration())) < 2000)
{
DEBUG_LOG(m_logger) << "AtBoobyTrapSecondary Mine wird ausgeloeset.";
checkBuildingsHit(data);
}
else
{
DEBUG_LOG(m_logger) << "outdated return";
return;
}
}
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary)
{
DEBUG_LOG(m_logger) << "AtBoobyTrapSecondary id=" << data.id() / 1000;
//auto offRouteMine = m_ddsHandler->dtcAes()->offRouteMine((int) (data.id() / 1000));
auto boobyTrap = m_ddsHandler->dtcAes()->boobyTrap((int)(data.id() / 1000));
if (!boobyTrap.effectStart().is_set())
{
DEBUG_LOG(m_logger) << "!offRouteMine.effectStart().is_set()";
return;
}
DEBUG_LOG(m_logger) << " currentPartitionTime=" << m_ddsHandler->currentPartitionTime()
<< " effectStart=" << boobyTrap.effectStart()
<< " effectDuration=" << boobyTrap.effectDuration()
<< " diff = " << m_ddsHandler->currentPartitionTime() - (boobyTrap.effectStart().get() + boobyTrap.effectDuration()) ;
if ((m_ddsHandler->currentPartitionTime() - (boobyTrap.effectStart().get() + boobyTrap.effectDuration())) < 2000)
{
DEBUG_LOG(m_logger) << "AtBoobyTrapSecondary Mine wird ausgeloeset.";
checkBuildingsHit(data);
}
else
{
DEBUG_LOG(m_logger) << "outdated return";
return;
}
}
DEBUG_LOG(m_logger) << "removeStates data";
removeStates(data);
DEBUG_LOG(m_logger) << "m_aesItemViewsUtm remove id" << data.aesItemId();
m_aesItemViewsUtm.remove(data.aesItemId());
}
}
}
void HandlerAesData::removeStates(const AreaEffectSimulation::AesItemView &data)
{
if (data.aesTypeId() != AreaEffectSimulation::AesType_def::AtExplosionArea)
return;
DEBUG_LOG(m_logger) << "Remove aesItemId=" << data.aesItemId();
// remove State for each building
for (CentralEffectSimulation::BitfieldStates &bfs : m_bitfieldStatesBld)
bfs.remove(data.aesItemId());
} // end removeStates
void HandlerAesData::calculateBuildingExplosion(const AreaEffectSimulation::ChargeStruct &chargeStruct,
const Core::GeoPosition2D& impactPosition,
const int id)
{
const double impactRadius = m_ddsHandler->chargeTypeRadius(chargeStruct);
DEBUG_LOG(m_logger) << "Handle ExplosionSingle (EsActivated)"
<< ", m_handlerBuildingData.getFootprints().size =" << m_handlerBuildingData->getFootprints().size();
QHash<int, CentralEffectSimulation::HandlerBuildingData::Footprint> footprints = m_handlerBuildingData->getFootprints();
// Bounding-Box-Check
// QMap<int, Footprint> m_handlerBuildingData.getFootprints();
for (const CentralEffectSimulation::HandlerBuildingData::Footprint &footprint : qAsConst(footprints))
{
const Core::GeoPosition2D impactPosition2D(impactPosition.lon(), impactPosition.lat());
if (inFootprint(impactPosition, footprint, impactRadius))
{
DEBUG_LOG(m_logger) << "ftc sendCESHitOnBuilding mseId = " << footprint.mseId
<< " chargeTypeId = " << chargeStruct.chargeTypeId()
<< " id = " << id
<< " currentPartitionTime = " << m_ddsHandler->currentPartitionTime()
<< " impactPosition2D.lon = " << impactPosition2D.lon()
<< " impactPosition2D.lat = " << impactPosition2D.lat();
Buildings::SendCesHitOnBuildingRequest requestBld(
footprint.mseId,
chargeStruct.chargeTypeId(),
m_ddsHandler->dtcPdm()->getBuildingChargeEffectByChargeTypeId(chargeStruct.chargeTypeId()).destructiveFactor(),
m_ddsHandler->dtcPdm()->getBuildingChargeEffectByChargeTypeId(chargeStruct.chargeTypeId()).penetrationFactor(),
id,
m_ddsHandler->currentPartitionTime(),
Core::GeoPosition(impactPosition2D.lon(), impactPosition2D.lat(), 0.0),
QStringLiteral("properties").toStdString());
m_ddsHandler->ftcBld()->sendCesHitOnBuildingRequest(requestBld, this);
}
else
DEBUG_LOG(m_logger) << "Not sendCESHitOnBuilding mseId = " << footprint.mseId;
DEBUG_LOG(m_logger) << "boundingBoxImpact.contains(footprint)";
} // for
}
void HandlerAesData::startTimer(int id, int msec) {
auto *timer = new QTimer(this);
timer->setProperty("chargeEffectId", id);
// Timeout-Slot mit echtem SLOT
connect(timer, &QTimer::timeout, this, &HandlerAesData::onStartTimeReached);
timer->start(msec);
DEBUG_LOG(m_logger) << "Timer " << id << " gestartet fuer " << msec << " ms.";
}
void HandlerAesData::onStartTimeReached()
{
if (!sender())
return;
bool bOk;
int chargeEffectId = sender()->property("chargeEffectId").toInt(&bOk);
if (!bOk)
return;
DEBUG_LOG(m_logger) << "Timer " << chargeEffectId << " ausgeloest!";
// Timer stoppen und loeschen
AreaEffectSimulation::ChargeEffect data = m_chargeEffects.value(chargeEffectId);
AreaEffectSimulation::ChargeStruct chargeStruct(data.chargeTypeId(),data.igniterTypeId(), data.igniterFunctionId());
calculateBuildingExplosion(chargeStruct, data.position(), data.id());
sender()->deleteLater();
m_chargeEffects.remove(chargeEffectId);
}
void HandlerAesData::onChargeEffectChanged(const AreaEffectSimulation::ChargeEffect &data, DataModification modType)
{
DEBUG_LOG(m_logger) << "HandlerExplosions::onChargeEffectChanged";
if (modType == DataModification::eRemoved)
return;
const long long effectStart = data.effectStart();
DEBUG_LOG(m_logger) << "HandlerExplosions::onChargeEffectChanged"
<< ", effectStart=" << effectStart
<< ", currentPartitionTime=" << m_ddsHandler->currentPartitionTime();
// Startzeit in der Vergangenheit: aktuelle Zeit - 3 Sekunden
if ( effectStart < m_ddsHandler->currentPartitionTime() - TIMEDIFFVALID )
{
DEBUG_LOG(m_logger) << "Startzeit in der Vergangenheit: aktuelle Zeit - 3 Sekunden";
return;
}
// Startzeit entspricht der aktuellen Zeit
if ( effectStart > m_ddsHandler->currentPartitionTime() - TIMEDIFFVALID
&& effectStart < m_ddsHandler->currentPartitionTime() + data.effectDuration() )
{
DEBUG_LOG(m_logger) << "Startzeit entspricht der aktuellen Zeit";
AreaEffectSimulation::ChargeStruct chargeStruct;
chargeStruct.chargeTypeId(data.chargeTypeId());
chargeStruct.igniterTypeId(data.igniterTypeId());
calculateBuildingExplosion(chargeStruct, data.position(), data.id());
}
// Startzeit in der Zukunft:
else if (effectStart > m_ddsHandler->currentPartitionTime() + data.effectDuration())
{
// Start mit Timer
DEBUG_LOG(m_logger) << "Startzeit in der Zukunft"
<< ", id :" << data.id()
<< ", duration=" << effectStart - m_ddsHandler->currentPartitionTime();
m_chargeEffects.insert(data.id(), data);
startTimer(data.id(), effectStart - m_ddsHandler->currentPartitionTime());
}
DEBUG_LOG(m_logger) << "END onChargeEffectChanged";
}
void HandlerAesData::onExplosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType)
{
bool handleExplosion = false;
if (modType != DataModification::eAdded &&
modType != DataModification::eModified)
{
m_explosionSingleState.remove(data.id());
return;
}
if (data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsRemoved)
{
DEBUG_LOG(m_logger) << "Remove SingleExplosion";
m_explosionSingleState.remove(data.id());
return;
}
// Only handle transitions from prepared or fired to activated
if ((m_explosionSingleState.value(data.id()) == AreaEffectSimulation::AesEffectState_def::EsPrepared ||
m_explosionSingleState.value(data.id()) == AreaEffectSimulation::AesEffectState_def::EsFired) &&
data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated)
{
DEBUG_LOG(m_logger) << "Handle SingleExplosion";
handleExplosion = true;
}
m_explosionSingleState.insert(data.id(), data.effectStateId());
DEBUG_LOG(m_logger) << "Got ExplosionSingle";
if (handleExplosion)
{
calculateBuildingExplosion(data.chargeStruct(), data.impactPosition(), data.id());
}
} // onExplosionSingleChanged
void HandlerAesData::onAirSupportImpactChanged(const AreaEffectSimulation::AirSupportImpact &data, DataModification modType)
{
DEBUG_LOG(m_logger) << "Got onAirSupportImpactChanged()";
AreaEffectSimulation::ExplosionSingle esData;
esData.id(data.id());
esData.chargeStruct().chargeTypeId(data.chargeStruct().chargeTypeId());
esData.impactPosition(data.impactPosition());
esData.effectStateId(data.effectStateId());
onExplosionSingleChanged(esData, modType);
}
void HandlerAesData::onTriggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType)
{
if (modType != DataModification::eAdded &&
modType != DataModification::eModified)
return;
DEBUG_LOG(m_logger) << "Got TriggeredImpacts";
preCalculateImpacts(data);
}
void HandlerAesData::onEffectsChanged(const AreaEffectSimulation::Effects &effects, DataModification modType)
{
TRACE_LOG(m_logger) << " Got Effects " << effects;
if (modType == DataModification::eRemoved)
return;
if (effects.aesTypeId().underlying() != AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions)
return;
DEBUG_LOG(m_logger) << " Got typechecked effects " << effects;
// calculate for every building of our exercise:
const QHash<int, CentralEffectSimulation::HandlerBuildingData::Footprint> &footprints = m_handlerBuildingData->getFootprints();
for (const CentralEffectSimulation::HandlerBuildingData::Footprint &footprint : qAsConst(footprints))
{
calculateImpacts(effects, footprint);
}
}
// ///////////////////////////////////
// I S M (InfrastructureManagement)
// ///////////////////////////////////
// ///////////////////////////////////
// Calculations:
// ///////////////////////////////////
bool HandlerAesData::inBoundingBox(const Core::GeoPosition2D& impactPosition,
const CentralEffectSimulation::HandlerBuildingData::Footprint &footprint,
const double impactRadius) const
{
const QPointF impactPos(CentralEffectSimulation::geographic2Utm(impactPosition, footprint.zone));
const QPolygonF polyBldgRadius({QPointF(footprint.boundingBoxPolyUtm.bottomLeft().rx() - impactRadius,
footprint.boundingBoxPolyUtm.bottomLeft().ry() + impactRadius),
QPointF(footprint.boundingBoxPolyUtm.topRight().rx() + impactRadius,
footprint.boundingBoxPolyUtm.bottomLeft().ry() + impactRadius),
QPointF(footprint.boundingBoxPolyUtm.topRight().rx() + impactRadius,
footprint.boundingBoxPolyUtm.topRight().ry() - impactRadius),
QPointF(footprint.boundingBoxPolyUtm.bottomLeft().rx() - impactRadius,
footprint.boundingBoxPolyUtm.topRight().ry() - impactRadius)});
return (polyBldgRadius.containsPoint(impactPos, Qt::OddEvenFill));
}
bool HandlerAesData::inFootprint(const Core::GeoPosition2D &geoPosition,
const CentralEffectSimulation::HandlerBuildingData::Footprint &footPrint,
const double radius) const
{
if ( !inBoundingBox( geoPosition, footPrint, radius))
return false;
const QPointF impact(CentralEffectSimulation::geographic2Utm(geoPosition, footPrint.zone));
// NT: Folgendes raubt zu viele Zeilen beim tail. Daher nehme ich es raus.
// if (m_logger.isDebugEnabled())
// {
// const QPointF utmBuilding(CentralEffectSimulation::geographic2Utm(footPrint.geoPosition, footPrint.zone));
// DEBUG_LOG(m_logger) << "Impact (x/y)=" << CentralEffectSimulation::debug(impact - utmBuilding);
// for (int i = 0; i < footPrint.polyUtm.length(); i++)
// DEBUG_LOG(m_logger) << " poly (x/y)=" << CentralEffectSimulation::debug(footPrint.polyUtm[i] - utmBuilding);
// }
// Check, if hit direct on building
if (footPrint.polyUtm.containsPoint(impact, Qt::OddEvenFill))
return true;
// Check, if hit in munition-radius
QPainterPath ppFp;
ppFp.addPolygon(footPrint.polyUtm);
QPainterPath ppCircle;
ppCircle.addEllipse(impact, radius, radius);
return ppFp.intersects(ppCircle);
}
void HandlerAesData::preCalculateImpacts(const AreaEffectSimulation::TriggeredImpacts &data)
{
if (data.id() <= 0)
return;
DEBUG_LOG(m_logger) << "preCalculateImpacts";
// Find AES ItemView and set Bounding-Box of Aes-Field
const int aesItemId = data.aesItemId();
// Search corresponding itemView. If not available no impact to participant.
// Use dtcAes since sender (AES) publishes TriggeredImpacts and AesItemView
//
AreaEffectSimulation::AesItemView aesItemView;
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> dtcAes = m_ddsHandler->dtcAes();
if (!dtcAes->aesItemViewFromEntityId(aesItemId, data.aesTypeId(), aesItemView))
{
static long msgCnt = 0;
WARNING_LOG(m_logger) << "TriggeredExplosions.aesItemId=" << data.aesItemId() << " No aesItemView available"
<< " (cnt=" << ++msgCnt << ")";
return;
}
// Maybe ExlosionClusters Trajectory is hitting a building?
// Vulnerability should be calculated
const QHash<int, CentralEffectSimulation::HandlerBuildingData::Footprint> &footprints = m_handlerBuildingData->getFootprints();
for (const CentralEffectSimulation::HandlerBuildingData::Footprint &footprint : qAsConst(footprints))
{
calculateImpacts(data, aesItemView, footprint);
} // for
}
void HandlerAesData::onSendCesHitOnBuildingReply(const Core::FunctionReplyObject &replyObject)
{
if (replyObject.error())
WARNING_LOG(m_logger) << "Can not send hit on building to building service: " << replyObject()
<< ", m_handlerBuildingData.getFootprints().size()" << m_handlerBuildingData->getFootprints().size();
else
DEBUG_LOG(m_logger) << "onSendCesHitOnBuildingReply for id " << replyObject.id() << " success\n"
<< " replyObject.str() = " << replyObject.str();
}
void HandlerAesData::onSendCesHit3DonBuildingReply(const Core::FunctionReplyObject &replyObject)
{
DEBUG_LOG(m_logger) << "m_handlerBuildingData.getFootprints() size " << m_handlerBuildingData->getFootprints().size();
if (replyObject.error())
WARNING_LOG(m_logger) << "Can not send hit3D on building to building service: " << replyObject()
<< ", m_handlerBuildingData.getFootprints().size()" << m_handlerBuildingData->getFootprints().size();
else
DEBUG_LOG(m_logger) << "onSendCesHit3DonBuildingReply for id " << replyObject.id() << " success\n"
<< " replyObject.str() = " << replyObject.str();
}
void HandlerAesData::onSendCesHitInformationReply(const Core::FunctionReplyObject &reply)
{
if (reply.error())
WARNING_LOG(m_logger) << "onSendCesHitInformationReply for id " << reply.id() << " failed: " << reply.str();
else
DEBUG_LOG(m_logger) << "onSendCesHitInformationReply for id " << reply.id() << " successful";
}
void HandlerAesData::onSetBuildingStatesReply(const Core::FunctionReplyObject &reply)
{
if (reply.error())
WARNING_LOG(m_logger) << "onSetBuildingStatesReply for id " << reply.id() << " failed: " << reply.str();
else
DEBUG_LOG(m_logger) << "onSetBuildingStatesReply for id " << reply.id() << " successful";
}
// calculate impacts for one building
void HandlerAesData::calculateImpacts(const AreaEffectSimulation::TriggeredImpacts &data, const AreaEffectSimulation::AesItemView &aesItemView,
const CentralEffectSimulation::HandlerBuildingData::Footprint &footprint)
{
const int aesItemId = data.aesItemId();
bool bIsExplosionCluster = false;
ProjectDataManagement::IgniterFunctionBase ignFuncBase = ProjectDataManagement::IgniterFunctionBase::IfbImpact;
// check for correct AES type artillery only
static QVector<AreaEffectSimulation::AesType_def::type> s_relevantTypes =
{
AreaEffectSimulation::AesType_def::AtExplosionArea,
AreaEffectSimulation::AesType_def::AtExplosionSingle,
AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions,
};
if (data.aesTypeId().underlying() == AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions)
{
bIsExplosionCluster = true;
ignFuncBase = igniterFunctionBaseExplosionCluster(aesItemId); // assume that fuseType does not differ within a single ExplosionArea
DEBUG_LOG(m_logger) << "Calculate, bIsExplosionCluster = " << bIsExplosionCluster
<< ", ignFuncBase = " << ignFuncBase;
}
else if (s_relevantTypes.contains(data.aesTypeId().underlying()))
DEBUG_LOG(m_logger) << "Calculate";
else
{
DEBUG_LOG(m_logger) << "No Calculation";
return;
}
if (aesItemId != aesItemView.aesItemId())
{
WARNING_LOG(m_logger) << "mismatch: "
<< ", TriggeredExplosions.aesItemId=" << data.aesItemId()
<< ", AesItemView.aesItemId=" << aesItemView.aesItemId();
return;
}
DEBUG_LOG(m_logger) << "calculateImpacts mseId=" << footprint.mseId << " aesItemId " << aesItemId
<< ", bIsExplosionCluster = " << bIsExplosionCluster;
// get position(s) of impact(s):
CentralEffectSimulation::BitfieldStates &bitfieldStates = m_bitfieldStatesBld[footprint.mseId];
QSet<int> &bitfieldState = bitfieldStates[aesItemId];
for (int i : qAsConst(bitfieldState))
DEBUG_LOG(m_logger) << "bitfieldState for " << aesItemId << ": " << i;
for (int32_t bitFieldIdx = 0; bitFieldIdx < data.impactCount(); ++bitFieldIdx)
{
// no break, because every bit can be a hit
if (LtsUtils::BitArray::testBit(data.bitfield(), bitFieldIdx))
continue;
// get position of impact to corresponding bit
if (aesItemView.form().size() <= size_t(bitFieldIdx))
continue;
const Core::GeoPosition &impactPosition = aesItemView.form()[bitFieldIdx];
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " impactPosition: lat/lon" << impactPosition.lat() << "/" << impactPosition.lon() << " z=" << impactPosition.z()
<< " UTM=" << CentralEffectSimulation::debug(CentralEffectSimulation::geographic2Utm(impactPosition));
// check, if impact-pos + munition-radius touch the building
// get radius of munition
const double impactRadius = m_ddsHandler->chargeTypeRadius(aesItemView.chargeStruct());
if (inFootprint(impactPosition, footprint, impactRadius))
{
DEBUG_LOG(m_logger) << "In Footprint of mseId = " << footprint.mseId;
if (!bitfieldState.contains(bitFieldIdx))
{
DEBUG_LOG(m_logger) << "m_bitfieldStates.insert(aesItemId=" << aesItemId << ", bitfieldState)" << " bitFieldIdx=" << bitFieldIdx;
bitfieldState.insert(bitFieldIdx);
DEBUG_LOG(m_logger) << "sendCesHit mseId = " << footprint.mseId
<< ", aesItemId=" << aesItemId
<< ", bitFieldIdx= " << bitFieldIdx
<< ", ignFuncBase = " << ignFuncBase;
if (! qFuzzyIsNull(impactPosition.z()))
{
// since HandlerBuildingModel::handleDetonationLocationRequest has already
// calculated to fuseType, the impactPosition is the detonationLocation:
Core::GeoPosition detonationLocation = impactPosition;
//
double detonationDistance = 0;
switch (ignFuncBase.underlying())
{
case ProjectDataManagement::IgniterFunctionBase::IfbProximity:
detonationDistance = -5;
break;
case ProjectDataManagement::IgniterFunctionBase::IfbImpact:
detonationDistance = 0;
break;
case ProjectDataManagement::IgniterFunctionBase::IfbDelay:
detonationDistance = 5;
break;
default:
// empty
break;
} // switch
Buildings::SendCesHit3DonBuildingRequest requestBld(
footprint.mseId,
aesItemView.chargeStruct().chargeTypeId(),
m_ddsHandler->dtcPdm()->getBuildingChargeEffectByChargeTypeId(aesItemView.chargeStruct().chargeTypeId()).destructiveFactor(),
m_ddsHandler->dtcPdm()->getBuildingChargeEffectByChargeTypeId(aesItemView.chargeStruct().chargeTypeId()).penetrationFactor(),
aesItemId,
m_ddsHandler->currentPartitionTime(),
impactPosition,
detonationLocation,
detonationDistance,
QStringLiteral("properties").toStdString());
DEBUG_LOG(m_logger) << "sendCesHit3DonBuildingRequest for aesItemId=" << aesItemId
<< " bitFieldIdx= " << bitFieldIdx
<< ", requestBld= " << requestBld;
m_ddsHandler->ftcBld()->sendCesHit3DonBuildingRequest(requestBld, this);
}
else
{
// z-Value is 0 -> old / ! AtExplosionClusterSingleExplosions
Buildings::SendCesHitOnBuildingRequest requestBld(
footprint.mseId,
aesItemView.chargeStruct().chargeTypeId(),
m_ddsHandler->dtcPdm()->getBuildingChargeEffectByChargeTypeId(aesItemView.chargeStruct().chargeTypeId()).destructiveFactor(),
m_ddsHandler->dtcPdm()->getBuildingChargeEffectByChargeTypeId(aesItemView.chargeStruct().chargeTypeId()).penetrationFactor(),
aesItemId,
m_ddsHandler->currentPartitionTime(),
Core::GeoPosition(impactPosition.lon(), impactPosition.lat(), 0.0),
QStringLiteral("properties").toStdString());
DEBUG_LOG(m_logger) << "sendCesHitOnBuildingRequest for aesItemId=" << aesItemId
<< " bitFieldIdx= " << bitFieldIdx
<< ", impactPosition= " << impactPosition;
m_ddsHandler->ftcBld()->sendCesHitOnBuildingRequest(requestBld, this);
} // if (impactPosition.z() > 0)
}
else
DEBUG_LOG(m_logger) << "NOT in Footprint of mseId = " << footprint.mseId;
// if (inFootprint(impactPosition
} // foreach Impact
} // for (int32_t bitFieldId
}
void HandlerAesData::calculateImpacts(const AreaEffectSimulation::Effects &effects, const CentralEffectSimulation::HandlerBuildingData::Footprint &footprint)
{
if (effects.aesTypeId().underlying() != AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions)
return;
const int aesItemId = effects.aesItemId();
DEBUG_LOG(m_logger) << "calculateImpacts mseId=" << footprint.mseId << " data.aesItemId() " << aesItemId;
const AreaEffectSimulation::ExplosionCluster &ec = m_ddsHandler->dtcAes()->explosionCluster(effects.aesItemId());
if (ec.id() != aesItemId)
return;
const ProjectDataManagement::IgniterFunctionBase ignFuncBase = igniterFunctionBaseExplosionCluster(aesItemId);
const double impactRadius = m_ddsHandler->chargeTypeRadius(ec.chargeStruct());
CentralEffectSimulation::BitfieldStates &bitfieldStates = m_bitfieldStatesBld[footprint.mseId];
QSet<int> &bitfieldState = bitfieldStates[aesItemId];
const std::vector<AreaEffectSimulation::SingleEffect> &singleEffectsRef = effects.singleEffects();
int indexBitFieldIdx = -1;
for (const AreaEffectSimulation::SingleEffect &singleEffect : qAsConst(singleEffectsRef))
{
++indexBitFieldIdx;
// just SesTriggered are relevant:
if (singleEffect.singleEffectState() != AreaEffectSimulation::AesSingleEffectState_def::SesTriggered)
continue;
// already processed?
if (bitfieldState.contains(indexBitFieldIdx))
continue;
// is building in range?
const Core::GeoPosition &impactPositionGeo = singleEffect.position();
if (!inFootprint(impactPositionGeo, footprint, impactRadius))
continue;
// Hier könnte man zunächst zwei-dimensional prüfen, ob ein anderes Bldg eine Verdeckung erzeugt zw.
// a) Explosionsort (impactPosition) und
// b) Grundriss (footprint) des Kandidaten
// Diese Verdeckung würde die Wirkung auf den Kandidaten reduzieren.
// 2DpoylgonCentroid https://stackoverflow.com/questions/2792443/finding-the-centroid-of-a-polygon
const LtsCoordTrans::LtsCoordinate impactPos(impactPositionGeo);
const QVector<int> &buildingIdsInBetween = findBuildingsBetween(impactPos, footprint);
QString mseIdAsStr;
for (auto mseId : buildingIdsInBetween)
mseIdAsStr += QString(QStringLiteral("_coveredByMseId_%1;")).arg(mseId);
DEBUG_LOG(m_logger) << "findBuildingsBetween returns mseIdAsStr =" << mseIdAsStr;
const ProjectDataManagement::BuildingChargeEffect &bldgChargeEffect = m_ddsHandler->dtcPdm()->getBuildingChargeEffectByChargeTypeId(ec.chargeStruct().chargeTypeId());
if (bldgChargeEffect.id() <= 0)
ERROR_LOG(m_logger) << "getBuildingChargeEffectByChargeTypeId failed, chargeTypeId not found: =" << ec.chargeStruct().chargeTypeId();
qint32 destructiveFactor = bldgChargeEffect.destructiveFactor();
qint32 penetrationFactor = bldgChargeEffect.penetrationFactor();
if ((destructiveFactor <= 0) || (penetrationFactor <= 0))
WARNING_LOG(m_logger) << "getBuildingChargeEffectByChargeTypeId failed, destructiveFactor or penetrationFactor invalid"
<< ", destructiveFactor = " << destructiveFactor
<< ", penetrationFactor = " << penetrationFactor;
if (!buildingIdsInBetween.empty())
{
destructiveFactor /= 2;
penetrationFactor /= 2;
}
QString properties = QStringLiteral("properties");
properties += mseIdAsStr;
const AreaEffectSimulation::AesZPlacement_def::type zPlacement = singleEffect.zPlacement().underlying();
if (zPlacement == AreaEffectSimulation::AesZPlacement_def::ZpDraped)
{
// z-Value is 0 -> old:
Buildings::SendCesHitOnBuildingRequest requestBld(
footprint.mseId,
ec.chargeStruct().chargeTypeId(),
destructiveFactor,
penetrationFactor,
aesItemId,
m_ddsHandler->currentPartitionTime(),
Core::GeoPosition(impactPositionGeo.lon(), impactPositionGeo.lat(), 0.0),
properties.toStdString());
DEBUG_LOG(m_logger) << "sendCesHitOnBuildingRequest for aesItemId=" << aesItemId
<< " bitFieldIdx= " << indexBitFieldIdx
<< ", impactPositionGeo= " << impactPositionGeo
<< ", chargeTypeId= " << ec.chargeStruct().chargeTypeId()
<< ", destructiveFactor= " << destructiveFactor
<< ", penetrationFactor= " << penetrationFactor;
m_ddsHandler->ftcBld()->sendCesHitOnBuildingRequest(requestBld, this);
bitfieldState.insert(indexBitFieldIdx);
}
else if (zPlacement == AreaEffectSimulation::AesZPlacement_def::ZpAbsolute)
{
// since HandlerBuildingModel::handleDetonationLocationRequest has already
// calculated to ignFuncBase, the impactPosition is the detonationLocation:
Core::GeoPosition detonationLocation = impactPositionGeo;
double detonationDistance = 0;
switch (ignFuncBase.underlying())
{
case ProjectDataManagement::IgniterFunctionBase::IfbProximity:
detonationDistance = -5;
break;
case ProjectDataManagement::IgniterFunctionBase::IfbImpact:
detonationDistance = 0;
break;
case ProjectDataManagement::IgniterFunctionBase::IfbDelay:
detonationDistance = 5;
break;
default:
// empty
break;
} // switch
Buildings::SendCesHit3DonBuildingRequest requestBld(
footprint.mseId,
ec.chargeStruct().chargeTypeId(),
destructiveFactor,
penetrationFactor,
aesItemId,
m_ddsHandler->currentPartitionTime(),
impactPositionGeo,
detonationLocation,
detonationDistance,
properties.toStdString());
DEBUG_LOG(m_logger) << "SendCesHit3DonBuildingRequest for aesItemId=" << aesItemId
<< " bitFieldIdx= " << indexBitFieldIdx
<< ", impactPosition= " << impactPositionGeo
<< ", zPlacement= " << zPlacement
<< ", chargeTypeId= " << ec.chargeStruct().chargeTypeId()
<< ", destructiveFactor= " << destructiveFactor
<< ", penetrationFactor= " << penetrationFactor;
m_ddsHandler->ftcBld()->sendCesHit3DonBuildingRequest(requestBld, this);
bitfieldState.insert(indexBitFieldIdx);
} // if
} // for
}
void HandlerAesData::checkBuildingsHit(const AreaEffectSimulation::AesItemView &data)
{
const int exerciseId = m_ddsHandler->getExerciseId();
QPolygonF polyGeo;
DEBUG_LOG(m_logger) << "checkBuildingsHit " << ", aesItemId=" << data.aesItemId();
DEBUG_LOG(m_logger) << "AtBoobyTrapSecondary data.form().size()=" << data.form().size();
// BoobyTrap
polyGeo.reserve(data.form().size());
for (const auto &pointGeo : qAsConst(data.form()))
{
QPointF point;
point.setX(pointGeo.lon());
point.setY(pointGeo.lat());
DEBUG_LOG(m_logger) << "point= " << point.x() << "/" << point.y();
polyGeo.append(point);
}
bool completeEnclosed = false;
bool isGroundLevel = true;
const QVector<int> &buildingIdsInside = m_ddsHandler->dtcIsm()->getBuildingByPolygon(exerciseId, polyGeo, completeEnclosed, isGroundLevel);
DEBUG_LOG(m_logger) << "buildingsInside.size=" << buildingIdsInside.size()
<< " exerciseId=" << exerciseId;
// only include buildings within the radius
for (const int buildingId : qAsConst(buildingIdsInside))
{
DEBUG_LOG(m_logger) << " BuildingId=" << buildingId;
Buildings::Building tmpBldg;
tmpBldg.buildingId(buildingId);
Core::GeoPosition impactPosition;
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary)
{
impactPosition.lat(m_ddsHandler->dtcAes()->boobyTrap(data.aesItemId()).impactPosition().lat());
impactPosition.lon(m_ddsHandler->dtcAes()->boobyTrap(data.aesItemId()).impactPosition().lon());
}
else if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary)
{
int zone = -1;
LtsCoordTrans::UtmCoordinate bottomLeft = LtsCoordTrans::UtmCoordinate::fromGeographic(data.boundingBoxBottomLeft().lon(), data.boundingBoxBottomLeft().lat(), zone);
LtsCoordTrans::UtmCoordinate topRight = LtsCoordTrans::UtmCoordinate::fromGeographic(data.boundingBoxTopRight().lon(), data.boundingBoxTopRight().lat(), zone);
LtsCoordTrans::UtmCoordinate impactPosPoint(topRight.zone, ((topRight.x + bottomLeft.x) / 2), ((topRight.y + bottomLeft.y) / 2), true);
impactPosPoint.zone = topRight.zone;
QPointF pointGeo = impactPosPoint.geographic();
impactPosition.lon(pointGeo.x());
impactPosition.lat(pointGeo.y());
DEBUG_LOG(m_logger) << "impactPosition lon/lat=" << impactPosition.lon() << "/" << impactPosition.lat()
<< " impactPosPoint.zone" << impactPosPoint.zone
<< " impactPosPoint=" << impactPosPoint.x << "/" << impactPosPoint.y
<< " topRight=" << topRight.x << "/" << topRight.y
<< " bottomLeft" << bottomLeft.x << "/" << bottomLeft.y;
}
Buildings::SendCesHitOnBuildingRequest requestBld(
tmpBldg.buildingId(),
data.chargeStruct().chargeTypeId(),
m_ddsHandler->dtcPdm()->getBuildingChargeEffectByChargeTypeId(data.chargeStruct().chargeTypeId()).destructiveFactor(),
m_ddsHandler->dtcPdm()->getBuildingChargeEffectByChargeTypeId(data.chargeStruct().chargeTypeId()).penetrationFactor(),
data.aesItemId(),
m_ddsHandler->currentPartitionTime(),
impactPosition,
QStringLiteral("properties").toStdString());
DEBUG_LOG(m_logger) << "sendCesHitOnBuildingRequest for aesItemId=" << data.aesItemId()
<< ", impactPosition= " << impactPosition;
m_ddsHandler->ftcBld()->sendCesHitOnBuildingRequest(requestBld, this);
}
}
QVector<int> HandlerAesData::findBuildingsBetween(const LtsCoordTrans::LtsCoordinate &impactPosition,
const CentralEffectSimulation::HandlerBuildingData::Footprint &targetFootprint)
{
QVector<int> buildingIdsInBetween;
// use zone of impactPosition
const LtsCoordTrans::UtmCoordinate &impactPositionUTM = impactPosition.utmCoordinate();
const int zone = impactPositionUTM.zone;
const LtsCoordTrans::LtsCoordinate targetFootprintPos =
LtsCoordTrans::LtsCoordinate::fromUtm(targetFootprint.polyUtm.first(), targetFootprint.zone, 0.0);
DEBUG_LOG(m_logger) << "findBuildingsBetween" << " START impactPosition " << impactPositionUTM.mgrs()
<< ", maybe effected mseId is = " << targetFootprint.mseId
<< " with targetFootprintPos = " << targetFootprintPos.utmCoordinate().mgrs();
// line between a) impactPosition and b) targetFootprintPos
QPolygonF impactToFootprintLineMetric;
impactToFootprintLineMetric.reserve(2);
// // a) impactPosition
// impactToFootprintLineMetric.append(impactPosition.utmCoordinateAsPointF(zone));
// // b) targetFootprintPos
// impactToFootprintLineMetric.append(targetFootprintPos.utmCoordinateAsPointF(zone));
// a) impactPosition
impactToFootprintLineMetric.append(impactPosition.toUtm<QPointF>());
// b) targetFootprintPos
impactToFootprintLineMetric.append(targetFootprintPos.toUtm<QPointF>(zone));
// check all exercise specific footprints except our:
const QHash<int, CentralEffectSimulation::HandlerBuildingData::Footprint> &allFootprintsOfEx = m_handlerBuildingData->getFootprints();
buildingIdsInBetween.reserve(allFootprintsOfEx.size());
for (const CentralEffectSimulation::HandlerBuildingData::Footprint &footprintToCheck : qAsConst(allFootprintsOfEx))
{
// do not check ourself
if (footprintToCheck.mseId == targetFootprint.mseId)
continue;
// check intersection of
// line between a) impactPosition and b) targetFootprintPos
// and footprint
// QPolygonF is your friend :-)
#if QT_VERSION < QT_VERSION_CHECK(5,10,0)
const bool intersects = impactToFootprintLineMetric.intersected(footprintToCheck.polyUtm).size() > 0;
#else
const bool intersects = impactToFootprintLineMetric.intersects(footprintToCheck.polyUtm);
#endif
DEBUG_LOG(m_logger) << "findBuildingsBetween"
<< " to mseId " << footprintToCheck.mseId
<< " with curFpTargetPos " << impactPosition.utmCoordinate().mgrs()
<< " -> intersects = " << intersects;
if (intersects)
{
DEBUG_LOG(m_logger) << "findBuildingsBetween"
<< " regarding impactPosition " << impactPositionUTM.mgrs()
<< " and mseId " << targetFootprint.mseId
<< " is concealed/covered by footpriont of mseId = " << footprintToCheck.mseId;
buildingIdsInBetween.append(footprintToCheck.mseId);
}
} // for
return buildingIdsInBetween;
}
} // namespace CesBuildings
@@ -0,0 +1,139 @@
/**
* Handler for player data
* $Id$
* $HeadURL$
* $Author$
* Created by gr, SLSE, 2017-02-20
*/
#pragma once
#include <CentralEffectSimulation/logger.h>
#include <AreaEffectSimulation/aes_dtc.h>
#include <Buildings/bld_dtc.h>
#include <Buildings/bld_ftc.h>
#include <ProjectDataManagement/pdm_dtc.h>
#include <TrainingAreaBase/tab_ftc.h>
#include <CentralEffectSimulation/dds_handler.h>
#include <CentralEffectSimulation/handler_building_data.h>
#include <CentralEffectSimulation/aes_item_view_utm.h>
#include <LtsCoordinate/lts_coordinate.h>
#include <QtCore/QObject>
#include <QtCore/QMap>
#include <QtCore/QHash>
#include <QtCore/QVector>
#include <QPolygonF>
#include <QTimer>
namespace LtsUtils
{
class QPoint3D;
}
// AES-Handling for buildings
namespace CesBuildings
{
class HandlerAesData : public QObject
, protected Buildings::Interface::Ftc::SendCesHitOnBuildingReplyHandler
, protected Buildings::Interface::Ftc::SendCesHit3DonBuildingReplyHandler
, protected TrainingAreaBase::Interface::Ftc::SendCesHitInformationReplyHandler
, protected Buildings::Interface::Ftc::SetBuildingStatesReplyHandler
{
Q_OBJECT
public:
explicit HandlerAesData(const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler,
const std::shared_ptr<CentralEffectSimulation::HandlerBuildingData> &buildingDataHandler,
QObject *parent = nullptr);
~HandlerAesData();
/**
* Initialize the handler to manage information from player management
*/
bool init();
AreaEffectSimulation::AesItemView itemView(const int &aesId) const { return m_aesItemViews.value(aesId); }
ProjectDataManagement::IgniterFunctionBase igniterFunctionBaseExplosionCluster(const int &aesId) const
{
auto chargeStruct = m_ddsHandler->dtcAes()->explosionCluster(aesId).chargeStruct();
return m_ddsHandler->dtcPdm()->getChargeTypeIgniterTypeIgniterFunction(chargeStruct.chargeTypeId(),
chargeStruct.igniterTypeId(),
chargeStruct.igniterFunctionId()).igniterFunctionBaseId();
}
int chargeTypeId(const int &aesId) const
{
return m_ddsHandler->dtcAes()->explosionCluster(aesId).chargeStruct().chargeTypeId();
}
protected:
void onSendCesHitOnBuildingReply(const Core::FunctionReplyObject &replyObject) override final;
void onSendCesHit3DonBuildingReply(const Core::FunctionReplyObject &replyObject) override final;
void onSendCesHitInformationReply(const Core::FunctionReplyObject &reply) override final;
void onSetBuildingStatesReply(const Core::FunctionReplyObject &reply) override final;
private slots:
/**
* Handle the signals from 'AES'
*/
void onChargeEffectChanged(const AreaEffectSimulation::ChargeEffect &data, DataModification modType);
void onExplosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType);
void onAirSupportImpactChanged(const AreaEffectSimulation::AirSupportImpact &data, DataModification modType);
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType);
void onTriggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType);
void onEffectsChanged(const AreaEffectSimulation::Effects &effects, DataModification modType);
void onBoobyTrapChanged(const AreaEffectSimulation::BoobyTrap &data, DataModification modType);
void onStartTimeReached();
void removeStates(const AreaEffectSimulation::AesItemView &data);
//private: // structs
// typedef QHash<int, QSet<int>> BitfieldStates; shift to aes_item_view_utm.h
private: // methoden
bool inFootprint(const Core::GeoPosition2D &geoPosition,
const CentralEffectSimulation::HandlerBuildingData::Footprint &footPrint,
const double radius) const;
bool inBoundingBox(const Core::GeoPosition2D& impactPosition,
const CentralEffectSimulation::HandlerBuildingData::Footprint &footprint,
const double impactRadius) const;
void preCalculateImpacts(const AreaEffectSimulation::TriggeredImpacts &data);
void calculateImpacts(const AreaEffectSimulation::TriggeredImpacts &data,
const AreaEffectSimulation::AesItemView &aesItemView,
const CentralEffectSimulation::HandlerBuildingData::Footprint &footprint);
void calculateImpacts(const AreaEffectSimulation::Effects &effects,
const CentralEffectSimulation::HandlerBuildingData::Footprint &footprint);
void checkBuildingsHit(const AreaEffectSimulation::AesItemView &data);
QVector<int> findBuildingsBetween(const LtsCoordTrans::LtsCoordinate &impactPosition,
const CentralEffectSimulation::HandlerBuildingData::Footprint &targetFootprint);
void calculateBuildingExplosion(const AreaEffectSimulation::ChargeStruct &chargeStruct, const Core::GeoPosition2D &impactPosition, const int id);
void startTimer(int id, int msec);
private: // attributes
std::shared_ptr<CentralEffectSimulation::DdsHandler> m_ddsHandler; ///< Pointer to VOM DDS handler
std::shared_ptr<CentralEffectSimulation::HandlerBuildingData> m_handlerBuildingData;
QHash<int, CentralEffectSimulation::BitfieldStates> m_bitfieldStatesBld; // key = mseId, value = BitfieldState
// AES-Values
QHash<int, AreaEffectSimulation::AesItemView> m_aesItemViews; // key = aesItemId
QHash<int, CentralEffectSimulation::AesItemViewUtm> m_aesItemViewsUtm; // key = aesItemId
QHash<int, AreaEffectSimulation::AesEffectState> m_explosionSingleState; // key = id value = state
CentralEffectSimulation::LOGGER_T &m_logger; ///< Interface to the Logging-Facility
QHash<int, AreaEffectSimulation::ChargeEffect> m_chargeEffects; // key = onChargeEffectChanged.id value ChargeEffect
};
} // namespace CesBuildings
@@ -0,0 +1,782 @@
/**
* Handler for building models.
* $Id$
* $HeadURL$
* $Author$
* Created by biedziak_f, SLTE, 2021-03-23
*/
#include "handler_building_model.h"
#include <CentralEffectSimulation/logger.h>
#include <float.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QVector3D>
// operator<<
std::ostream &operator<< (std::ostream &stream, const QVector3D &value)
{
stream << "QPointF("
<< QString::number(value.x(), 'f', 6) << "#"
<< QString::number(value.y(), 'f', 6) << "#"
<< QString::number(value.z(), 'f', 6) << "#lenght="
<< QString::number(value.length(), 'f', 6)
<< ")";
return stream;
}
namespace CesBuildings
{
///////////////////////////////////////////////////////////////////////////////////////////////////
// HandlerBuildingModel
//
/*************************************************************************************************
* Ctor, dtor and init *
*************************************************************************************************/
HandlerBuildingModel::HandlerBuildingModel(
const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler, const std::shared_ptr<HandlerAesData> &aesDataHandler, QObject *parent
)
: QObject(parent)
, CentralEffectSimulation::Interface::Fts::GetLineBuildingIntersectionRequestHandler(ddsHandler->ftsCes())
, CentralEffectSimulation::Interface::Fts::GetLineBuildingIntersectsRequestHandler(ddsHandler->ftsCes())
, CentralEffectSimulation::Interface::Fts::DetonationLocationRequestHandler(ddsHandler->ftsCes())
, m_ddsHandler(ddsHandler)
, m_aesDataHandler(aesDataHandler)
, m_logger(CentralEffectSimulation::getLogger("Plugin.Buildings.HandlerBuildingModel"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
HandlerBuildingModel::~HandlerBuildingModel()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool HandlerBuildingModel::init()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
std::shared_ptr<InfrastructureManagement::Interface::Dtc> dtcIsm = m_ddsHandler->dtcIsm();
dtcIsm->waitForHistoricalDataMainStructureElement(1000);
connect(dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
this, &HandlerBuildingModel::onMainStructureElementChanged);
// get:
dtcIsm->mainStructureElements([this](const InfrastructureManagement::MainStructureElement & data)
{
onMainStructureElementChanged(data, DataModification::eAdded);
});
INFO_LOG(m_logger) << "HandlerBuildingModel is running."
<< ", m_buildingModels.size() = " << m_buildingModels.size();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
HandlerBuildingModelInterface::LineBuildingIntersectionResult HandlerBuildingModel::getLineBuildingIntersection(
const std::vector<Core::GeoPosition> &line, const std::string &requestIdOpt)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
CentralEffectSimulation::GetLineBuildingIntersectionRequest newRequest;
newRequest.line(line);
newRequest.requestId(requestIdOpt);
const bool justForLineOfSight = false;
const CentralEffectSimulation::GetLineBuildingIntersectionReply &reply =
getLineBuildingIntersectionInternal(newRequest, justForLineOfSight);
// convert reply to result:
// compare HandlerBuildingModel::getLineBuildingIntersection()
LineBuildingIntersectionResult result;
result.requestId = requestIdOpt;
result.errorString = reply.errorString();
result.errorParams = reply.errorParams();
result.intersection = reply.intersection();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return result;
}
HandlerBuildingModelInterface::LineBuildingIntersectsResult HandlerBuildingModel::getLineBuildingIntersects(const std::vector<Core::GeoPosition> &line, const std::string &requestIdOpt)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
CentralEffectSimulation::GetLineBuildingIntersectionRequest newRequest;
newRequest.line(line);
newRequest.requestId(requestIdOpt);
const bool justForLineOfSight = true;
const CentralEffectSimulation::GetLineBuildingIntersectionReply &reply =
getLineBuildingIntersectionInternal(newRequest, justForLineOfSight);
// convert reply to result:
// compare HandlerBuildingModel::onGetLineBuildingIntersectsRequest()
LineBuildingIntersectsResult result;
result.requestId = requestIdOpt;
result.errorString = reply.errorString();
result.errorParams = reply.errorParams();
result.intersects = ! std::isnan(reply.intersection().lat()); // ! std::isnan
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return result;
}
void HandlerBuildingModel::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data, DataModification modType)
{
const int mseBldgId = data.id();
TRACE_LOG(m_logger) << "MainStructureElement === " << data;
// Always delete m_buildingModels-entry
BuildingModel *buildingModelPtr = m_buildingModels.value((mseBldgId));
delete buildingModelPtr;
m_buildingModels.remove(mseBldgId);
if (modType == DataModification::eRemoved)
{
DEBUG_LOG(m_logger) << "Building not added or modified id=" << mseBldgId;
return;
}
// skip "Outdoor Cameras / Announcement Units"
if (data.structureElementTypeId() != InfrastructureManagement::StructureElementType_def::Building)
return;
// Vor allem in der GUEZ-DB sind ca 23 Gebäude per Hand eingefügt. (Sakralbau, Bahnhof, Wasserwerk etc.)
// Diese tragen die Description "Import von Hand".
// Für diese steht natürlich kein Verwundungsmodell zur Verfügung.
// Wie können wir diese erkennen und hier überspringen?
// Ich habe keine bessere Möglichkeit gefunden als diese:
const Core::GeoPosition &geoPos = data.geoPosition();
if (qFuzzyIsNull(geoPos.z()))
{
INFO_LOG(m_logger) << "BuildingId " << mseBldgId
<< " kann übersprungen werden, da von Hand importiert."
<< ", name: '" << data.name() << "'"
<< ", name: '" << data.description() << "'";
return;
}
const int exerciseId = m_ddsHandler->getExerciseId();
if (m_ddsHandler->dtcIsm()->isElementAssignedToExercise(data, exerciseId))
{
DEBUG_LOG(m_logger) << "BuildingId " << mseBldgId
<< ", in Exercise";
}
else
{
DEBUG_LOG(m_logger) << "BuildingId " << mseBldgId
<< ", not in Exercise";
return;
}
DEBUG_LOG(m_logger) << "HandlerBuildingData::onMainStructureElementChanged() id=" << mseBldgId
<< " properties=" << data.properties();
// const QVector<int> buildingIds = m_ddsHandler->dtcIsm()->getBuildingIdsByExercise(exerciseId);
// const QMap<int, InfrastructureManagement::VulnerabilityModelData> vulnerabilityModelData = m_ddsHandler->dtcIsm()->vulnerabilityModelDatas();
// QMap<int, InfrastructureManagement::VulnerabilityModelData> vulnerabilityModelData;
// InfrastructureManagement::VulnerabilityModelData vulnerabilityModelDataEle;
QByteArray vulnerabilityModelData = m_ddsHandler->dtcIsm()->getVulnerabilityModelData(data.id());
TRACE_LOG(m_logger) << "vulnerabilityModelData=" << vulnerabilityModelData
<< " id=" << data.id();
// int id = -1;
// for (auto vmdIt = vulnerabilityModelData.constBegin(); vmdIt != vulnerabilityModelData.constEnd(); ++vmdIt)
// {
// if (vmdIt.value().mainStructureElementId() == mseBldgId)
// {
// id = vmdIt.key();
// vulnerabilityModelDataEle = m_ddsHandler->dtcIsm()->vulnerabilityModelDatas().value(id);
// break;
// } // if
// } // for
// if (id == -1)
// {
// WARNING_LOG(m_logger) << "Missing VulnerabilityModelData for building " << mseBldgId << ". Skip building.";
// return;
// } // if
const InfrastructureManagement::MainFootprint &mainFootprint = m_ddsHandler->dtcIsm()->getFootprintsByExerciseId(exerciseId).value(mseBldgId);
DEBUG_LOG(m_logger) << "BuildingId " << mseBldgId;
BuildingModel *buildingModel = new BuildingModel(this);
const InfrastructureManagement::MainStructureElement &mse = data;
if (!buildingModel->init(mainFootprint, mse, vulnerabilityModelData, mseBldgId))
{
WARNING_LOG(m_logger) << "Initializing BuildingModel failed for building " << mseBldgId << ". Skipping building.";
return;
}
// if
INFO_LOG(m_logger) << "Inserting BuildingModel for building " << mseBldgId;
m_buildingModels.insert(mseBldgId, buildingModel);
INFO_LOG(m_logger) << "onMainStructureElementChanged: "
<< ", m_buildingModels.size() = " << m_buildingModels.size();
}
//--------------------------------------------------------------------------------------------------
// Intersection handling *
//--------------------------------------------------------------------------------------------------
void HandlerBuildingModel::onGetLineBuildingIntersectionRequest(const rti::core::SampleIdentity &cookie,
const CentralEffectSimulation::GetLineBuildingIntersectionRequest &request)
{
const int exerciseId = m_ddsHandler->getExerciseId();
DEBUG_LOG(m_logger) << "START onGetLineBuildingIntersectionRequest" << ", exerciseId = " << exerciseId << ", request '" << request.requestId() << "'";
const bool justForLineOfSight = false;
const CentralEffectSimulation::GetLineBuildingIntersectionReply &reply = getLineBuildingIntersectionInternal(request, justForLineOfSight);
// sendReply
m_ddsHandler->ftsCes()->getLineBuildingIntersectionReply(cookie, reply);
DEBUG_LOG(m_logger) << "END onGetLineBuildingIntersectionRequest, request '" << request.requestId() << "'";
}
void HandlerBuildingModel::onGetLineBuildingIntersectsRequest(const rti::core::SampleIdentity &cookie,
const CentralEffectSimulation::GetLineBuildingIntersectsRequest &request)
{
const int exerciseId = m_ddsHandler->getExerciseId();
DEBUG_LOG(m_logger) << "START onGetLineBuildingIntersectsRequest" << ", exerciseId = " << exerciseId << ", request '" << request.requestId() << "'";
CentralEffectSimulation::GetLineBuildingIntersectionRequest newRequest;
newRequest.line(request.line());
newRequest.requestId(request.requestId());
const bool justForLineOfSight = true;
const CentralEffectSimulation::GetLineBuildingIntersectionReply &reply = getLineBuildingIntersectionInternal(newRequest, justForLineOfSight);
// sendReply
CentralEffectSimulation::GetLineBuildingIntersectsReply newReply;
newReply.id(reply.id());
newReply.errorString(reply.errorString());
newReply.errorParams(reply.errorParams());
newReply.requestId(reply.requestId());
newReply.intersects(! std::isnan(reply.intersection().lat())); // ! std::isnan
m_ddsHandler->ftsCes()->getLineBuildingIntersectsReply(cookie, newReply);
DEBUG_LOG(m_logger) << "END onGetLineBuildingIntersectsRequest, request '" << request.requestId() << "'";
}
//LtsUtils::QPoint3D set_zValueToIfNegative(const LtsUtils::QPoint3D &pnt, double newZValue = 0.1)
//{
// return LtsUtils::QPoint3D(pnt.x(),
// pnt.y(),
// (pnt.z() > 0) ? pnt.z() : newZValue);
//}
CentralEffectSimulation::GetLineBuildingIntersectionReply HandlerBuildingModel::getLineBuildingIntersectionInternal(const CentralEffectSimulation::GetLineBuildingIntersectionRequest &request,
bool justForLineOfSight,
int *buildingIdOut,
int *segmentIdxOfIntersectionPtrOut) const
{
static Core::GeoPosition s_invalidPos(std::nan(""), std::nan(""), std::nan(""));
const int exerciseId = m_ddsHandler->getExerciseId();
DEBUG_LOG(m_logger) << "START getLineBuildingIntersectionInternal" << ", exerciseId = " << exerciseId << ", request '" << request.requestId() << "'"
<< ", request.line().size() = " << request.line().size();
CentralEffectSimulation::GetLineBuildingIntersectionReply reply;
reply.requestId(request.requestId());
// prepare invalid 'answer'
reply.intersection(s_invalidPos);
// empty (poly-)line
// (think of a trajectory)
const std::vector<Core::GeoPosition> &polylineRef = request.line();
if (polylineRef.size() < 2)
{
reply.errorString("insufficiant number of points");
WARNING_LOG(m_logger) << "getLineBuildingIntersectionInternal" << ", exerciseId = " << exerciseId << ", request '" << request.requestId() << "'"
<< ", error: '" << reply.errorString() << "'";
return reply;
}
QPolygonF polygon2D;
polygon2D.reserve(polylineRef.size());
for (const Core::GeoPosition &geoPos : qAsConst(polylineRef))
polygon2D << QPointF(geoPos.lon(), geoPos.lat());
// Only the buildings where the line/trajectory flies over the building footprint are taken into account.
bool completeEnclosed = false;
bool isGroundLevel = false;
const QVector<int> &relevantBuildings = m_ddsHandler->dtcIsm()->getBuildingByPolygon(exerciseId, polygon2D, completeEnclosed, isGroundLevel);
if (m_logger.isDebugEnabled())
{
DEBUG_LOG(m_logger) << "relevantBuildings.size=" << relevantBuildings.size();
for (const int bldgId : qAsConst(relevantBuildings))
DEBUG_LOG(m_logger) << "relevantBuilding: bldgId = " << bldgId;
}
double distance = DBL_MAX;
uint lineSegmentIdx = 0;
//---------------------
// We need to iterate over all items.
// But we need access to current and also successor item!
// If we like to avoid index operator, we can use following approach:
//
// iterate over all items, !!! BUT ONE !!!
// for (lineIt = polylineRef.begin(); lineIt != polylineRef.end()-1; )
// {
// // Copy...
// const Core::GeoPosition segStart = *lineIt;
// // ...increment and ref
// const Core::GeoPosition &segEnd = *(++lineIt);
// ...
//---------------------
// but we prefer index operator here, because in total is better:
// less copying of GeoPosition, iterator etc.
//---------------------
for (lineSegmentIdx = 0; lineSegmentIdx < polylineRef.size() - 1; ++lineSegmentIdx)
{
const Core::GeoPosition &segStart = polylineRef[lineSegmentIdx];
const Core::GeoPosition &segEnd = polylineRef[lineSegmentIdx + 1];
DEBUG_LOG(m_logger) << " lineSegmentIdx=" << lineSegmentIdx
<< ", start=" << segStart
<< " , end=" << segEnd;
int buildingId = -1; // for debugging purposes
//for (BuildingModel *buildingModel : qAsConst(m_buildingModels))
for (const int bldgId : qAsConst(relevantBuildings))
{
BuildingModel *buildingModel = m_buildingModels.value(bldgId, nullptr);
if (!buildingModel)
{
WARNING_LOG(m_logger) << " buildingModel not found, bldgId=" << bldgId;
continue;
}
DEBUG_LOG(m_logger) << " buildingModel->buildingId=" << buildingModel->buildingId()
<< " , HEIGHT = " << buildingModel-> height();
// skip buildingModel, if damaged (>80%)
auto dtcBld = m_ddsHandler->dtcBld();
dtcBld->enableBuildingState();
const Buildings::BuildingState &buildingState = dtcBld->buildingState(bldgId);
// if buildingState is not found, assume intact:
if (/*(buildingState.id() == bldgId) && */(buildingState.damagePercent() >= 80))
{
WARNING_LOG(m_logger) << " buildingModel->buildingId=" << buildingModel->buildingId()
<< ", lineSegmentIdx=" << lineSegmentIdx
<< ", damagePercent > 80% (" << buildingState.damagePercent() << ")";
continue;
}
// Do NOT
// Do NOT
// Do NOT
// Note:
// Imagine following situation:
// ______
// | |
// | Bldg |
// | |
// ----------
// * ---/ ------ o
// ---/ --------- Surface / BaseSurface / Soil
// * = Impact / Detonation
// o = Player
// In that case, no intersection will re recognized :-(
// To avoid this, lift zValue on building level by using set_zValueToIfNegative
// positions in the building's coordinate system in [m] (distance from reference position)
// const LtsUtils::QPoint3D &relStart = set_zValueToIfNegative(buildingModel->fromGeographic(segStart), 0.1); // lift / lift_zValueToIfNegative
// const LtsUtils::QPoint3D &relEnd = set_zValueToIfNegative(buildingModel->fromGeographic(segEnd), 0.1); // lift / lift_zValueToIfNegative
// Do NOT
// GUEZE-3166:
// in case of U_BAHN, segStart and segEnd really have negative values.
// It will lead to false results, if set_zValueToIfNegative is executed.
// In the meantime, lineOfSightElevation is introduced.
// Aceept the situation drawn above and assume, that lineOfSightElevation will do it.
// Do NOT
// Do NOT
const LtsUtils::QPoint3D &relStart = buildingModel->fromGeographic(segStart); // lift / lift_zValueToIfNegative
const LtsUtils::QPoint3D &relEnd = buildingModel->fromGeographic(segEnd); // lift / lift_zValueToIfNegative
DEBUG_LOG(m_logger) << " buildingModel->buildingId=" << buildingModel->buildingId()
<< ", lineSegmentIdx=" << lineSegmentIdx;
DEBUG_LOG(m_logger) << " segStart=" << segStart << " relStart=" << relStart;
DEBUG_LOG(m_logger) << " segEnd =" << segEnd << " relEnd=" << relEnd;
if (!buildingModel->hasIntersectionSimplified(relStart, relEnd)) // check height and footprint
continue;
DEBUG_LOG(m_logger) << " buildingModel->buildingId=" << buildingModel->buildingId()
<< ", lineSegmentIdx=" << lineSegmentIdx
<< ", hasIntersectionSimplified was true";
const Core::GeoPosition &intersection = buildingModel->intersection(relStart, relEnd); // assume intersection and calculate
DEBUG_LOG(m_logger) << " buildingModel->buildingId=" << buildingModel->buildingId()
<< ", lineSegmentIdx=" << lineSegmentIdx
<< ", intersection = " << intersection;
if (!BuildingModel::isValid(intersection)) // no intersection
continue;
DEBUG_LOG(m_logger) << " buildingModel->buildingId=" << buildingModel->buildingId()
<< ", lineSegmentIdx=" << lineSegmentIdx
<< ", has valid intersection = " << intersection;
if (buildingIdOut)
*buildingIdOut = buildingModel->buildingId();
// justForLineOfSight :
if (justForLineOfSight)
{
reply.intersection(intersection);
DEBUG_LOG(m_logger) << "END getLineBuildingIntersectionInternal, return due to justForLineOfSight " << request.requestId() << "'";
return reply;
}
// : justForLineOfSight
const double dist = (relStart - buildingModel->fromGeographic(intersection)).length(); // distance to start of segment
if (dist < distance) // new intersection is closer than the last one
{
if (buildingId == -1) // first intersection found
DEBUG_LOG(m_logger) << "Building " << buildingModel->buildingId() << " was hit.";
else // this building "covers" the last one found
DEBUG_LOG(m_logger) << "Building " << buildingModel->buildingId() << " was hit prior to building " << buildingId << ".";
buildingId = buildingModel->buildingId();
distance = dist;
reply.intersection(intersection);
if (segmentIdxOfIntersectionPtrOut)
*segmentIdxOfIntersectionPtrOut = lineSegmentIdx;
} // if
} // for (const int bldgId : qAsConst(relevantBuildings))
} // for(lineIt = polylineRef.begin(); lineIt != polylineRef.end()-1; ++lineIt)
DEBUG_LOG(m_logger) << "END getLineBuildingIntersectionInternal, request '" << request.requestId() << "'"
<< " buildingIdOut=" << *buildingIdOut;
return reply;
}
//--------------------------------------------------------------------------------------------------
// DetonationLocationRequest handling *
//--------------------------------------------------------------------------------------------------
void HandlerBuildingModel::onDetonationLocationRequest(
const rti::core::SampleIdentity &cookie, const CentralEffectSimulation::DetonationLocationRequest &request
)
{
DEBUG_LOG(m_logger) << "Received DetonationLocationRequest for aesId: " << request.id();
const CentralEffectSimulation::DetonationLocationReply reply = handleDetonationLocationRequest(request);
if (!reply.errorString().empty())
WARNING_LOG(m_logger) << "DetonationLocationRequest for aesId " << request.id() << " failed: " << reply.errorString();
// if
m_ddsHandler->ftsCes()->detonationLocationReply(cookie, reply);
}
CentralEffectSimulation::DetonationLocationReply HandlerBuildingModel::handleDetonationLocationRequest(const CentralEffectSimulation::DetonationLocationRequest &request) const
{
const int exerciseId = m_ddsHandler->getExerciseId();
DEBUG_LOG(m_logger) << " handleDetonationLocationRequest request=" << request
<< ", m_buildingModels.size() = " << m_buildingModels.size();
// AES::
// ExplosionCluster most likely has serveral impacts and therefore several trajectories.
// To differentiate between them, 'explosionIndex' is used (starting with 0)
// CES:
// To differentiate between a) explosionIndex and b) trajectoryIdx (segmentIdx)
// const int explosionIndex = request.index();
// prepare reply and store some values from request:
CentralEffectSimulation::DetonationLocationReply reply;
reply.id(request.id()); // AES: aesItemId
reply.index(request.index()); // AES: explosionIndex
if ( m_buildingModels.size() <= 0)
return reply;
CentralEffectSimulation::GetLineBuildingIntersectionRequest lbRequest;
lbRequest.requestId("handleDetonationLocationRequest");
lbRequest.line(request.trajectory());
const std::vector<Core::GeoPosition>& reqTrajRef = request.trajectory();
if (reqTrajRef.size() < 2)
{
ERROR_LOG(m_logger) << " handleDetonationLocationRequest request.trajectory() invalid, size =" << reqTrajRef.size();
return reply;
}
// next step: determine detonationDistance according fuseType:
double detonationDistance = 0;
ProjectDataManagement::IgniterFunctionBase ignFuncBase = m_ddsHandler->getIgniterFunctionBaseFromChargeTypeId(request.chargeTypeId(),
request.igniterTypeId(),
request.igniterFunctionId());
switch (ignFuncBase.underlying())
{
case ProjectDataManagement::IgniterFunctionBase::IfbProximity: detonationDistance = -5; break;
case ProjectDataManagement::IgniterFunctionBase::IfbImpact: detonationDistance = 0; break;
case ProjectDataManagement::IgniterFunctionBase::IfbDelay: detonationDistance = 5; break;
default:
// empty
break;
} // switch
// next step: find bldgIntersection
const bool justForLineOfSight = false;
int validSizeOfOriginalTraj = -1;
int buildingId = -1;
const CentralEffectSimulation::GetLineBuildingIntersectionReply &lbiReply =
getLineBuildingIntersectionInternal(lbRequest, justForLineOfSight, &buildingId, &validSizeOfOriginalTraj);
const LtsCoordTrans::LtsCoordinate bldgIntersectionCoord(lbiReply.intersection());
const bool bHasBuildingIntersection = BuildingModel::isValid(bldgIntersectionCoord.geoPosition());
if (bHasBuildingIntersection)
{
DEBUG_LOG(m_logger) << "RESULT: Trajectory: hasBuildingIntersection YES, at: " << bldgIntersectionCoord.mgrs()
<< " buildingId=" << buildingId;
}
else
{
DEBUG_LOG(m_logger) << "RESULT: Trajectory: hasBuildingIntersection NO";
const bool bIsInTrainingOrCentralArea = true;
if (bIsInTrainingOrCentralArea)
{
DEBUG_LOG(m_logger) << "RESULT: integrate free area...";
// free area and FuseType_def::IfbDelay:
// We can´t move the detonation point _below_ the surface.
// That would be identical to a neagative 'startHat'
// In other words: lineOfSightElevation would deliver LineOfSight::LOS_ERROR
// so:
if (detonationDistance > 0) // detonationDistance > 0 === FuseType_def::IfbDelay
detonationDistance = 0;
}
} // if (bHasBuildingIntersection)
// next step: integrate detonationDistance into trajectory to find the final detonationLocation:
// !!! assume that the requested trajectory ends directly on the ground !!!
LtsCoordTrans::LtsCoordinate detonationLocation;
if (bHasBuildingIntersection)
detonationLocation = bldgIntersectionCoord;
else
detonationLocation = LtsCoordTrans::LtsCoordinate(reqTrajRef.back());
// do we really have to do any calculations?
if (qFuzzyIsNull(detonationDistance)) // depends on 'FuseType'
{
if (!bHasBuildingIntersection)
{
DEBUG_LOG(m_logger) << "detonationLocation on ground" << detonationLocation.geoPosition()
<< std::fixed << std::setprecision(3)
<< ", heightOverElevation = " << detonationLocation.heightOverElevation();
Q_ASSERT_X(std::fabs(detonationLocation.heightOverElevation()) < 1.0, "handleDetonationLocationRequest", "heightOverElevation is to high");
}
DEBUG_LOG(m_logger) << "Trajectory bAdjusted/bHasBuildingIntersection: " << bHasBuildingIntersection
<< ", igniterFunctionBase: " << ignFuncBase
<< ", detonationDistance: " << detonationDistance
<< ", reqTrajRef.size():" << reqTrajRef.size() << " back: " << reqTrajRef.back()
<< ", detonationLocation: " << detonationLocation.toString(true)
<< ", buildingId: " << buildingId;
reply.position(detonationLocation.geoPosition());
reply.buildingId(buildingId);
}
else
{
// DetonationLocation
// instead of backtrackTrajectory(), use simply resize and push_back(bldgIntersectionCoord)
std::vector<Core::GeoPosition> trajectoryCopy = reqTrajRef;
DEBUG_LOG(m_logger) << "validSizeOfOriginalTraj is below zero: " << validSizeOfOriginalTraj << ", exerciseId " << exerciseId << ", buildingId=" << buildingId;
// in case of hasBuildingIntersection
if (validSizeOfOriginalTraj > 0)
{
trajectoryCopy.resize(validSizeOfOriginalTraj);
trajectoryCopy.push_back(bldgIntersectionCoord.geoPosition());
}
// adjust detonationLocation by taking detonationDistance (!= 0) into account:
detonationLocation = LtsCoordTrans::LtsCoordinate(calculateDetonationLocation(trajectoryCopy, detonationDistance));
DEBUG_LOG(m_logger) << "Trajectory bAdjusted/bHasBuildingIntersection: " << bHasBuildingIntersection
<< ", igniterFunctionBase: " << ignFuncBase
<< ", detonationDistance: " << detonationDistance
<< ", trajectoryCopy.size()=" << trajectoryCopy.size() << " back: " << trajectoryCopy.back()
<< ", detonationLocation: " << detonationLocation.toString(true)
<< ", buildingId: " << buildingId;
reply.buildingId(buildingId);
reply.position(detonationLocation.geoPosition());
}
// otherwise let reply.position be untouched.
return reply;
}
Core::GeoPosition HandlerBuildingModel::calculateDetonationLocation(const std::vector<Core::GeoPosition> &trajectoryGeometry, double detonationDistance) const
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
const int geometrySize = trajectoryGeometry.size();
if (geometrySize < 3)
{
ERROR_LOG(m_logger) << LOGFUNCTION << ", trajectoryGeometry not sufficiant";
return {};
}
// Z-Werte - absolute
// geometrySize-3]; - see comment below
// ^^^
auto p1 = trajectoryGeometry[geometrySize - 3];
LtsCoordTrans::UtmCoordinate utm1 = LtsCoordTrans::UtmCoordinate::fromGeographic(p1.lon(), p1.lat()); // ToDo: Zone des Bldgs?
QVector3D segStart(utm1.x, utm1.y, p1.z());
auto p2 = trajectoryGeometry[geometrySize - 1];
LtsCoordTrans::UtmCoordinate utm2 = LtsCoordTrans::UtmCoordinate::fromGeographic(p2.lon(), p2.lat()); // ToDo: Zone des Bldgs?
QVector3D segEnd(utm2.x, utm2.y, p2.z());
QVector3D flightVec = segEnd - segStart;
INFO_LOG(m_logger) << "flightVec1 "
<< ", utm1 " << utm1 << " , z " << p1.z()
<< ", utm2 " << utm2 << " , z " << p2.z()
<< ", flightVec " << flightVec;
// 'auto p1 = trajectoryGeometry[geometrySize-3];'
// ^^^
// Sometime the flightVec has a very small component, so it becomes zero and scaling to 5m will fail:
// 2023-12-15 16:01:59.879 INFO CES::HandlerBuildingModel |#| Core::GeoPosition CesBuildings::HandlerBuildingModel::calculateDetonationLocation(const std::vector<Core::GeoPosition>&, double) const START (ation/Plugins/Buildings/handler_building_model.cpp:279)
// 2023-12-15 16:01:59.879 ERROR CES::HandlerBuildingModel |#|
// flightVec1 ,
// utm1 UtmCoordinate(676943.27#5818641.5 zone=32) , z 98.19423,
// utm2 UtmCoordinate(676943.29#5818641.7 zone=32) , z 98.072554,
// flightVec QPointF(0.062500#0.000000#-0.121674#lenght=0.136787) (ation/Plugins/Buildings/handler_building_model.cpp:299)
// ^^^^^^^^
// 2023-12-15 16:01:59.879 ERROR CES::HandlerBuildingModel |#| flightVec2 ,
// utm1 UtmCoordinate(676943.27#5818641.5 zone=32) , z 98.19423,
// utm2 UtmCoordinate(676943.29#5818641.7 zone=32) , z 98.072554,
// flightVec QPointF(2.284572#0.000000#-4.447553#lenght=5.000000), detonationLoc
// ^^^^^^^^
// scale:
const int distanceMeter = std::fabs(detonationDistance); // meter
flightVec *= distanceMeter / flightVec.length();
// now put on impactPositon;
QVector3D detonationLoc;
if (detonationDistance > 0) // Delay
detonationLoc = segEnd + flightVec; // 'extend'
else
detonationLoc = segEnd - flightVec; // 'reduce'
LtsCoordTrans::UtmCoordinate utmDeto(utm1.zone, detonationLoc.x(), detonationLoc.y());
const QPointF &pointDeto = utmDeto.geographic();
Core::GeoPosition geoPosDeto(pointDeto.x(), pointDeto.y(), detonationLoc.z());
DEBUG_LOG(m_logger) << "flightVec2 "
<< ", utm1 " << utm1 << " , z " << p1.z()
<< ", utm2 " << utm2 << " , z " << p2.z()
<< ", flightVec " << flightVec
<< ", detonationLoc " << detonationLoc
<< ", utmDeto " << utmDeto;
return geoPosDeto;
}
/*
Core::GeoPosition HandlerBuildingModel::backtrackTrajectory(const std::vector<Core::GeoPosition> &trajectory,
const Core::GeoPosition &position,
double distancePerSegment) const
{
Core::GeoPosition startGeo = position;
LtsCoordTrans::UtmCoordinate startUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(position.lon(), position.lat());
LtsUtils::QPoint3D start(startUtm.x, startUtm.y, position.z());
double res = distancePerSegment;
for (int i = trajectory.size() - 1; i > 0; --i)
{
const Core::GeoPosition &segmentStartGeo = trajectory[i];
const Core::GeoPosition &segmentEndGeo = trajectory[i - 1];
const LtsCoordTrans::UtmCoordinate segmentStartUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(segmentStartGeo.lon(), segmentStartGeo.lat());
const LtsCoordTrans::UtmCoordinate segmentEndUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(segmentEndGeo.lon(), segmentEndGeo.lat());
const LtsUtils::QPoint3D segmentStart(segmentStartUtm.x, segmentStartUtm.y, segmentStartGeo.z());
const LtsUtils::QPoint3D segmentEnd(segmentEndUtm.x, segmentEndUtm.y, segmentEndGeo.z());
const LtsUtils::QPoint3D direction = (segmentEnd - segmentStart).normalized();
if (LtsUtils::QPoint3D::dotProduct(start - segmentEnd, direction) > (segmentEnd - segmentStart).length()) // start is in a different trajectory segment
continue;
const double length = (start - segmentEnd).length();
if (length < res) // continue to next segment
{
res -= length;
start = segmentEnd;
continue;
} // if
start += res * direction;
startUtm.x = start.x();
startUtm.y = start.y();
const QPointF lonLat = startUtm.geographic();
startGeo.lon(lonLat.x());
startGeo.lat(lonLat.y());
startGeo.z(start.z());
return startGeo;
} // for
WARNING_LOG(m_logger) << "Backtracing trajectory for proximity fuse type failed.";
return startGeo;
}
*/
} // namespace CesBuildings
@@ -0,0 +1,118 @@
/**
* Handler for building models.
* $Id$
* $HeadURL$
* $Author$
* Created by biedziak_f, SLTE, 2021-03-23
*/
#pragma once
#include "ces_building_model.h"
#include "handler_aes_data.h"
// for interface
#include "../../proxy_building.h"
#include <CentralEffectSimulation/dds_handler.h>
#include <QObject>
#include <QMap>
namespace NGL
{
class INGLLogger;
}
namespace CesBuildings
{
///////////////////////////////////////////////////////////////////////////////////////////////////
// HandlerBuildingModel
//
/**
* @brief The HandlerBuildingModel class contains building and rooms geometry in detail.
* Based on that LineOfSight operations could be offered.
*/
class HandlerBuildingModel final
: public QObject
, public HandlerBuildingModelInterface
, protected CentralEffectSimulation::Interface::Fts::GetLineBuildingIntersectionRequestHandler
, protected CentralEffectSimulation::Interface::Fts::GetLineBuildingIntersectsRequestHandler
, protected CentralEffectSimulation::Interface::Fts::DetonationLocationRequestHandler
{
Q_OBJECT
public:
explicit HandlerBuildingModel(
const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler, const std::shared_ptr<HandlerAesData> &aesDataHandler, QObject *parent = nullptr
);
~HandlerBuildingModel();
bool init();
const QMap<int, BuildingModel *> &buildingModels() const { return m_buildingModels; }
/*! \name implementation of synchron calls of HandlerBuildingModel - LineOfSight etc*/
//@{
///< LineOfSight: find exact intersection
LineBuildingIntersectionResult getLineBuildingIntersection(const std::vector<Core::GeoPosition> &line,
const std::string &requestIdOpt = {}) override;
///< LineOfSight: find if lingOfSight is given or not
LineBuildingIntersectsResult getLineBuildingIntersects(const std::vector<Core::GeoPosition> &line,
const std::string &requestIdOpt = {}) override;
//@}
protected:
///< LineOfSight: find exact intersection
void onGetLineBuildingIntersectionRequest(const rti::core::SampleIdentity &cookie, const CentralEffectSimulation::GetLineBuildingIntersectionRequest &request) override final;
///< LineOfSight: find if lingOfSight is given or not
void onGetLineBuildingIntersectsRequest(const rti::core::SampleIdentity &cookie, const CentralEffectSimulation::GetLineBuildingIntersectsRequest &request) override final;
///< special request for AreaEffectSimulation
void onDetonationLocationRequest(const rti::core::SampleIdentity &cookie, const CentralEffectSimulation::DetonationLocationRequest &request) override final;
private Q_SLOTS:
/**
* Handle MainStructureElement from 'ISM'
*/
void onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data, DataModification modType);
private:
/*!
* \brief getLineBuildingIntersectionInternal
* \param request more or less genral request
* \param justForLineOfSight stop on first intersection or find exact intersection?
* \param segmentIdxOfIntersectionPtrOut intersection of intersection
* \return reply
*/
CentralEffectSimulation::GetLineBuildingIntersectionReply getLineBuildingIntersectionInternal(const CentralEffectSimulation::GetLineBuildingIntersectionRequest &request,
bool justForLineOfSight = false,
int *buildingIdOut = nullptr,
int *segmentIdxOfIntersectionPtrOut = nullptr
) const;
///< special request for AreaEffectSimulation
CentralEffectSimulation::DetonationLocationReply handleDetonationLocationRequest(const CentralEffectSimulation::DetonationLocationRequest &request) const;
Core::GeoPosition calculateDetonationLocation(const std::vector<Core::GeoPosition> &trajectoryGeometry, double detonationDistance) const;
private:
std::shared_ptr<CentralEffectSimulation::DdsHandler> m_ddsHandler;
std::shared_ptr<HandlerAesData> m_aesDataHandler;
QMap<int, BuildingModel *> m_buildingModels; // key = buildingId
CentralEffectSimulation::LOGGER_T m_logger;
}; // class HandlerBuildingModel
} // namespace CesBuildings
@@ -0,0 +1,413 @@
/**
* Handler for player data
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2017-02-20
*/
#include "handler_building_ownership.h"
#include <LtsCoordTrans/lts_coord_trans.h>
#include <ngldb/dbtransaction.h>
#include <QJsonDocument>
#include <QJsonObject>
namespace CesBuildings
{
HandlerBuildingOwnership::HandlerBuildingOwnership(const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler,
const std::shared_ptr<CentralEffectSimulation::HandlerParticipant> &participantHandler,
const std::shared_ptr<CentralEffectSimulation::HandlerBuildingData> &buildingDataHandler,
const std::shared_ptr<CentralEffectSimulation::DatabaseInterface> &db,
QObject *parent)
: QObject(parent)
, SetOwnershipRequestHandler(ddsHandler->ftsCes())
, m_ddsHandler(ddsHandler)
, m_handlerParticipant(participantHandler)
, m_handlerBuildingData(buildingDataHandler)
, m_db(db)
, m_logger(CentralEffectSimulation::getLogger("Plugin.Buildings.HandlerBuildingOwnership"))
{
INFO_LOG(m_logger) << "HandlerBuildingOwnership::HandlerBuildingOwnership";
} // end of ctor()
//-----------------------------------------------------------------------------
HandlerBuildingOwnership::~HandlerBuildingOwnership()
{
} // end of dtor()
//-----------------------------------------------------------------------------
bool HandlerBuildingOwnership::init()
{
INFO_LOG(m_logger) << "HandlerBuildingOwnership::init";
auto dtcIsm = m_ddsHandler->dtcIsm();
DEBUG_LOG(m_logger) << "init";
loadOwnershipsFromDb();
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::newOutdoorPosition,
this, &HandlerBuildingOwnership::onParticipantPositionChanged);
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::newIndoorPosition,
this, &HandlerBuildingOwnership::onParticipantPositionChanged);
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::newNotfightMode,
this, &HandlerBuildingOwnership::onParticipantPositionChanged);
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::participantLeavesBuilding,
this, &HandlerBuildingOwnership::onParticipantLeavesBuilding);
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::newParticipantState,
this, &HandlerBuildingOwnership::onParticipantPositionChanged);
dtcIsm->waitForHistoricalDataMainStructureElement(1000);
connect(dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
this, &HandlerBuildingOwnership::onMainStructureElementChanged);
// Get 'static' data for all MainStructureElements
{
auto cb = [this](const InfrastructureManagement::MainStructureElement & mse)
{
onMainStructureElementChanged(mse, DataModification::eAdded);
};
if (!dtcIsm->mainStructureElements(cb))
return false;
}
return true;
} // end of init()
//-----------------------------------------------------------------------------
// ///////////////////////////////////
// B L D (Buildings)
// ///////////////////////////////////
void HandlerBuildingOwnership::onSetOwnershipRequest(const rti::core::SampleIdentity &cookie,
const CentralEffectSimulation::SetOwnershipRequest &request)
{
INFO_LOG(m_logger) << "onSetOwnershipRequest: " << request;
// remove Ownership, if partyId == 0
if (request.partyId() == 0)
removeFromDbBuildingId(request.buildingId());
const QVector<int> floors = m_handlerBuildingData->getFloorsFromBuilding(request.buildingId());
for (int floorId : floors)
saveBuildingOwnership(floorId, request.partyId(), request.buildingId());
if (!floors.isEmpty())
sendBuildingOwnership(request.buildingId());
m_ddsHandler->ftsCes()->setOwnershipReply(cookie, Core::FunctionReplyObject(request.buildingId()));
}
void HandlerBuildingOwnership::onParticipantPositionChanged(const CentralEffectSimulation::HandlerParticipant::CesParticipantData &partPos)
{
const int participantId = partPos.participantId();
INFO_LOG(m_logger) << "BuildingOwnership onParticipantPositionChanged participantId=" << participantId
<< " vulnerabilityState=" << partPos.vulnerabilityState
<< " buildingId=" << partPos.buildingId()
<< " notfightMode=" << partPos.notfightMode;
// [GUEZE-2256] 3D Wirksim - Funktionsraum Nicht Kampffaehig
// Teilnehmer, die den Status Nicht Kampffaehig haben, düfen nicht bei der Berechnung des Gebaeudebesitzes beruecksichtigt werden.
if (partPos.notfightMode)
return;
int floorId = m_handlerBuildingData->getFloorIdFromRoomId(partPos.roomId());
if (partPos.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::CatastrophicKill)
m_participantFloor.remove(participantId);
else
m_participantFloor.insert(participantId, floorId);
int newOwnership = calculateOwnershipByParticipantId(participantId);
checkAndSendOwnership(newOwnership, floorId);
INFO_LOG(m_logger) << "END BuildingOwnership onParticipantPositionChanged participantId=" << participantId
<< " vulnerabilityState=" << partPos.vulnerabilityState;
} // end of onParticipantPositionChanged()
// ///////////////////////////////////
// I S M (InfrastructureManagement)
// ///////////////////////////////////
void HandlerBuildingOwnership::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data, DataModification modType)
{
INFO_LOG(m_logger) << "onMainStructureElementChanged id=" << data.id()
<< " modelId =" << data.modelId();
if (modType == DataModification::eRemoved || data.modelId() <= 0)
{
m_buildingOwnership.remove(data.id());
return;
}
QJsonArray jsonArray = QJsonDocument::fromJson(QByteArray::fromStdString(data.properties())).object().value(QLatin1String("available_in_exercise")).toArray();
DEBUG_LOG(m_logger) << "available_in_exercise jsonDocument.size()=" << jsonArray.size();
QVector<int> result;
result.reserve(jsonArray.size());
// Check if present in the current exercise and remove
if (m_buildingOwnership.contains(data.id()))
{
int id = data.id();
m_buildingOwnership.remove(id);
m_ddsHandler->dtsCes()->removeBuildingOwnershipByKey(id);
}
for (auto it = jsonArray.constBegin(); it != jsonArray.constEnd(); ++it)
{
DEBUG_LOG(m_logger) << "available_in_exercise jsonDocument=" << it->toInt();
if (m_ddsHandler->getExerciseId() != it->toInt())
continue;
DEBUG_LOG(m_logger) << "Got MainStructureElement"
<< " data.id()=" << data.id()
<< " data.modelId=" << data.modelId();
if (!m_buildingOwnership.contains(data.id()))
{
// insert in m_buildingOwnership and publish to dds
CentralEffectSimulation::BuildingOwnership bo;
bo.buildingId(data.id());
bo.sampleTime(QDateTime::currentMSecsSinceEpoch());
updateOwnerships(&bo);
m_buildingOwnership.insert(data.id(), bo);
m_ddsHandler->dtsCes()->publish(bo);
} // if
} // for
}
void HandlerBuildingOwnership::onParticipantLeavesBuilding(const int participantId)
{
INFO_LOG(m_logger) << "BuildingOwnership onParticipantLeavesBuilding participantId=" << participantId;
auto it = m_participantFloor.find(participantId);
if (it == m_participantFloor.end())
return;
m_participantFloor.erase(it);
const int floorId = it.value();
const int newOwnership = calculateOwnershipByFloorId(floorId);
DEBUG_LOG(m_logger) << "newOwnership=" << newOwnership;
if (newOwnership > 0)
checkAndSendOwnership(newOwnership, floorId);
} // end of onParticipantLeavesBuilding()
int HandlerBuildingOwnership::calculateOwnershipByParticipantId(const int participantId)
{
INFO_LOG(m_logger) << "BuildingOwnership calculateOwnershipByParticipantId participantId=" << participantId;
CentralEffectSimulation::HandlerParticipant::CesParticipantData partPos = m_handlerParticipant->position(participantId);
return calculateOwnershipByFloorId(m_handlerBuildingData->getFloorIdFromRoomId(partPos.roomId()));
}
int HandlerBuildingOwnership::calculateOwnershipByFloorId(const int floorId)
{
INFO_LOG(m_logger) << "BuildingOwnership calculateOwnershipByFloorId floorId=" << floorId;
int ownership = -1;
if (floorId == -1)
return ownership;
DEBUG_LOG(m_logger) << "calculateOwnership floorId = " << floorId;
QHash <int, int> partyCount; // key = Party, value= Count of Participants;
// Suche alle Participants in der Etage
for (auto it = m_participantFloor.cbegin(); it != m_participantFloor.cend(); ++it)
{
int iteratorFloor = it.value();
int iteratorParticipant = it.key();
if (floorId == iteratorFloor)
{
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &localPartPos = m_handlerParticipant->position(iteratorParticipant);
if (localPartPos.vulnerabilityState == ProjectDataManagement::VulnerabilityState::CatastrophicKill)
continue; // Don't count participants with catastrophic Kill
const int partyId = localPartPos.partyId();
++partyCount[partyId];
}
}
// berechne daraus die Farbe der Partei
int countParty = 0;
for (auto it = partyCount.begin(); it != partyCount.end(); ++it)
{
if (it.value() > countParty)
{
countParty = it.value();
ownership = it.key();
}
}
return ownership;
}
int HandlerBuildingOwnership::getOwnership(int buildingId, int floorId) const
{
INFO_LOG(m_logger) << "BuildingOwnership getOwnership buildingId=" << buildingId
<< " floorId=" << floorId;
auto itBldg = m_buildingOwnership.find(buildingId);
if (itBldg == m_buildingOwnership.end())
return -1;
const CentralEffectSimulation::BuildingOwnership &bo = itBldg.value();
for (const CentralEffectSimulation::Ownership &ownership : bo.ownerships())
{
if (ownership.floorId() == floorId)
return ownership.partyId();
}
return -1;
}
void HandlerBuildingOwnership::checkAndSendOwnership(const int newOwnership, const int floorId)
{
INFO_LOG(m_logger) << "BuildingOwnership checkAndSendOwnership";
if (floorId < 0) // outside building
return;
const int buildingId = m_handlerBuildingData->getBuildingIdFromFloorId(floorId);
if (buildingId < 0)
{
WARNING_LOG(m_logger) << "Could not find building for floor with id " << floorId << " - ignoring";
return;
}
// prüfe, ob sich die Farbe geändert hat.
const int oldOwnership = getOwnership(buildingId, floorId);
DEBUG_LOG(m_logger) << "checkAndSendOwnership buildingId = "
<< buildingId
<< " floorId=" << floorId
<< " oldOwnership=" << oldOwnership
<< " newOwnership=" << newOwnership;
if (oldOwnership != newOwnership) // Kriterium zum Senden
{
// Wenn ja, Eintrag in der Verwaltung
saveBuildingOwnership(floorId, newOwnership, buildingId);
// und Meldung verschicken.
sendBuildingOwnership(buildingId);
DEBUG_LOG(m_logger) << "new Building Ownership";
}
}
void HandlerBuildingOwnership::updateOwnerships(CentralEffectSimulation::BuildingOwnership *bo)
{
INFO_LOG(m_logger) << "BuildingOwnership updateOwnerships";
QMap <int, int> ownershipMap;
const QVector<int> floors = m_handlerBuildingData->getFloorsFromBuilding(bo->buildingId());
DEBUG_LOG(m_logger) << "updateOwnerships floors.size= " << floors.size();
for (const int floorId : floors)
ownershipMap[floorId] = 0;
for (const CentralEffectSimulation::Ownership &ownership : bo->ownerships())
{
DEBUG_LOG(m_logger) << "updateOwnerships floorId=" << ownership.floorId() << ": " << ownership.partyId();
ownershipMap[ownership.floorId()] = ownership.partyId();
}
bo->ownerships().resize(0);
bo->ownerships().reserve(ownershipMap.size());
CentralEffectSimulation::Ownership ownership;
for (auto it = ownershipMap.cbegin(); it != ownershipMap.cend(); ++it)
{
DEBUG_LOG(m_logger) << it.key() << ": " << it.value();
ownership.floorId(it.key());
ownership.partyId(it.value());
bo->ownerships().push_back(ownership);
}
}
void HandlerBuildingOwnership::saveBuildingOwnership(int floorId, int partyId, int buildingId)
{
INFO_LOG(m_logger) << "saveBuildingOwnership floorId: " << floorId
<< ", partyId: " << partyId
<< ", buildingId: " << buildingId;
// Vorhandenen Eintrag für das Gebäude suchen
auto it = m_buildingOwnership.find(buildingId);
if (it != m_buildingOwnership.end())
{
CentralEffectSimulation::BuildingOwnership &bo = *it;
// Vorhanden Eintrag für das Stockwerk suchen:
for (CentralEffectSimulation::Ownership &ownership : bo.ownerships())
{
if (ownership.floorId() == floorId)
{
ownership.partyId(partyId);
return;
}
}
// Neuen Eintrag für das Stockwerk anlegen
CentralEffectSimulation::Ownership ownership;
ownership.floorId(floorId);
ownership.partyId(partyId);
bo.ownerships().push_back(std::move(ownership));
m_buildingOwnership.insert(buildingId, bo);
return;
}
// Neuen Eintrag für das Gebäude anlegen
CentralEffectSimulation::BuildingOwnership bo;
CentralEffectSimulation::Ownership ownership;
bo.buildingId(buildingId);
ownership.floorId(floorId);
ownership.partyId(partyId);
bo.ownerships().resize(1, ownership);
m_buildingOwnership.insert(buildingId, bo);
}
void HandlerBuildingOwnership::sendBuildingOwnership(int buildingId)
{
INFO_LOG(m_logger) << "sendBuildingOwnership for building: " << buildingId;
CentralEffectSimulation::BuildingOwnership bo = m_buildingOwnership.value(buildingId);
bo.buildingId(buildingId);
bo.sampleTime(QDateTime::currentMSecsSinceEpoch());
updateOwnerships(&bo);
m_ddsHandler->dtsCes()->publish(bo);
insertInDb(bo);
}
// ///////////////////////////////////////////////////
/// \brief HandlerConfigureAlarms::loadOwnershipsFromDb
/// \return
///
bool HandlerBuildingOwnership::loadOwnershipsFromDb()
{
INFO_LOG(m_logger) << "HandlerBuildingOwnership::loadOwnershipsFromDb ";
m_buildingOwnership.clear();
auto cbBo = [this](const CentralEffectSimulation::Database::CesOwnership & bo)
{
saveBuildingOwnership(bo.floorId, bo.partyId, bo.buildingId);
};
if (!m_db->select(cbBo))
{
ERROR_LOG(m_logger) << "Error reading data from database 'CesOwnership'";
return false;
}
return true;
}
void HandlerBuildingOwnership::removeFromDbBuildingId(const int buildingId)
{
INFO_LOG(m_logger) << "HandlerBuildingOwnership::removeFromDbBuildingId buildingId: " << buildingId;
m_db->removeCesOwnershipByBuildingId(buildingId);
}
void HandlerBuildingOwnership::insertInDb(const CentralEffectSimulation::BuildingOwnership &bo)
{
DBTransaction trans(m_db->database());
removeFromDbBuildingId(bo.buildingId());
INFO_LOG(m_logger) << "insertInDb buildingId: " << bo.buildingId()
<< ", bo.ownerships().size(): " << bo.ownerships().size();
CentralEffectSimulation::Database::CesOwnership newOwnership;
newOwnership.buildingId = bo.buildingId();
for (const CentralEffectSimulation::Ownership &ownership : bo.ownerships())
{
newOwnership.id = 0;
newOwnership.floorId = ownership.floorId();
newOwnership.partyId = ownership.partyId();
DEBUG_LOG(m_logger) << "ownership: floorId = " << newOwnership.floorId
<< " partyId = " << newOwnership.partyId;
if (!m_db->insert(newOwnership))
ERROR_LOG(m_logger) << "Error adding 'CesOwnership' to database "
<< " buildingId =" << newOwnership.buildingId
<< " floorId = " << newOwnership.floorId
<< " partyId = " << newOwnership.partyId;
}
trans.commit();
} // end of insertInDb
} // namespace CesBuildings
@@ -0,0 +1,93 @@
/**
* Handler for player data
* $Id$
* $HeadURL$
* $Author$
* Created by gr, SLSE, 2017-02-20
*/
#pragma once
#include <CentralEffectSimulation/logger.h>
#include <CentralEffectSimulation/dds_handler.h>
#include <CentralEffectSimulation/ces_db.h>
#include <CentralEffectSimulation/ces_fts.h>
#include <Buildings/bld_dtc.h>
#include <CentralEffectSimulation/handler_participant.h>
#include <CentralEffectSimulation/handler_building_data.h>
#include <QtCore/QObject>
// AES-Handling for participants within buildings
namespace CesBuildings
{
class HandlerBuildingOwnership final
: public QObject
, protected CentralEffectSimulation::Interface::Fts::SetOwnershipRequestHandler
{
Q_OBJECT
public:
explicit HandlerBuildingOwnership(const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler,
const std::shared_ptr<CentralEffectSimulation::HandlerParticipant> &participantHandler,
const std::shared_ptr<CentralEffectSimulation::HandlerBuildingData> &buildingDataHandler,
const std::shared_ptr<CentralEffectSimulation::DatabaseInterface> &db,
QObject *parent = nullptr);
~HandlerBuildingOwnership();
/**
* Initialize the handler to manage information from player management
*/
bool init();
private Q_SLOTS:
/**
* Handle MainStructureElement from 'ISM'
*/
void onParticipantPositionChanged(const CentralEffectSimulation::HandlerParticipant::CesParticipantData &partPos);
/**
* Handle MainStructureElement from 'ISM'
*/
void onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data, DataModification modType);
void onParticipantLeavesBuilding(const int participantId);
private: // methoden
void onSetOwnershipRequest(const rti::core::SampleIdentity &cookie,
const CentralEffectSimulation::SetOwnershipRequest &request) override;
int calculateOwnershipByParticipantId(const int participantId);
int calculateOwnershipByFloorId(const int floorId);
void checkAndSendOwnership(const int newOwnership, const int floorId);
void saveBuildingOwnership(int floorId, int partyId, int buildingId);
void sendBuildingOwnership(int buildingId);
int getOwnership(int buildingId, int floorId) const;
void updateOwnerships(CentralEffectSimulation::BuildingOwnership *bo);
bool loadOwnershipsFromDb();
void removeFromDbBuildingId(const int buildingId);
void insertInDb(const CentralEffectSimulation::BuildingOwnership &bo);
private: // attributes
std::shared_ptr<CentralEffectSimulation::DdsHandler> m_ddsHandler; ///< Pointer to DDS handler
std::shared_ptr<CentralEffectSimulation::HandlerParticipant> m_handlerParticipant;
std::shared_ptr<CentralEffectSimulation::HandlerBuildingData> m_handlerBuildingData;
std::shared_ptr<CentralEffectSimulation::DatabaseInterface> m_db;
QHash <int, int> m_participantFloor; // key = ParicipantId, value= FloorId;
QHash <int, CentralEffectSimulation::BuildingOwnership> m_buildingOwnership; // key BuildingId, Value= Message BuildingOwnership
CentralEffectSimulation::LOGGER_T m_logger;
};
} // namespace CesBuildings
@@ -0,0 +1,519 @@
/**
* Handler for player data
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2017-02-20
*/
#include "handler_contamination.h"
#include <CentralEffectSimulation/handler_participant.h>
#include <CentralEffectSimulation/handler_building_data.h>
#include <QPainterPath>
#include <QPolygonF>
namespace CesBuildings
{
HandlerContamination::HandlerContamination(const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler,
QObject *parent)
: QObject(parent)
, m_ddsHandler(ddsHandler)
, m_logger(CentralEffectSimulation::getLogger("Plugin.Buildings.Buildings"))
{
} // end of ctor()
//-----------------------------------------------------------------------------
HandlerContamination::~HandlerContamination()
{
} // end of dtor()
//-----------------------------------------------------------------------------
bool HandlerContamination::init()
{
auto dtcAes = m_ddsHandler->dtcAes();
auto ftcBld = m_ddsHandler->ftcBld();
auto dtcBld = m_ddsHandler->dtcBld();
ftcBld->enableSetBuildingContaminationState();
////////////////////////////
/// \brief Get 'static' data for all BCContaminations
///
dtcAes->waitForHistoricalDataBCContamination(1000);
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::bCContaminationChanged,
this, &HandlerContamination::onBCContaminationChanged);
// Get 'static' data for all BCContaminations
{
auto cb = [this](const AreaEffectSimulation::BCContamination & bcc)
{
onBCContaminationChanged(bcc, DataModification::eAdded);
};
if (!dtcAes->bCContaminations(cb))
return false;
}
////////////////////////////
/// \brief Get 'static' data for all AesItemView
///
dtcAes->waitForHistoricalDataAesItemView(1000);
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
this, &HandlerContamination::onAesItemViewChanged);
// Get 'static' data for all AesItemView
{
auto cb = [this](const AreaEffectSimulation::AesItemView & aiv)
{
onAesItemViewChanged(aiv, DataModification::eAdded);
};
if (!dtcAes->aesItemViews(cb))
return false;
}
////////////////////////////
/// \brief Get data for all Building States
///
dtcBld->waitForHistoricalDataBuildingState(1000);
connect(dtcBld.get(), &Buildings::Interface::Dtc::buildingStateChanged,
this, &HandlerContamination::onBuildingStateChanged);
// Get 'static' data for all buildingStates
{
auto cb = [this](const Buildings::BuildingState & bs)
{
onBuildingStateChanged(bs, DataModification::eAdded);
};
if (!dtcBld->buildingStates(cb))
return false;
}
return true;
} // end of init()
//-----------------------------------------------------------------------------
// ///////////////////////////////////
// A E S (AreaEffectSimulation)
// ///////////////////////////////////
void HandlerContamination::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
{
if (modType != DataModification::eAdded &&
modType != DataModification::eModified)
return;
DEBUG_LOG(m_logger) << "Got AesItemView: " << data.effectStateId()
<< " data.aesItemId()" << data.aesItemId()
<< " data.aesTypeId()" << data.aesTypeId();
switch (data.effectStateId().underlying())
{
case AreaEffectSimulation::AesEffectState_def::EsActivated:
{
double chargeHeight; // Alle Stockwerke beruecksichtigen
double chargeDepression; // Alle Kellerraeume beruecksichtigen
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtNContamination)
{
chargeHeight = 500.0; // Alle Stockwerke beruecksichtigen
chargeDepression = -1000.0; // Alle Kellerraeume beruecksichtigen
DEBUG_LOG(m_logger) << "AtNContamination: chargeHeight=" << chargeHeight
<< " chargeDepression=" << chargeDepression;
}
else
{
chargeHeight = m_aesBCContaminations.value(data.aesItemId()).upperOffset();
chargeDepression = m_aesBCContaminations.value(data.aesItemId()).lowerOffset();
DEBUG_LOG(m_logger) << "BCContaminations: chargeHeight=" << chargeHeight
<< " chargeDepression=" << chargeDepression;
}
if (data.aesTypeId() != AreaEffectSimulation::AesType_def::AtBCContamination
&& data.aesTypeId() != AreaEffectSimulation::AesType_def::AtNContamination)
{
DEBUG_LOG(m_logger) << "return1: AesItemView: " << data.effectStateId();
return;
}
// Gebaeude die von einem sesshaften Kampfstoff betroffen sind, müssen als kontaminiert gelten.
const ProjectDataManagement::VolatilityType volatilityType = m_ddsHandler->volatilityTypeId(data.chargeStruct());
if (volatilityType != ProjectDataManagement::VolatilityType_def::Resident
&& data.aesTypeId() != AreaEffectSimulation::AesType_def::AtNContamination)
{
DEBUG_LOG(m_logger) << "return2: AesItemView: " << data.effectStateId();
return;
}
DEBUG_LOG(m_logger) << "HandlerContamination::onAesItemViewChanged data.aesItemId=" << data.aesItemId();
auto dtcIsm = m_ddsHandler->dtcIsm();
// Form in UTM-Polygon wandeln
int exerciseId = m_ddsHandler->getExerciseId();
QPolygonF polygonGeo;
// Convert Form to UTM
for (unsigned int i = 0; i < data.form().size(); i++)
polygonGeo.append(QPointF(data.form()[i].lon(), data.form()[i].lat()));
bool completeEnclosed = true;
bool isGroundLevel = false;
const QVector<int> &buildingIds = dtcIsm.get()->getBuildingByPolygon(exerciseId, polygonGeo, completeEnclosed, isGroundLevel);
DEBUG_LOG(m_logger) << "buildingIds.size=" << buildingIds.size();
for (int buildingId : qAsConst(buildingIds))
{
calculateBuilding(buildingId, data, chargeHeight, chargeDepression);
}
//
break;
}
default:
break;
}
}
void HandlerContamination::calculateBuilding(int buildingId,
const AreaEffectSimulation::AesItemView &data,
double chargeHeight,
double chargeDepression)
{
auto dtcIsm = m_ddsHandler->dtcIsm();
QVector<int> effectedRooms;
QVector<int> effectedFloors;
if (data.aesTypeId() != AreaEffectSimulation::AesType_def::AtBCContamination
&& data.aesTypeId() != AreaEffectSimulation::AesType_def::AtNContamination)
{
DEBUG_LOG(m_logger) << "return: NO BC-Contamination AesItemView: " << data.effectStateId();
return;
}
const ProjectDataManagement::VolatilityType volatilityType = m_ddsHandler->volatilityTypeId(data.chargeStruct());
if ( volatilityType != ProjectDataManagement::VolatilityType_def::Resident
&& data.aesTypeId() != AreaEffectSimulation::AesType_def::AtNContamination)
return;
DEBUG_LOG(m_logger) << "buildingId=" << buildingId;
effectedRooms.clear();
effectedFloors = getEffectedFloors(buildingId, chargeHeight, chargeDepression);
for (int effectedFloor : qAsConst(effectedFloors))
effectedRooms += dtcIsm.get()->getRoomIdsFromFloorId(buildingId, effectedFloor);
if (!effectedRooms.empty())
{
DEBUG_LOG(m_logger) << "effectedRooms.size=" << effectedRooms.size();
ProjectDataManagement::VulnerabilityState vulnerabilityState = ProjectDataManagement::VulnerabilityState::CombatReady;
// [GUEZE-2752] N-Contamination: Only Contamionation inside Range1
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtNContamination
&& !isInsideRange1(buildingId, data.aesItemId()))
{
DEBUG_LOG(m_logger) << "!isInsideRange1 buildingId=" << buildingId;
return;
}
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtBCContamination
&& !isInsideBCContamination(buildingId, data.aesItemId()))
{
DEBUG_LOG(m_logger) << "AtBCContamination !isInsideRange buildingId=" << buildingId << "return";
return;
}
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtNContamination
&& isInsideInnerCircle(buildingId, data.aesItemId()))
{
constexpr int TIME_2_SECONDS = 2000;
// Only actual explosion not old N-Fields
if ( m_ddsHandler->dtcCore()->partitionTime().timeStamp() < (data.effectStart() + TIME_2_SECONDS))
{
DEBUG_LOG(m_logger) << "VulnerabilityState=CatastrophicKill";
vulnerabilityState = ProjectDataManagement::VulnerabilityState::CatastrophicKill;
}
}
DEBUG_LOG(m_logger) << "setBuildingContaminationStateRequest buildingId=" << buildingId
<< " data.aesTypeId()=" << data.aesTypeId()
<< " isInsideInnerCircle(buildingId, data.aesItemId()=" << isInsideInnerCircle(buildingId, data.aesItemId());
{
DEBUG_LOG(m_logger) << "isInsideInnerCircle buildingId=" << buildingId;
setBuildingContaminationStateRequest(buildingId, data.aesItemId(), vulnerabilityState, effectedRooms);
}
}
}
// ///////////////////////////////////
// B L D (Buildings)
// ///////////////////////////////////
void HandlerContamination::onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType)
{
if (modType != DataModification::eAdded
&& modType != DataModification::eModified)
return;
INFO_LOG(m_logger) << "onBuildingStateChanged"
<< " id=" << data.id()
<< " aesId=" << data.aesId()
<< " contaminationStates().size=" << data.contaminationStates().size();
// Reset:
if (data.contaminationStates().empty())
m_contaminationState.remove(data.id());
// If a building is reset in an area where there is an active nuclear weapon, it will not be recontaminated -> in this case,
// regular checks should be carried out to see if the building needs to be contaminated
// Buildings that have been reset or decontaminated will be recontaminated as long as the nuclear weapon is still present
const auto aesItemViews = m_ddsHandler->dtcAes()->aesItemViews();
for (const auto &aesItemView : qAsConst(aesItemViews))
{
if (aesItemView.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated)
{
DEBUG_LOG(m_logger) << "Wirkfeld aesItemView.id()=" << aesItemView.id()
<< " aesItemView.aesItemId()=" << aesItemView.aesItemId()
<< " fuer Gebaeude " << data.id() << " neu berechnen";
double chargeHeight = 0.0;
double chargeDepression = 0.0;
if (aesItemView.aesTypeId() == AreaEffectSimulation::AesType_def::AtNContamination)
{
chargeHeight = 500.0; // Alle Stockwerke beruecksichtigen
chargeDepression = -1000.0; // Alle Kellerraeume beruecksichtigen
DEBUG_LOG(m_logger) << "AtNContamination: chargeHeight=" << chargeHeight
<< " chargeDepression=" << chargeDepression;
}
else
{
if ( m_aesBCContaminations.contains(aesItemView.aesItemId()))
{
chargeHeight = m_aesBCContaminations.value(aesItemView.aesItemId()).upperOffset();
chargeDepression = m_aesBCContaminations.value(aesItemView.aesItemId()).lowerOffset();
DEBUG_LOG(m_logger) << "BCContaminations: chargeHeight=" << chargeHeight
<< " chargeDepression=" << chargeDepression;
}
else
{
DEBUG_LOG(m_logger) << "BCContaminations: m_aesBCContaminations not contains:"<< aesItemView.aesItemId();
}
}
// [GUEZE-2527] Fehler bei A-Waffen und Dekontaminierung
auto dtcIsm = m_ddsHandler->dtcIsm();
int exerciseId = m_ddsHandler->getExerciseId();
QPolygonF polygonGeo;
polygonGeo.reserve(aesItemView.form().size());
// Convert Form to UTM
for (const auto point : aesItemView.form())
polygonGeo.append(QPointF(point.lon(), point.lat()));
bool completeEnclosed = true;
bool isGroundLevel = false;
const QVector<int> &buildingIds = dtcIsm.get()->getBuildingByPolygon(exerciseId, polygonGeo, completeEnclosed, isGroundLevel);
if (buildingIds.contains(data.id() ))
calculateBuilding(data.id(), aesItemView, chargeHeight, chargeDepression);
else
DEBUG_LOG(m_logger) << "Building not in Area BuildingId=" << data.id();
}
}
}
void HandlerContamination::setBuildingContaminationStateRequest(int buildingId,
int aesId,
ProjectDataManagement::VulnerabilityState vulnerabilityState,
QVector<int> rooms)
{
Buildings::ContaminationState contaminationState;
contaminationState.aesId(aesId);
contaminationState.vulnerabilityState(vulnerabilityState);
// contaminationState.vulne
DEBUG_LOG(m_logger) << "setBuildingContaminationStateRequest"
<< " buildingId=" << buildingId
<< " aesId=" << aesId
<< " vulnerabilityState=" << vulnerabilityState
<< " rooms.size=" << rooms.size();
contaminationState.rooms().resize(rooms.size());
for (int i = 0; i < rooms.size(); i++)
{
contaminationState.rooms()[i] = rooms[i];
contaminationState.vulnerabilityState(vulnerabilityState);
DEBUG_LOG(m_logger) << " room[" << i << "]=" << rooms[i];
}
Buildings::SetBuildingContaminationStateRequest requestContamination(
buildingId,
contaminationState
);
// Senden, wenn fuer das Gebaeude noch keine Contamination vorhanden ist.
if (!m_contaminationState.contains(buildingId))
{
DEBUG_LOG(m_logger) << "Neue Kontamination BuildingId=" << buildingId
<< " requestContamination aesId=" << requestContamination.contaminationState().aesId();
m_ddsHandler->ftcBld()->setBuildingContaminationStateRequest(requestContamination, this);
m_contaminationState.insert(buildingId, requestContamination);
return;
}
// Senden, wenn sich die Kontamination geaendert hat.
Buildings::SetBuildingContaminationStateRequest lastRequestContamination = m_contaminationState.value(buildingId);
if (lastRequestContamination != requestContamination)
{
DEBUG_LOG(m_logger) << "Änderung der Kontamination BuildingId=" << buildingId
<< " aesId=" << requestContamination.contaminationState().aesId();
m_ddsHandler->ftcBld()->setBuildingContaminationStateRequest(requestContamination, this);
m_contaminationState.insert(buildingId, requestContamination);
return;
}
DEBUG_LOG(m_logger) << "Keine Änderung der Kontamination BuildingId=" << buildingId;
}
QVector<int> HandlerContamination::getEffectedFloors(const int buildingId, const int chargeHeight, const int depression)
{
auto dtcIsm = m_ddsHandler->dtcIsm();
DEBUG_LOG(m_logger) << "Contaminated-Building=" << buildingId
<< " chargeHeight=" << chargeHeight
<< " depression=" << depression;
const QVector<int> &floorIds = dtcIsm->getFloorIdsFromBuilding(buildingId);
QVector<int> effectedFloorIds;
effectedFloorIds.reserve(floorIds.size());
for (int floorId : qAsConst(floorIds))
{
double halfFloorHeight = dtcIsm->getHalfFloorHeight(buildingId, floorId);
DEBUG_LOG(m_logger) << " floorId=" << floorId
<< " halfFloorHeight=" << halfFloorHeight
<< " chargeHeight=" << chargeHeight
<< " depression=" << depression;
if (depression < 0) // Kellerraeme beruecksichtigen
{
if (halfFloorHeight > depression)
DEBUG_LOG(m_logger) << "Checke Obergrenze";
else
{
DEBUG_LOG(m_logger) << "halfFloorHeight > depression floorId=" << floorId << " continue";
continue;
}
}
else
{
if (halfFloorHeight < 0) // Kellerraeume nicht beruecksichtigen
{
DEBUG_LOG(m_logger) << "depression ist nicht < 0"
<< " Kelleretagen nicht beruecksichtigen floorId=" << floorId << " continue";
continue;
}
}
if (halfFloorHeight < chargeHeight)
effectedFloorIds.append(floorId);
}
return effectedFloorIds;
}
void HandlerContamination::onSetBuildingContaminationStateReply(const Core::FunctionReplyObject &replyObject)
{
if (replyObject.error())
WARNING_LOG(m_logger) << "Can not send ContaminationStates on building to building service: " << replyObject();
else
DEBUG_LOG(m_logger) << "onSetBuildingContaminationStateReply for id " << replyObject.id() << " success\n"
<< " replyObject.str() = " << replyObject.str();
}
void HandlerContamination::onBCContaminationChanged(const AreaEffectSimulation::BCContamination &data, DataModification modType)
{
if ((modType == DataModification::eRemoved)
|| data.isDeleted())
m_aesBCContaminations.remove(data.id());
else
m_aesBCContaminations.insert(data.id(), data);
}
// Returns true if the building is in the inner circle at the time of impact and should fail as a result.
// Liefert true, wenn sich das Gebaeude beim Einschlag im inneren Kreis befindet und daraufhin ausfallen soll.
bool HandlerContamination::isInsideInnerCircle(int buildingId, int aesId)
{
InfrastructureManagement::MainStructureElement mse = m_ddsHandler->dtcIsm()->mainStructureElement(buildingId);
AreaEffectSimulation::NContamination nContamination = m_ddsHandler->dtcAes()->nContamination(aesId);
DEBUG_LOG(m_logger) << "isInsideInnerCircle borderLengthInner=" << nContamination.borderLengthInner()
<< " borderLengthOuter=" << nContamination.borderLengthOuter()
<< " impactRadius=" << nContamination.impactRadius();
int zone = -1;
const QPointF impactPositionUtm = CentralEffectSimulation::geographic2Utm(nContamination.impactPosition(), zone);
DEBUG_LOG(m_logger) << "impactPositionUtm=" << impactPositionUtm.x() << "/" << impactPositionUtm.y()
<< " zone=" << zone;
const QPointF buildingPositionUtm = CentralEffectSimulation::geographic2Utm(mse.geoPosition(), zone);
DEBUG_LOG(m_logger) << "buildingPositionUtm=" << buildingPositionUtm.x() << "/" << buildingPositionUtm.y();
double squareDistance = CentralEffectSimulation::getSquareDistance(impactPositionUtm, buildingPositionUtm);
if (squareDistance < nContamination.impactRadius() * nContamination.impactRadius())
{
DEBUG_LOG(m_logger) << "isInsideInnerCircle return true";
return true;
}
else
{
DEBUG_LOG(m_logger) << "isInsideInnerCircle return false";
return false;
}
}
// Returns true if the building is in the inner circle at the time of impact and should fail as a result.
// Liefert true, wenn sich das Gebaeude beim Einschlag im inneren Kreis befindet und daraufhin ausfallen soll.
bool HandlerContamination::isInsideBCContamination(int buildingId, int aesId)
{
InfrastructureManagement::MainStructureElement mse = m_ddsHandler->dtcIsm()->mainStructureElement(buildingId);
//AreaEffectSimulation::NContamination nContamination = m_ddsHandler->dtcAes()->nContamination(aesId);
AreaEffectSimulation::BCContamination bcContamination = m_ddsHandler->dtcAes()->bCContamination(aesId);
DEBUG_LOG(m_logger) << " impactRadius=" << bcContamination.impactRadius();
int zone = -1;
const QPointF impactPositionUtm = CentralEffectSimulation::geographic2Utm(bcContamination.impactPosition(), zone);
DEBUG_LOG(m_logger) << "impactPositionUtm=" << impactPositionUtm.x() << "/" << impactPositionUtm.y()
<< " zone=" << zone;
const QPointF buildingPositionUtm = CentralEffectSimulation::geographic2Utm(mse.geoPosition(), zone);
DEBUG_LOG(m_logger) << "buildingPositionUtm=" << buildingPositionUtm.x() << "/" << buildingPositionUtm.y();
double squareDistance = CentralEffectSimulation::getSquareDistance(impactPositionUtm, buildingPositionUtm);
if (squareDistance < bcContamination.impactRadius() * bcContamination.impactRadius())
{
DEBUG_LOG(m_logger) << "isInsideInnerCircle return true";
return true;
}
else
{
DEBUG_LOG(m_logger) << "isInsideInnerCircle return false";
return false;
}
}
// Returns true if the building is located in range 1 at the time of impact and is to be contaminated as a result.
// Liefert true, wenn sich das Gebaeude beim Einschlag im Bereich 1 befindet und daraufhin kontaminiert werden soll.
bool HandlerContamination::isInsideRange1(int buildingId, int aesId)
{
InfrastructureManagement::MainStructureElement mse = m_ddsHandler->dtcIsm()->mainStructureElement(buildingId);
AreaEffectSimulation::NContamination nContamination = m_ddsHandler->dtcAes()->nContamination(aesId);
DEBUG_LOG(m_logger) << "isInsideRange1 borderLengthInner=" << nContamination.borderLengthInner()
<< " borderLengthOuter=" << nContamination.borderLengthOuter()
<< " impactRadius=" << nContamination.impactRadius();
int zone = -1;
const QPointF impactPositionUtm = CentralEffectSimulation::geographic2Utm(nContamination.impactPosition(), zone);
DEBUG_LOG(m_logger) << "impactPositionUtm=" << impactPositionUtm.x() << "/" << impactPositionUtm.y()
<< " zone=" << zone;
const QPointF buildingPositionUtm = CentralEffectSimulation::geographic2Utm(mse.geoPosition(), zone);
DEBUG_LOG(m_logger) << "buildingPositionUtm=" << buildingPositionUtm.x() << "/" << buildingPositionUtm.y();
double squareDistance = CentralEffectSimulation::getSquareDistance(impactPositionUtm, buildingPositionUtm);
if (squareDistance < nContamination.borderLengthInner() * nContamination.borderLengthInner())
{
DEBUG_LOG(m_logger) << "isInsideRange1 return true";
return true;
}
else
{
DEBUG_LOG(m_logger) << "isInsideRange1 return false";
return false;
}
}
} // namespace CesBuildings
@@ -0,0 +1,82 @@
/**
* Handler for player data
* $Id$
* $HeadURL$
* $Author$
* Created by gr, SLSE, 2017-02-20
*/
#pragma once
#include <CentralEffectSimulation/logger.h>
#include <AreaEffectSimulation/aes_dtc.h>
#include <Buildings/bld_dtc.h>
#include <Buildings/bld_ftc.h>
#include <ProjectDataManagement/pdm_dtc.h>
#include <TrainingAreaBase/tab_ftc.h>
#include <CentralEffectSimulation/dds_handler.h>
#include <CentralEffectSimulation/handler_building_data.h>
#include <QtCore/QObject>
#include <QtCore/QMap>
#include <QtCore/QHash>
#include <QtCore/QVector>
namespace LtsUtils
{
class QPoint3D;
}
// AES-Handling for buildings
namespace CesBuildings
{
class HandlerContamination : public QObject
, protected Buildings::Interface::Ftc::SetBuildingContaminationStateReplyHandler
{
Q_OBJECT
public:
explicit HandlerContamination(const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler,
QObject *parent = nullptr);
~HandlerContamination();
bool init();
protected:
void onSetBuildingContaminationStateReply(const Core::FunctionReplyObject &replyObject) override final;
private slots:
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType);
void onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType);
void onBCContaminationChanged(const AreaEffectSimulation::BCContamination &data, DataModification modType);
private:
QVector<int> getEffectedFloors(const int buildingId, const int chargeHeight, const int depression);
void setBuildingContaminationStateRequest(int buildingId,
int aesId,
ProjectDataManagement::VulnerabilityState vulnerabilityState,
QVector<int> rooms);
bool isInsideInnerCircle(int buildingId, int aesId);
bool isInsideRange1(int buildingId, int aesId);
bool isInsideBCContamination(int buildingId, int aesId);
void calculateBuilding(int buildingId,
const AreaEffectSimulation::AesItemView &data,
double chargeHeight,
double chargeDepression);
private:
QHash<int, AreaEffectSimulation::BCContamination> m_aesBCContaminations; // key = aesItemId
std::shared_ptr<CentralEffectSimulation::DdsHandler> m_ddsHandler; ///< Pointer to VOM DDS handler
std::shared_ptr<CentralEffectSimulation::HandlerBuildingData> m_handlerBuildingData;
QMap<int, Buildings::SetBuildingContaminationStateRequest> m_contaminationState; // Key = BuildingId
CentralEffectSimulation::LOGGER_T m_logger;
};
} // namespace CesBuildings
@@ -0,0 +1,141 @@
/**
* Plugin Building Ownership
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLTE, 2016-04-14
*/
#include "plugin.h"
#include <CentralEffectSimulation/proxy_building.h>
#include <QTimer>
namespace CesBuildings
{
std::shared_ptr<CentralEffectSimulation::Plugin::Interface> CesBuildingsPlugin::createInterface(CentralEffectSimulation::Plugin::DataProvider *pdp,
const std::shared_ptr<DDSConnector::DdsConnector> &dDSConnector,
NGL::Settings *settings,
CentralEffectSimulation::MainHandler *mainHandler)
{
return std::make_shared<CesBuildingsInterfaceImpl>(pdp, dDSConnector, settings, mainHandler);
}
CesBuildingsInterfaceImpl::CesBuildingsInterfaceImpl(CentralEffectSimulation::Plugin::DataProvider *pdp,
const std::shared_ptr<DDSConnector::DdsConnector> &dDSConnector,
NGL::Settings *settings,
CentralEffectSimulation::MainHandler *mainHandler)
: m_pdp(pdp)
, m_ddsConnector(dDSConnector)
, m_mainHandler(mainHandler)
, m_ddsHandler(m_mainHandler->dds())
, m_db(m_mainHandler->db())
, m_handlerBuildingData(m_mainHandler->handlerBuildingData())
, m_handlerParticipant(m_mainHandler->handlerParticipant())
, m_logger(CentralEffectSimulation::getLogger("Plugin.Buildings.CesBuildingsInterfaceImpl"))
{
Q_UNUSED(settings)
}
CesBuildingsInterfaceImpl::~CesBuildingsInterfaceImpl()
{
m_handlerBuildingOwnership.reset();
m_handlerAesData.reset();
m_handlerContaminations.reset();
}
bool CesBuildingsInterfaceImpl::init(int domainId, int exerciseId)
{
m_domainId = domainId;
m_exerciseId = exerciseId;
INFO_LOG(m_logger) << "CesBuildingsInterfaceImpl::init()"
<< " m_domainId=" << m_domainId
<< " m_exerciseId=" << m_exerciseId;
// initialize handlerBuildingOwnership
INFO_LOG(m_logger) << "initialize handlerBuildingOwnership ----------------------------";
m_handlerBuildingOwnership = std::make_shared<HandlerBuildingOwnership>(m_ddsHandler,
m_handlerParticipant,
m_handlerBuildingData,
m_db,
this);
if (!m_handlerBuildingOwnership->init())
{
ERROR_LOG(m_logger) << "Initialisation m_handlerBuildingOwnership failed.";
return false;
}
INFO_LOG(m_logger) << "end initialize handlerBuildingOwnership ----------------------------";
// initialize handlerAesData
INFO_LOG(m_logger) << "initialize handlerAesData ----------------------------";
m_handlerAesData = std::make_shared<HandlerAesData>(m_ddsHandler,
m_handlerBuildingData,
this);
if (!m_handlerAesData->init())
{
ERROR_LOG(m_logger) << "Initialisation m_handlerAesData failed.";
return false;
}
INFO_LOG(m_logger) << "end initialize HandlerAesData ----------------------------";
// initialize handlerAesData
INFO_LOG(m_logger) << "initialize handlerContaminations ----------------------------";
m_handlerContaminations = std::make_shared<HandlerContamination>(m_ddsHandler,
this);
if (!m_handlerContaminations->init())
{
ERROR_LOG(m_logger) << "Initialisation m_handlerContaminations failed.";
return false;
}
INFO_LOG(m_logger) << "end initialize HandlerContaminations ----------------------------";
// initialize handlerBuildingModel
INFO_LOG(m_logger) << "initialize handlerBuildingModel ----------------------------";
m_handlerBuildingModel = std::make_shared<HandlerBuildingModel>(m_ddsHandler,
m_handlerAesData,
this);
if (!m_handlerBuildingModel->init())
{
ERROR_LOG(m_logger) << "Initialisation m_handlerBuildingModel failed.";
return false;
}
INFO_LOG(m_logger) << "end initialize handlerBuildingModel ----------------------------";
// Maybe not all MainStructureElements are processed yet.
// So give MainEventLoop time to finish their processing:
// suggest Qtimer::singleShot()
QTimer::singleShot(1000, this, [this]()
{
std::shared_ptr<CentralEffectSimulation::ProxyBuilding> proxyBuilding = m_mainHandler->proxyBuilding();
if (proxyBuilding)
{
INFO_LOG(m_logger) << "set_handlerBuildingModel ----------------------------";
proxyBuilding->set_handlerBuildingModel(m_handlerBuildingModel);
}
});
INFO_LOG(m_logger) << "CesBuildingsInterfaceImpl::init() return true";
return true;
}
QString CesBuildingsInterfaceImpl::echo(const QString &message)
{
QString ret(QStringLiteral("<<<< %1 >>>> CentralEffectSimulationBuildingOwnershipInterfaceImpl::echo").arg(message));
INFO_LOG(m_logger) << "CentralEffectSimulationBuildingOwnershipInterfaceImpl::echo return:" << ret;
DEBUG_LOG(m_logger) << "DEBUG: CentralEffectSimulationBuildingOwnershipInterfaceImpl::echo return:" << ret;
return ret;
}
} //namespace CesBuildings
@@ -0,0 +1,87 @@
/**
* Plugin Building Ownership
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLTE, 2016-04-14
*/
#pragma once
#include "../../proxy_building.h"
#include "handler_building_ownership.h"
#include "handler_aes_data.h"
#include "handler_building_model.h"
#include "handler_contamination.h"
#include <CentralEffectSimulation/logger.h>
#include <CentralEffectSimulation/ces_plugin_interface.h>
#include <CentralEffectSimulation/main_handler.h>
#include <CentralEffectSimulation/dds_handler.h>
#include <CentralEffectSimulation/handler_building_data.h>
#include <DDS/DDSConnector/dds_connector.h>
#include <QObject>
namespace CesBuildings
{
class CesBuildingsPlugin : public QObject, public CentralEffectSimulation::Plugin::Plugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "special:3:ces.CentralEffectSimulationBuildingOwnershipPlugin")
Q_INTERFACES(CentralEffectSimulation::Plugin::Plugin)
public:
CesBuildingsPlugin() = default;
~CesBuildingsPlugin() = default;
std::shared_ptr<CentralEffectSimulation::Plugin::Interface> createInterface(CentralEffectSimulation::Plugin::DataProvider *pdp,
const std::shared_ptr<DDSConnector::DdsConnector> &dDSConnector,
NGL::Settings *settings,
CentralEffectSimulation::MainHandler *mainHandler) override;
};
class CesBuildingsInterfaceImpl final : public CentralEffectSimulation::Plugin::Interface
{
Q_OBJECT
public:
CesBuildingsInterfaceImpl(CentralEffectSimulation::Plugin::DataProvider *pdp,
const std::shared_ptr<DDSConnector::DdsConnector> &dDSConnector,
NGL::Settings *settings,
CentralEffectSimulation::MainHandler *mainHandler);
~CesBuildingsInterfaceImpl();
//bool init();
const char *name() const override { return "CentralEffectSimulationBuildingOwnership"; }
QString echo(const QString &message) override;
void set_handlerBuildingModel(CentralEffectSimulation::ProxyBuilding *proxy);
private Q_SLOTS:
bool init(int domainId, int exerciseId) override;
private:
private:
CentralEffectSimulation::Plugin::DataProvider *m_pdp{nullptr};
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
CentralEffectSimulation::MainHandler *m_mainHandler{nullptr};
std::shared_ptr<CentralEffectSimulation::DdsHandler> m_ddsHandler;
std::shared_ptr<CentralEffectSimulation::DatabaseInterface> m_db;
std::shared_ptr<CentralEffectSimulation::HandlerBuildingData> m_handlerBuildingData; ///< Pointer to AES Building handler
std::shared_ptr<CentralEffectSimulation::HandlerParticipant> m_handlerParticipant; ///< Pointer to handler for all participants
std::shared_ptr<HandlerContamination> m_handlerContaminations;
std::shared_ptr<HandlerBuildingOwnership> m_handlerBuildingOwnership; ///< Pointer to handler for Building Ownership
std::shared_ptr<HandlerAesData> m_handlerAesData;
std::shared_ptr<HandlerBuildingModel> m_handlerBuildingModel;
CentralEffectSimulation::LOGGER_T m_logger;
int m_domainId{0};
int m_exerciseId{0};
};
} // namespace CesBuildings