Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+782
@@ -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
|
||||
Reference in new issue
Block a user