/** * 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 #include #include #include 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_def::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 + 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 + 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