376 lines
13 KiB
C++
Executable File
376 lines
13 KiB
C++
Executable File
/**
|
|
* Handler for the HMI language
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
#include "object_functional_area.h"
|
|
#include "special_area_provider.h"
|
|
#include "Utils/polygons.h"
|
|
#include "handler_charge_administration.h"
|
|
#include "settings.h"
|
|
|
|
#include <LtsCoordTrans/lts_coord_trans.h>
|
|
|
|
#include <QtGui/QPolygonF>
|
|
#include <QtCore/QTimer>
|
|
#include <cmath>
|
|
|
|
namespace AreaEffectSimulation
|
|
{
|
|
|
|
ObjectFunctionalArea::ObjectFunctionalArea(MainHandler *mainHandler,
|
|
QObject *parent)
|
|
: ObjectBaseTmpl(mainHandler, QStringLiteral("FunctionalArea"), parent)
|
|
{
|
|
}
|
|
|
|
ObjectFunctionalArea::~ObjectFunctionalArea()
|
|
{
|
|
delete m_timer;
|
|
removeTopics();
|
|
}
|
|
|
|
Core::FunctionReplyObject ObjectFunctionalArea::createObject(const Database::AesFunctionalArea &data)
|
|
{
|
|
DEBUG_LOG(m_logger) << "ObjectFunctionalArea::createObject aesId=" << data.id
|
|
<< " data.effectStateId=" << data.effectStateId;
|
|
Core::FunctionReplyObject ret;
|
|
bool setIsCentral = false;
|
|
|
|
m_dataAesFunctionalArea = data;
|
|
|
|
|
|
if (data.supplyMode == AesOperatingMode::OmWaitingTime)
|
|
{
|
|
setIsCentral = true;
|
|
m_data.participantId = data.participantId;
|
|
m_timer = new QTimer(this);
|
|
|
|
connect(m_timer, &QTimer::timeout,
|
|
this, &ObjectFunctionalArea::myTimerSlot, Qt::UniqueConnection);
|
|
|
|
DEBUG_LOG(m_logger) << "connect participantPositionChanged";
|
|
connect(m_mainHandler->dds()->ppmDtc().get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged,
|
|
this, &ObjectFunctionalArea::onParticipantPositionChanged);
|
|
|
|
DEBUG_LOG(m_logger) << " onParticipantPositionChanged.....";
|
|
auto cb = [this](const ParticipantManagement::ParticipantPosition & data)
|
|
{
|
|
onParticipantPositionChanged(data, DataModification::eAdded);
|
|
};
|
|
m_mainHandler->dds()->ppmDtc()->participantPositions(cb);
|
|
DEBUG_LOG(m_logger) << " onParticipantPositionChanged.....DONE";
|
|
|
|
}
|
|
ret = ObjectBaseTmpl::createObject(m_dataAesFunctionalArea, false, setIsCentral);
|
|
|
|
return ret;
|
|
}
|
|
|
|
Core::FunctionReplyObject ObjectFunctionalArea::updateObject(const Database::AesFunctionalArea &data)
|
|
{
|
|
m_dataAesFunctionalArea = data;
|
|
Core::FunctionReplyObject ret = ObjectBaseTmpl::updateObject(data);
|
|
Q_UNUSED(ret)
|
|
if (ret.error() || (isOnlyObjectNameModifiable() && (data.id > 0))) // data.id > 0 -> negative values from oc always get a full update
|
|
return ret;
|
|
|
|
// only allow some fields
|
|
auto tmpData(m_data);
|
|
tmpData.id = std::abs(data.id);
|
|
tmpData.name = data.name;
|
|
tmpData.effectStart = data.effectStart;
|
|
tmpData.effectDuration = data.effectDuration;
|
|
tmpData.position = data.position;
|
|
DEBUG_LOG(m_logger) << "tmpData.position=" << data.position.x() << "/" << data.position.y();
|
|
tmpData.participantId = data.participantId;
|
|
tmpData.partyId = data.partyId;
|
|
tmpData.chargeTypeId = data.chargeTypeId;
|
|
tmpData.width = data.width;
|
|
tmpData.length = data.length;
|
|
tmpData.pointSymbol = data.pointSymbol;
|
|
tmpData.functionalAreaTypeId = data.functionalAreaTypeId;
|
|
tmpData.deconMode = data.deconMode;
|
|
tmpData.deconTime = data.deconTime;
|
|
tmpData.maintMode = data.maintMode;
|
|
tmpData.maintTime = data.maintTime;
|
|
tmpData.medicMode = data.medicMode;
|
|
tmpData.medicTime = data.medicTime;
|
|
tmpData.effectStateId = data.effectStateId; // overwrite for oc
|
|
tmpData.properties = data.properties;
|
|
|
|
if (!m_mainHandler->db()->update(tmpData))
|
|
return Core::FunctionReplyObject(data.id, tr_lts("dds", "Error updating functional area with id %1 in database.")).arg(m_data.id);
|
|
|
|
m_data = std::move(tmpData);
|
|
|
|
m_publishDataTimer->start();
|
|
checkEnterNewState();
|
|
|
|
return Core::FunctionReplyObject(data.id); // data not m_data for the possible negative id in the oc-laptop
|
|
}
|
|
|
|
Core::FunctionReplyObject ObjectFunctionalArea::removeObject()
|
|
{
|
|
Core::FunctionReplyObject ret = ObjectBaseTmpl::removeObject();
|
|
return ret;
|
|
}
|
|
|
|
bool ObjectFunctionalArea::removeObjectFromDb()
|
|
{
|
|
return m_mainHandler->db()->removeAesFunctionalArea(m_data.id);
|
|
|
|
}
|
|
|
|
void ObjectFunctionalArea::setEffectState(AesEffectState newState)
|
|
{
|
|
ObjectBaseTmpl::setEffectState(newState);
|
|
}
|
|
|
|
void ObjectFunctionalArea::onPublishData()
|
|
{
|
|
|
|
if (m_data.id == 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << "ObjectFunctionalArea::onPublishData return";
|
|
return;
|
|
}
|
|
|
|
ObjectBaseTmpl::onPublishData();
|
|
|
|
if (!m_mainHandler->db()->update(m_data))
|
|
ERROR_LOG(m_logger) << "Error updating AesFunctionalArea-data in database";
|
|
|
|
DEBUG_LOG(m_logger) << "onPublishData m_data.position=" << m_data.position.x() << "/" << m_data.position.y()
|
|
<< " id=" << m_data.id
|
|
<< " effectStateId=" << m_data.effectStateId;
|
|
|
|
const auto pointSymbol = m_data.pointSymbol.toStdString();
|
|
|
|
FunctionalArea ddsData(m_data.id,
|
|
m_data.name.toStdString(),
|
|
effectState() == AesEffectState::EsRemoved,
|
|
false,
|
|
partitionTimeMSec(),
|
|
{m_data.chargeTypeId,0,0},
|
|
m_data.effectDuration,
|
|
toOptional(toMSec(m_data.effectStart)),
|
|
m_data.effectStateId,
|
|
m_data.effectSourceId,
|
|
toOptional(m_data.partyId),
|
|
toOptional(m_data.participantId),
|
|
m_data.effectMarkingInTa,
|
|
m_data.externalId,
|
|
m_data.isCentral,
|
|
m_data.properties.toStdString(),
|
|
Area(Core::GeoPosition2D(m_data.position.x(),
|
|
m_data.position.y()),
|
|
m_data.width,
|
|
m_data.length,
|
|
0.0),
|
|
toOptional(pointSymbol),
|
|
m_data.functionalAreaTypeId,
|
|
m_data.deconMode,
|
|
m_data.deconTime,
|
|
m_data.maintMode,
|
|
m_data.maintTime,
|
|
m_data.medicMode,
|
|
m_data.medicTime,
|
|
m_data.supplyMode,
|
|
m_data.supplyTime,
|
|
m_data.notfightMode,
|
|
m_data.notfightTime
|
|
);
|
|
m_mainHandler->dds()->dts()->publish(ddsData);
|
|
publishAiv();
|
|
}
|
|
|
|
void ObjectFunctionalArea::publishAiv()
|
|
{
|
|
// Todo: calculate unique id.
|
|
// Better than aiv.id(1000 * aesItemId + AesType::AtFunctionalArea);
|
|
|
|
DEBUG_LOG(m_logger) << "publishAiv";
|
|
|
|
const QPolygonF poly = Polygons::functionalArea(m_data);
|
|
const QRectF bounds(poly.boundingRect());
|
|
|
|
AesItemView aiv(m_aiv);
|
|
aiv.aesItemId = m_data.id;
|
|
aiv.chargeStruct.chargeTypeId = m_data.chargeTypeId;
|
|
aiv.effectStart = toMSec(m_data.effectStart);
|
|
ddsVecFromPoly(poly, aiv.form);
|
|
aiv.boundingBoxBottomLeft = Core::GeoPosition2D(bounds.bottomLeft().x(), bounds.bottomLeft().y());
|
|
aiv.boundingBoxTopRight = Core::GeoPosition2D(bounds.topRight().x(), bounds.topRight().y());
|
|
aiv.aesTypeId = AesType::AtFunctionalArea;
|
|
aiv.effectStateId = effectState();
|
|
aiv.id = 1000 * m_data.id + static_cast<int>(AesType::AtFunctionalArea);
|
|
if (m_data.partyId != 0)
|
|
aiv.partyId = m_data.partyId;
|
|
|
|
checkIsCentralAndPublish(aiv.form, m_aiv.form, m_data.isCentral);
|
|
|
|
if (aiv != m_aiv)
|
|
{
|
|
aiv.sampleTime = partitionTimeMSec();
|
|
m_aiv = aiv;
|
|
m_mainHandler->dds()->dts()->publish(aiv);
|
|
emit newAiv(aiv);
|
|
}
|
|
}
|
|
|
|
void ObjectFunctionalArea::removeTopics()
|
|
{
|
|
auto dts = m_mainHandler->dds()->dts();
|
|
dts->removeFunctionalAreaByKey(m_data.id);
|
|
dts->removeAesItemViewByKey(1000 * m_data.id + static_cast<int>(AesType::AtFunctionalArea));
|
|
emit removeAiv(m_data.id);
|
|
}
|
|
|
|
QPolygonF ObjectFunctionalArea::generateForm()
|
|
{
|
|
return Polygons::functionalArea(m_data);
|
|
}
|
|
|
|
QPointF ObjectFunctionalArea::geographic2Utm(const Core::GeoPosition2D &geoPos, int *zone)
|
|
{
|
|
const int zoneToUse = zone ? *zone : -1;
|
|
auto utm = LtsCoordTrans::UtmCoordinate::fromGeographic(geoPos.lon, geoPos.lat, zoneToUse);
|
|
if (zone)
|
|
*zone = utm.zone;
|
|
return QPointF(utm.x, utm.y);
|
|
}
|
|
|
|
|
|
void ObjectFunctionalArea::onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType)
|
|
{
|
|
|
|
if (modType != DataModification::eRemoved && (data.participantId == m_data.participantId))
|
|
{
|
|
DEBUG_LOG(m_logger) << " onParticipantPositionChanged....."
|
|
<< " participantId=" << data.participantId
|
|
<< " aesId=" << m_data.id
|
|
<< " suppyParticipantId=" << m_data.participantId;
|
|
DEBUG_LOG(m_logger) << "Supply Truck: onParticipantPositionChanged: " << data;
|
|
if (m_activePosAvailable)
|
|
{
|
|
int zone = -1;
|
|
|
|
DEBUG_LOG(m_logger) << "New Supply Truck Position participantId: " << data.participantId
|
|
<< " pos: lat=" << data.pos.lat << " lon=" << data.pos.lon;
|
|
|
|
const QPointF participantPosUtmPoint = geographic2Utm(data.pos, &zone);
|
|
DEBUG_LOG(m_logger) << "participantPosUtmPoint=" << participantPosUtmPoint.x() << "/" << participantPosUtmPoint.y()
|
|
<< " zone=" << zone;
|
|
|
|
|
|
|
|
const QPointF activationPosUtmPoint = geographic2Utm(m_activatePos, &zone);
|
|
DEBUG_LOG(m_logger) << "activationPosUtmPoint=" << activationPosUtmPoint.x() << "/" << activationPosUtmPoint.y()
|
|
<< " zone=" << zone;
|
|
|
|
|
|
//double squareDistance = LtsCoordTrans::squareDistance(participantPosUtmPoint, activationPosUtmPoint);
|
|
|
|
|
|
const double distanceSquared = LtsCoordTrans::squareDistance(data.pos.lon, data.pos.lat, m_activatePos.lon, m_activatePos.lat);
|
|
DEBUG_LOG(m_logger) << "squareDistance=" << distanceSquared
|
|
<< " distance = " << sqrt(distanceSquared)
|
|
<< " getMaximumStepLengthStanding=" << Settings::getMaximumStepLengthStanding();
|
|
|
|
|
|
// vehicle does not move
|
|
if (distanceSquared < Settings::getMaximumStepLengthStanding() * Settings::getMaximumStepLengthStanding())
|
|
{
|
|
DEBUG_LOG(m_logger) << "Supply Truck is not moving";
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "Supply Truck is moving! state=" << m_data.effectStateId;
|
|
if (m_data.effectStateId == AesEffectState::EsActivated)
|
|
{
|
|
m_data.effectStateId = AesEffectState::EsPaused;
|
|
m_dataAesFunctionalArea.effectStateId = AesEffectState::EsPaused;
|
|
DEBUG_LOG(m_logger) << "Supply Truck is moving Timer neu setzen!";
|
|
updateTimer();
|
|
}
|
|
}
|
|
}
|
|
m_data.position.setX(data.pos.lon);
|
|
m_data.position.setY(data.pos.lat);
|
|
m_data.partyId = data.partyId;
|
|
m_data.isCentral = true;
|
|
|
|
m_dataAesFunctionalArea.position.setX(data.pos.lon);
|
|
m_dataAesFunctionalArea.position.setY(data.pos.lat);
|
|
m_dataAesFunctionalArea.partyId = data.partyId;
|
|
m_dataAesFunctionalArea.isCentral = true;
|
|
{
|
|
int zone = -1;
|
|
const QPointF participantPosUtmPoint = geographic2Utm(data.pos, &zone);
|
|
|
|
QPointF utmPointShift;
|
|
utmPointShift.setX(participantPosUtmPoint.x() - m_dataAesFunctionalArea.length / 2);
|
|
utmPointShift.setY(participantPosUtmPoint.y() - m_dataAesFunctionalArea.width / 2);
|
|
DEBUG_LOG(m_logger) << "data.pos=" << data.pos
|
|
<< " participantPosUtmPoint=" << participantPosUtmPoint.x() << "/" << participantPosUtmPoint.y()
|
|
<< " utmPointShift=" << utmPointShift.x() << "/" << utmPointShift.y()
|
|
<< " length=" << m_dataAesFunctionalArea.length
|
|
<< " width=" << m_dataAesFunctionalArea.width;
|
|
Core::GeoPosition2D posShift;
|
|
LtsCoordTrans::UtmCoordinate utm;
|
|
|
|
utm.x = utmPointShift.x();
|
|
utm.y = utmPointShift.y();
|
|
utm.zone = zone;
|
|
|
|
QPointF point = utm.geographic();
|
|
|
|
|
|
m_activatePos.lon = point.x();
|
|
m_activatePos.lat = point.y();
|
|
m_dataAesFunctionalArea.position.setX(point.x());
|
|
m_dataAesFunctionalArea.position.setY(point.y());
|
|
m_data.position.setX(point.x());
|
|
m_data.position.setY(point.y());
|
|
DEBUG_LOG(m_logger) << "m_activatePos=" << m_activatePos;
|
|
}
|
|
m_activePosAvailable = true;
|
|
|
|
DEBUG_LOG(m_logger) << "onParticipantPositionChanged: Vor updateObject";
|
|
updateObject(m_dataAesFunctionalArea);
|
|
DEBUG_LOG(m_logger) << "onParticipantPositionChanged: Vor onPublishData";
|
|
onPublishData();
|
|
}
|
|
}
|
|
|
|
void ObjectFunctionalArea::updateTimer()
|
|
{
|
|
|
|
DEBUG_LOG(m_logger) << "TargetTimer::updateTimer t=" << Settings::getActivationTimeAfterStopSupplyTruck();
|
|
m_timer->setSingleShot(true);
|
|
m_timer->start(Settings::getActivationTimeAfterStopSupplyTruck());
|
|
}
|
|
|
|
void ObjectFunctionalArea::myTimerSlot()
|
|
{
|
|
|
|
// m_activePosAvailable = false;
|
|
m_data.effectStateId = AesEffectState::EsActivated;
|
|
m_dataAesFunctionalArea.effectStateId = AesEffectState::EsActivated;
|
|
DEBUG_LOG(m_logger) << "TimerSlot Setze Supply-Truck active aesItemId=" << m_aiv.aesItemId
|
|
<< " participantId=" << m_data.participantId
|
|
<< " effectStateId=" << m_data.effectStateId;
|
|
DEBUG_LOG(m_logger) << "onParticipantPositionChanged: Vor updateObject";
|
|
updateObject(m_dataAesFunctionalArea);
|
|
DEBUG_LOG(m_logger) << "onParticipantPositionChanged: Vor onPublishData";
|
|
onPublishData();
|
|
|
|
}
|
|
|
|
} // Namespace AreaEffectSimulation
|
|
|