340 lines
9.6 KiB
C++
Executable File
340 lines
9.6 KiB
C++
Executable File
/**
|
|
* Object for the null mine area (where the unassigned DUS mines belong to)
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
#include "object_mine_area_null.h"
|
|
#include "special_area_provider.h"
|
|
|
|
#include <QPolygonF>
|
|
#include <LtsUtilsCore/dds_bitarray.h>
|
|
#include <ngldb/dbtransaction.h>
|
|
|
|
namespace AreaEffectSimulation
|
|
{
|
|
|
|
ObjectMineAreaNull::ObjectMineAreaNull(MainHandler *mainHandler,
|
|
QObject *parent)
|
|
: ObjectBaseTmpl(mainHandler, QStringLiteral("MineAreaNull"), parent)
|
|
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
|
, m_setId(0)
|
|
{
|
|
// read all Triggered Mines from database
|
|
// Store all those of this mine area in m_triggeredMines
|
|
auto cb = [this] (const Database::AesMineAreaTriggeredMines &mine)
|
|
{
|
|
m_triggeredMines.insert(mine.mineId, mine);
|
|
};
|
|
if (!m_mainHandler->db()->selectByMineAreaId(cb, 0)) // mineArea 0
|
|
{
|
|
ERROR_LOG(m_logger) << "Error reading data from database!";
|
|
}
|
|
|
|
// Set TriggeredExplosions Base Data
|
|
m_tis.id(AesType::AtMineAreaSingleMines);
|
|
m_tis.aesItemId(0);
|
|
m_tis.aesTypeId(AesType::AtMineAreaSingleMines);
|
|
|
|
// Set DUS-Mine status Base Data
|
|
m_dms.mines().resize(m_triggeredMines.size());
|
|
|
|
onPublishData();
|
|
}
|
|
|
|
ObjectMineAreaNull::~ObjectMineAreaNull()
|
|
{
|
|
removeTopics();
|
|
}
|
|
bool ObjectMineAreaNull::isDusMineArea() const
|
|
{
|
|
return static_cast<MineClass::type>(m_mainHandler->dds()->pdmDtc()->mineClass(m_data.chargeTypeId, m_data.igniterTypeId, m_data.igniterFunctionId))
|
|
== MineClass::DUS;
|
|
}
|
|
|
|
bool ObjectMineAreaNull::isConcreteMine() const
|
|
{
|
|
return static_cast<MineClass::type>(m_mainHandler->dds()->pdmDtc()->mineClass(m_data.chargeTypeId, m_data.igniterTypeId, m_data.igniterFunctionId))
|
|
== MineClass::Concrete;
|
|
}
|
|
|
|
bool ObjectMineAreaNull::isVirtualSingleMine() const
|
|
{
|
|
return static_cast<MineClass::type>(m_mainHandler->dds()->pdmDtc()->mineClass(m_data.chargeTypeId, m_data.igniterTypeId, m_data.igniterFunctionId))
|
|
== MineClass::VirtualSingle;
|
|
}
|
|
|
|
bool ObjectMineAreaNull::isVirtualMine() const
|
|
{
|
|
return static_cast<MineClass::type>(m_mainHandler->dds()->pdmDtc()->mineClass(m_data.chargeTypeId, m_data.igniterTypeId, m_data.igniterFunctionId))
|
|
== MineClass::Virtual;
|
|
}
|
|
int ObjectMineAreaNull::lastConcreteMineNo()
|
|
{
|
|
int lastMineNo = 0;
|
|
for (const Database::AesMineAreaTriggeredMines &mine : qAsConst(m_triggeredMines))
|
|
{
|
|
// NOTE: igniterType/IgniterFunciton = 0 as long as AesMineAreaTriggeredMines does not contain values
|
|
DEBUG_LOG(m_logger) << "mine: chargeTypeId " << mine.chargeTypeId << ", mineId: " << mine.mineId;
|
|
if (isConcreteMine() ||
|
|
isDusMineArea())
|
|
{
|
|
if (mine.mineId > lastMineNo)
|
|
lastMineNo = mine.mineId;
|
|
}
|
|
}
|
|
return lastMineNo;
|
|
}
|
|
|
|
bool ObjectMineAreaNull::triggerMine(int mineId, bool trigger, int chargeTypeId, const QPointF &position, bool publish)
|
|
{
|
|
Database::AesMineAreaTriggeredMines &tm = m_triggeredMines[mineId];
|
|
tm.mineAreaId = 0;
|
|
tm.mineId = mineId;
|
|
tm.isTriggered = trigger;
|
|
if (chargeTypeId > 0)
|
|
tm.chargeTypeId = chargeTypeId;
|
|
if (trigger)
|
|
tm.triggerTime = QDateTime::fromMSecsSinceEpoch(partitionTimeMSec());
|
|
if (!position.isNull())
|
|
tm.position = position;
|
|
|
|
bool bOk = true;
|
|
|
|
DEBUG_LOG(m_logger) << "tm.id: " << tm.id << ", mineId: " << tm.mineId << ", mineAreaId: " << tm.mineAreaId;
|
|
|
|
if (tm.chargeTypeId == 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Not possible to trigger mine with invalid chargeTypeId 0";
|
|
|
|
return false;
|
|
}
|
|
|
|
if (!tm.id)
|
|
{
|
|
bOk &= m_mainHandler->db()->insert(tm);
|
|
m_setId++;
|
|
}
|
|
else
|
|
bOk &= m_mainHandler->db()->update(tm);
|
|
|
|
if (!bOk)
|
|
return false;
|
|
|
|
if (publish)
|
|
onPublishData();
|
|
return true;
|
|
}
|
|
|
|
bool ObjectMineAreaNull::triggerMine(Database::AesMineAreaTriggeredMines &mine)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Triggering mine " << mine.mineId << " with dbId " << mine.id;
|
|
mine.mineAreaId = m_data.id;
|
|
mine.isTriggered = true;
|
|
mine.triggerTime = QDateTime::fromMSecsSinceEpoch(partitionTimeMSec());
|
|
|
|
m_triggeredMines[mine.mineId] = mine;
|
|
|
|
if (!m_mainHandler->db()->update(mine))
|
|
ERROR_LOG (m_logger) << "Error updating mine " << mine.mineId << " in db!";
|
|
|
|
onPublishData();
|
|
return true;
|
|
}
|
|
|
|
void ObjectMineAreaNull::triggerMines(const QList<Database::AesMineAreaTriggeredMines> &mines)
|
|
{
|
|
DBTransaction trans(m_mainHandler->db()->database());
|
|
bool bOk = true;
|
|
for (const auto &mine : mines)
|
|
{
|
|
m_triggeredMines[mine.mineId] = mine;
|
|
m_triggeredMines[mine.mineId].mineAreaId = 0;
|
|
|
|
if (!m_mainHandler->db()->update(m_triggeredMines[mine.mineId]))
|
|
{
|
|
bOk = false;
|
|
ERROR_LOG (m_logger) << "Error updating mine " << mine.mineId << " in db!";
|
|
}
|
|
}
|
|
if (bOk)
|
|
trans.commit();
|
|
|
|
m_setId++;
|
|
onPublishData();
|
|
}
|
|
|
|
bool ObjectMineAreaNull::resetMine(int mineId)
|
|
{
|
|
return triggerMine(mineId, false);
|
|
}
|
|
|
|
bool ObjectMineAreaNull::resetMines()
|
|
{
|
|
DEBUG_LOG(m_logger) << "Resetting unassociated DUS mines, count: " << m_triggeredMines.size();
|
|
|
|
bool bOk = true;
|
|
auto it = m_triggeredMines.begin();
|
|
while (it != m_triggeredMines.end())
|
|
{
|
|
Database::AesMineAreaTriggeredMines &tm = (*it);
|
|
if (tm.isTriggered)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Reset mine with id " << tm.mineId;
|
|
tm.isTriggered = false;
|
|
bOk &= m_mainHandler->db()->update(tm);
|
|
}
|
|
++it;
|
|
}
|
|
|
|
if (!bOk)
|
|
return false;
|
|
|
|
// This pauses the TAB reaction on mine reset changes...
|
|
const TrainingAreaBase::SendResetAllDusMinesRequest req;
|
|
|
|
m_requestHelper->startSingleRequest([req, this]()
|
|
{
|
|
return m_mainHandler->dds()->tabFtc()->sendResetAllDusMinesRequest(req,this);
|
|
});
|
|
|
|
// We're publishing data anyhow. So do the other DUS mine areas.
|
|
onPublishData();
|
|
|
|
return true;
|
|
}
|
|
|
|
Database::AesMineAreaTriggeredMines ObjectMineAreaNull::takeMine(int mineId)
|
|
{
|
|
if (!m_triggeredMines.contains(mineId))
|
|
return Database::AesMineAreaTriggeredMines();
|
|
|
|
Database::AesMineAreaTriggeredMines ret = m_triggeredMines.value(mineId);
|
|
m_triggeredMines.remove(mineId);
|
|
|
|
m_setId++;
|
|
onPublishData();
|
|
return ret;
|
|
}
|
|
|
|
void ObjectMineAreaNull::onPublishData()
|
|
{
|
|
DDSConnector::CoherentSet cs (m_mainHandler->dds()->ddsConnector());
|
|
ObjectBaseTmpl::onPublishData();
|
|
|
|
publishTriggeredImpacts();
|
|
publishDusMineStatus();
|
|
publishAiv();
|
|
}
|
|
|
|
void ObjectMineAreaNull::removeTopics()
|
|
{
|
|
auto dts = m_mainHandler->dds()->dts();
|
|
dts->removeMineAreaByKey(m_data.id);
|
|
dts->removeAesItemViewByKey(1000 * m_data.id + AesType::AtMineAreaSingleMines);
|
|
dts->removeTriggeredImpactsByKey(1000 * m_data.id + AesType::AtMineAreaSingleMines);
|
|
emit removeAiv(m_data.id);
|
|
}
|
|
|
|
void ObjectMineAreaNull::publishAiv()
|
|
{
|
|
// Todo: calculate unique id.
|
|
// Better than aiv.id(1000 * aesItemId + AesType::AtMineArea);
|
|
std::vector<Core::GeoPosition> vec;
|
|
vec.reserve(m_triggeredMines.size());
|
|
QPolygonF tmp;
|
|
tmp.reserve(m_triggeredMines.size());
|
|
for (const auto &mine : qAsConst(m_triggeredMines))
|
|
{
|
|
vec.emplace_back(Core::GeoPosition(mine.position.x(), mine.position.y(), 0));
|
|
tmp.push_back(mine.position);
|
|
}
|
|
|
|
AesItemView aiv2(m_aiv2);
|
|
aiv2.aesItemId(0);
|
|
aiv2.chargeStruct().chargeTypeId(m_data.chargeTypeId); // Shall be invalid. EffectSimulation has been conducted before, so not necessary for service sCES
|
|
aiv2.effectStart(0);
|
|
aiv2.form(vec);
|
|
aiv2.boundingBoxBottomLeft() = Core::GeoPosition2D(tmp.boundingRect().bottomLeft().x(), tmp.boundingRect().bottomLeft().y());
|
|
aiv2.boundingBoxTopRight() = Core::GeoPosition2D(tmp.boundingRect().topRight().x(), tmp.boundingRect().topRight().y());
|
|
aiv2.aesTypeId(AesType::inner_enum::AtMineAreaSingleMines);
|
|
aiv2.id(AesType::inner_enum::AtMineAreaSingleMines);
|
|
aiv2.effectStateId(AesEffectState::inner_enum::EsActivated);
|
|
aiv2.setId(dds::core::optional<rti::core::int64>(m_setId));
|
|
if (m_data.partyId != 0)
|
|
aiv2.partyId(m_data.partyId);
|
|
|
|
checkIsCentralAndPublish(aiv2.form(), m_aiv2.form(), m_data.isCentral);
|
|
|
|
if (aiv2 != m_aiv2)
|
|
{
|
|
aiv2.sampleTime(partitionTimeMSec());
|
|
m_aiv2 = aiv2;
|
|
m_mainHandler->dds()->dts()->publish(aiv2);
|
|
emit newAiv(aiv2);
|
|
}
|
|
}
|
|
|
|
bool ObjectMineAreaNull::publishTriggeredImpacts()
|
|
{
|
|
// Build an own tes-bitfield and compare, only store and publish if changed.
|
|
TriggeredImpacts tis(m_tis);
|
|
tis.impactCount(m_triggeredMines.size());
|
|
tis.bitfield().resize((m_triggeredMines.size() + 7) / 8);
|
|
tis.setId(dds::core::optional<rti::core::int64>(m_setId));
|
|
|
|
int i = 0;
|
|
for (const auto &mine : qAsConst(m_triggeredMines))
|
|
{
|
|
// Triggered Impact == 0, if mine is disarmed/exploded
|
|
LtsUtils::BitArray::setBit(tis.bitfield(), i++, !mine.isTriggered);
|
|
}
|
|
if (m_tis != tis)
|
|
{
|
|
m_tis = tis;
|
|
m_tis.sampleTime(partitionTimeMSec());
|
|
return m_mainHandler->dds()->dts()->publish(m_tis);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ObjectMineAreaNull::publishDusMineStatus()
|
|
{
|
|
// DusMineStatus mines vector is coherent to triggered impacts bitfield
|
|
DusMineState dms(m_dms);
|
|
|
|
dms.mines().resize(m_triggeredMines.size());
|
|
dms.setId(dds::core::optional<rti::core::int64>(m_setId));
|
|
int i = 0;
|
|
for (const auto &mine : qAsConst(m_triggeredMines))
|
|
{
|
|
const DusMine entry(mine.mineId, mine.isTriggered, mine.chargeTypeId, {mine.position.x(), mine.position.y()});
|
|
dms.mines()[i++] = entry;
|
|
}
|
|
|
|
if (m_dms != dms)
|
|
{
|
|
m_dms = dms;
|
|
m_dms.sampleTime(partitionTimeMSec());
|
|
return m_mainHandler->dds()->dts()->publish(m_dms);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QPolygonF ObjectMineAreaNull::generateForm()
|
|
{
|
|
std::vector<Core::GeoPosition> vec;
|
|
vec.reserve(m_triggeredMines.size());
|
|
QPolygonF tmp;
|
|
tmp.reserve(m_triggeredMines.size());
|
|
for (const auto &mine : qAsConst(m_triggeredMines))
|
|
{
|
|
vec.emplace_back(Core::GeoPosition(mine.position.x(), mine.position.y(), 0));
|
|
tmp.push_back(mine.position);
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
} // namespace
|