/** * @RDE_HEADER@ * Exportieren einer Uebung in eine MSDL-Datei * $Id$ * $HeadURL$ * $Author$ */ // at first to avoid compiler errors on windows #include #include "msdl_export.h" #include "ui_msdl_export.h" #include "msdl_export_scenario_data.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace msdl { using organizationsType = msdl_1::MilitaryScenarioType::Organizations_type; using equipType = organizationsType::Equipment_type; using equipItemType = equipType::EquipmentItem_type; using coordChoiceType = equipItemType::Disposition_type::Location_type::CoordinateChoice_type; using coordDataType = equipItemType::Disposition_type::Location_type::CoordinateData_type; using descriptionType = schemas::modelID::modelIdentificationType::description_type; using equipOptional = organizationsType::Equipment_optional; using equipRelationsType = equipItemType::Relations_type; using unitsType = organizationsType::Units_type; using unitType = unitsType::Unit_type; using relationsType = unitType::Relations_type; using forceRelationChoiceType = relationsType::ForceRelation_type::ForceRelationChoice_type; using forceRelationDataType = relationsType::ForceRelation_type::ForceRelationData_type; using forceSidesType = msdl_1::MilitaryScenarioType::ForceSides_type; using forceSideType = forceSidesType::ForceSide_type; using ownerChoiceType = equipRelationsType::HoldingOrganization_type::OwnerChoice_type; using ownerDataType = equipRelationsType::HoldingOrganization_type::OwnerData_type; namespace Private { static msdl_1::MilitaryScenarioType::ScenarioID_type createTagScenarioID(const msdl::ScenarioDataDialog &dlgData); static msdl_1::MilitaryScenarioType::ForceSides_type createTagForceSides(const QMap &mapForces, QMap &mapForceHandles); static msdl_1::MilitaryScenarioType::Options_type createTagOptions(); static msdl_1::MilitaryScenarioType::Environment_type createTagEnvironment(); static msdl_1::MilitaryScenarioType::Organizations_type::Units_type createTagUnits(const QMap &mapParticipants, const QMap &mapForceHandles, QMap &mapParticipantsUUIDs); static msdl_1::MilitaryScenarioType::Organizations_type::Equipment_type createTagEquipment(const QMap &mapParticipants, const QMap &mapParticipantsUUIDs, const QMap &mapParticipantPositions, const QMap &mapTypes, const QMap &mapEquipment, const QMap &mapForceHandles, NGL::INGLLogger &logger); static void writeMilitaryScenario(const msdl_1::MilitaryScenarioType &miType, const std::string &filename); } ExportMsdl::ExportMsdl(LtsSession::LtsSession *pSession, QWidget *parent) : NGLDialog(parent) , mLogger(msdl::getLogger("ExportMsdl")) , mUi(new Ui_MSDLExport) , m_pSession(pSession) { mUi->setupUi(this); setWindowTitle(tr("Export Exercise Scenario")); connect(mUi->tbExportFile, &QToolButton::clicked, this, &ExportMsdl::onTbExportFileClicked); connect(mUi->m_pushButton_StartExport, &QPushButton::clicked, this, &ExportMsdl::onApply); QString strExportFile = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pathSelectedExportFile"), QString()).toString(); if (strExportFile.size()) { mUi->leExportFile->setText(strExportFile); mUi->m_pushButton_StartExport->setEnabled(true); } if (!m_pSession->getDtc(m_ppmDtc) || !m_pSession->getDtc(m_exmDtc) || !m_pSession->getDtc(m_opmDtc)) { ERROR_LOG(mLogger) << "Fetching m_ppmDtc or m_exmDtc or m_opmDtc failed!"; setEnabled(false); } } ExportMsdl::~ExportMsdl() { delete mUi; } void ExportMsdl::onTbExportFileClicked() { QString strExportPath = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pathSelectedExportFile"), QStringLiteral("/tmp/msdl.xml")).toString(); QString caption(tr("Select File")); QFileDialog fileDialog(this, caption, strExportPath, tr("XML files (*.xml)")); fileDialog.setAcceptMode(QFileDialog::AcceptSave); QList urls; urls << QUrl::fromLocalFile(strExportPath); fileDialog.setSidebarUrls(urls); if (fileDialog.exec()) // TODO: use show(), use signals & slots ! { strExportPath = fileDialog.selectedFiles().constFirst(); mUi->leExportFile->setText(strExportPath); LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("pathSelectedExportFile"), strExportPath); } mUi->m_pushButton_StartExport->setEnabled(!mUi->leExportFile->text().isEmpty()); } msdl_1::MilitaryScenarioType::ScenarioID_type Private::createTagScenarioID(const msdl::ScenarioDataDialog &dlgData) { QDate cuDa = QDate::currentDate(); xml_schema::date da(cuDa.year(), cuDa.month(), cuDa.day()); // Block ScenarioID: General information msdl_1::MilitaryScenarioType::ScenarioID_type::name_type nameType(dlgData.exerciseName().toStdString()); msdl_1::MilitaryScenarioType::ScenarioID_type::type_type typeType("BOM"); msdl_1::MilitaryScenarioType::ScenarioID_type::version_type versionType(dlgData.exerciseVersion().toStdString()); msdl_1::MilitaryScenarioType::ScenarioID_type::modificationDate_type modDateType(da); msdl_1::MilitaryScenarioType::ScenarioID_type::securityClassification_type secClassType("Unclassified"); msdl_1::MilitaryScenarioType::ScenarioID_type::description_type desType(dlgData.exerciseDescription().toStdString()); msdl_1::MilitaryScenarioType::ScenarioID_type scIDType(nameType, typeType, versionType, modDateType, secClassType, desType); msdl_1::MilitaryScenarioType::ScenarioID_type::applicationDomain_type domainType(dlgData.exerciseDomain().toStdString()); scIDType.applicationDomain(domainType); // ScenarioID: poc information as part of the general information (Mandatory!) msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type pocType(dlgData.pocType().toStdString()); pocType.pocName(dlgData.pocAuthor().toStdString()); msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocEmail_sequence pocSeqMail; pocSeqMail.push_back(msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocEmail_type(dlgData.pocEmail().toStdString())); pocType.pocEmail(pocSeqMail); msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocTelephone_sequence pocSeqTelephone; pocSeqTelephone.push_back(msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocTelephone_type(dlgData.pocTelephone().toStdString())); // pocSeqTelephone.push_back(msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocTelephone_type("+421-1080-4288")); // Example for adding further telephone numbers pocType.pocTelephone(pocSeqTelephone); msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocOrg_type pocOrgType(dlgData.pocOrganization().toStdString()); pocType.pocOrg(pocOrgType); msdl_1::MilitaryScenarioType::ScenarioID_type::poc_sequence pocSequence; pocSequence.push_back(pocType); scIDType.poc(pocSequence); scIDType.purpose(dlgData.exercisePurpose().toStdString()); scIDType.modificationDate(da); return scIDType; } msdl_1::MilitaryScenarioType::ForceSides_type Private::createTagForceSides(const QMap &mapForces, QMap &mapForceHandles) { msdl_1::MilitaryScenarioType::ForceSides_type foType; msdl_1::MilitaryScenarioType::ForceSides_type::ForceSide_sequence &foSiSe(foType.ForceSide()); // We have to create all UUIDs first QMap mapUUID2Force; for (const ParticipantManagement::Party &party : mapForces) { // Skip Pool and O/C Service if (party.id() == 0 || party.id() == 1) continue; QString obHaStr = QUuid::createUuid().toString(); obHaStr = obHaStr.mid(1, obHaStr.size() - 2); mapUUID2Force[obHaStr] = party; } // Create ForceSide for each party QMapIterator itForce(mapUUID2Force); while (itForce.hasNext()) { itForce.next(); const QString &strUUID = itForce.key(); const ParticipantManagement::Party &party = itForce.value(); msdl_1::ForceSideType::ObjectHandle_type obHaTy(strUUID.toStdString().c_str()); msdl_1::ForceSideType::ForceSideName_type foSiNaTy(party.name().c_str()); msdl_1::ForceSideType foSiTy(obHaTy, foSiNaTy); // Connect all parties among each other by using their relationship status (Hostile, Friend, ...) msdl_1::ForceSideType::Associations_type::Association_sequence asSequence; QMapIterator itRelationship(mapUUID2Force); while (itRelationship.hasNext()) { itRelationship.next(); if (itRelationship.key() == strUUID) continue; /* * Identify relationship. Only FR / HO / NEUTR / UNK are used */ ParticipantManagement::Role role = itRelationship.value().role(); msdl_1::ForceSideType::Associations_type::Association_type::Relationship_type relType = msdl_1::ForceSideType::Associations_type::Association_type::Relationship_type::UNK; if (role == ParticipantManagement::Role_def::Enemy) relType = msdl_1::ForceSideType::Associations_type::Association_type::Relationship_type::HO; else if (role == ParticipantManagement::Role_def::Friend) relType = msdl_1::ForceSideType::Associations_type::Association_type::Relationship_type::FR; else if (role == ParticipantManagement::Role_def::Neutral) relType = msdl_1::ForceSideType::Associations_type::Association_type::Relationship_type::NEUTRL; msdl_1::ForceSideType::Associations_type::Association_type aType(itRelationship.key().toStdString().c_str(), relType); asSequence.push_back(aType); } msdl_1::ForceSideType::Associations_type asType; asType.Association(asSequence); foSiTy.Associations(asType); foSiSe.push_back(foSiTy); mapForceHandles[party.id()] = strUUID; } return foType; } msdl_1::MilitaryScenarioType::Options_type Private::createTagOptions() { msdl_1::MilitaryScenarioType::Options_type opType(""); opType.MSDLVersion("1.0.0"); msdl_1::boolean aggrBased = false; msdl_1::OrganizationDetailType orType(aggrBased); msdl_1::OrganizationDetailType::AggregateEchelon_type aggrEchelon(msdl_1::OrganizationDetailType::AggregateEchelon_type::enumEchelon::BATTALION); orType.AggregateEchelon(aggrEchelon); opType.OrganizationDetail(orType); return opType; } msdl_1::MilitaryScenarioType::Environment_type Private::createTagEnvironment() { msdl_1::MilitaryScenarioType::Environment_type enType; // Time msdl_1::MilitaryScenarioType::Environment_type::ScenarioTime_type timeType("2013-05-28T17:37:24Z"); enType.ScenarioTime(timeType); // Upper Right msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::UpperRight_type::CoordinateChoice_type choiceType_ur(msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::UpperRight_type::CoordinateChoice_type::GCC); coordDataType::GCC_type::X_type x_ur(123); coordDataType::GCC_type::X_type y_ur(456); coordDataType::GCC_type::Z_type z_ur(789); coordDataType::GCC_type utTy_ur(x_ur, y_ur, z_ur); coordDataType coDaTy_ur; coDaTy_ur.GCC(utTy_ur); msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::UpperRight_type urType(choiceType_ur, coDaTy_ur); // Lower Left msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::LowerLeft_type::CoordinateChoice_type choiceType(msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::UpperRight_type::CoordinateChoice_type::GCC); coordDataType::GCC_type::X_type x_ll(987); coordDataType::GCC_type::X_type y_ll(654); coordDataType::GCC_type::Z_type z_ll(321); coordDataType::GCC_type utTy_ll(x_ll, y_ll, z_ll); coordDataType coDaTy_ll; coDaTy_ll.GCC(utTy_ll); msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::LowerLeft_type llType(choiceType, coDaTy_ll); // AreaOfInterest msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type areaType(urType, llType); enType.AreaOfInterest(areaType); return enType; } msdl_1::MilitaryScenarioType::Organizations_type::Units_type Private::createTagUnits(const QMap &mapParticipants, const QMap &mapForceHandles, QMap &mapParticipantsUUIDs) { mapParticipantsUUIDs.clear(); // Create unique identifier for all participants for (const ParticipantManagement::Participant &participant : mapParticipants) { QString obHaStr = QUuid::createUuid().toString(); obHaStr = obHaStr.mid(1, obHaStr.size() - 2); mapParticipantsUUIDs[participant.id()] = obHaStr.toStdString(); } unitsType unitsTy; unitsType::Unit_sequence &unSe(unitsTy.Unit()); for (auto it = mapForceHandles.begin(); it != mapForceHandles.end(); ++it) { for (const ParticipantManagement::Participant &participant : mapParticipants) { // Does participant belong to currently exported party? if (participant.partyId() != it.key()) continue; if (participant.isDeleted()) continue; forceRelationDataType foReDaTy; forceRelationChoiceType foReChTy = forceRelationChoiceType::FORCE_SIDE; if (participant.superiorId() == 0) // Vorgesetzter ist die Truppe { foReChTy = forceRelationChoiceType::FORCE_SIDE; const QString &obHaStr = it.value(); foReDaTy.ForceSideHandle(obHaStr.toStdString().c_str()); } else { foReChTy = forceRelationChoiceType::UNIT; msdl_1::CommandRelationType::CommandingSuperiorHandle_type handle(mapParticipantsUUIDs.value(participant.superiorId())); forceRelationDataType::CommandRelation_type cmdRelation(handle, msdl_1::CommandRelationType::CommandRelationshipType_type::TACON); // No idea about the enumeration values (ADCON, None, etc.) foReDaTy.CommandRelation(cmdRelation); } unitType::ObjectHandle_type unObHaTy(mapParticipantsUUIDs.value(participant.id())); unitType::SymbolIdentifier_type syIdTy = "S--------------"; relationsType::ForceRelation_type foReTy(foReChTy, foReDaTy); unitType::Relations_type reTy(foReTy); unitType unitTy(unObHaTy, syIdTy, reTy); unitTy.SymbolIdentifier(syIdTy); unitType::Name_type naTy(participant.designator().c_str()); unitTy.Name(naTy); unSe.push_back(unitTy); } } return unitsTy; } msdl_1::MilitaryScenarioType::Organizations_type::Equipment_type Private::createTagEquipment(const QMap &mapParticipants, const QMap &mapParticipantsUUIDs, const QMap &mapParticipantPositions, const QMap &mapTypes, const QMap &mapEquipment, const QMap &mapForceHandles, NGL::INGLLogger &logger) { equipType eqTy; equipType::EquipmentItem_sequence &eqItSeq(eqTy.EquipmentItem()); for (auto it = mapForceHandles.begin(); it != mapForceHandles.end(); ++it) { const int32_t partyId = it.key(); for (const ParticipantManagement::Participant &participant : mapParticipants) { // Does participant belong to current party? if (participant.partyId() != partyId) continue; if (participant.isDeleted()) continue; /* * Identify equipment owner handle (UUID) * According to ICD is 'ownerChoise' always unit */ ownerDataType::UnitOwnerHandle_type foOwHaTy; foOwHaTy = mapParticipantsUUIDs.value(participant.id()).c_str(); ownerDataType owDaTy; owDaTy.UnitOwnerHandle(foOwHaTy); ownerChoiceType owChTy(ownerChoiceType::UNIT); equipRelationsType::HoldingOrganization_type hoOrTy(owChTy, owDaTy); equipItemType::Relations_type reTy(hoOrTy); // Equipment modifiers auto vecDISEntities = mapTypes.value(participant.typeId()).disEntities(); if (!vecDISEntities.size()) { WARNING_LOG(logger) << "Participant id " << participant.id() << " belongs to a type id " << participant.typeId() << " which has no DIS id! Skipping export of participant!"; continue; } // DIS entity id: Does not matter if this type has more than 1 DIS id. Simply pick first one equipItemType::EquipmentSymbolModifiers_type eqModifiers(ParticipantManagement::DIS::convertDISTypeInteger2MSDLString(vecDISEntities[0]).toStdString().c_str()); eqModifiers.Quantity(1); eqModifiers.EquipmentType("S--------------"); // Coordinates and Elevation // Unclear: Are participant coordinates correctly specified converted? coordDataType::GCC_type::X_type x(mapParticipantPositions[participant.id()].pos().lon()); coordDataType::GCC_type::X_type y(mapParticipantPositions[participant.id()].pos().lat()); coordDataType::GCC_type::Z_type z(mapParticipantPositions[participant.id()].pos().z()); coordDataType::GCC_type utTy(x, y, z); coordDataType coDaTy; coDaTy.GCC(utTy); coordChoiceType coChTy(coordChoiceType::enumCoordinateSystemType::GCC); /* // UTM Version coordDataType::UTM_type::UTMGridZone_type utmGriZoTy("UTM"); coordDataType::UTM_type::UTMEasting_type utmEaTy(mapParticipantPositions[participant.id()].pos().lon()); coordDataType::UTM_type::UTMNorthing_type utmNoTy(mapParticipantPositions[participant.id()].pos().lat()); coordDataType::UTM_type utTy(utmGriZoTy, utmEaTy, utmNoTy); coordDataType::UTM_type::ElevationAGL_type elType(mapParticipantPositions[participant.id()].pos().z()); utTy.ElevationAGL(elType); coordDataType coDaTy; coDaTy.UTM(utTy); coordChoiceType coChTy(coordChoiceType::enumCoordinateSystemType::UTM); */ equipItemType::Disposition_type::Location_type loTy(coChTy, coDaTy); equipItemType::Disposition_type diTy(loTy); // Direction of Movement equipItemType::Disposition_type::DirectionOfMovement_type loDir(0.0); diTy.DirectionOfMovement(loDir); // SIDC equipItemType::SymbolIdentifier_type syIdTy("S--------------"); // Finally create equipment equipItemType eqItTy(foOwHaTy, syIdTy, diTy, reTy); eqItTy.EquipmentSymbolModifiers(eqModifiers); // Create UUID for equipment QString obHaStr = QUuid::createUuid().toString(); obHaStr = obHaStr.mid(1, obHaStr.size() - 2); equipItemType::ObjectHandle_type eqObHaTy = obHaStr.toStdString().c_str(); eqItTy.ObjectHandle(eqObHaTy); // Participant -> TypeId -> EquipmentId -> Equipment name (Easy workflow, right?) equipItemType::Name_type naTy(mapEquipment.value(mapTypes.value(participant.typeId()).equipmentTypeId()).name()); eqItTy.Name(naTy); eqItTy.SymbolIdentifier(syIdTy); eqItSeq.push_back(eqItTy); } } return eqTy; } void Private::writeMilitaryScenario(const msdl_1::MilitaryScenarioType &miType, const std::string &filename) { xml_schema::namespace_infomap map; map["msdl"].name = "urn:sisostds:scenario:military:data:draft:msdl:1"; map["msdl"].schema = NGL::findFile(NGL::FileType::ConfigFile, QStringLiteral("MilitaryScenario_1.0.0.xsd")).toStdString(); map["modelID"].name = "http://www.sisostds.org/schemas/modelID"; std::ofstream ofs(filename); msdl_1::MilitaryScenario(ofs, miType, map); } void ExportMsdl::onApply() { ScenarioDataDialog dlg(this, m_pSession, m_opmDtc, m_exmDtc); int retCode = dlg.exec(); if (retCode == QDialog::Rejected) { close(); return; } try { const auto participants = m_ppmDtc->participants(); QMap mapForceHandles; QMap mapParticipantsUUIDs; msdl_1::MilitaryScenarioType::ScenarioID_type scIDType = Private::createTagScenarioID(dlg); msdl_1::MilitaryScenarioType::ForceSides_type foType = Private::createTagForceSides(m_ppmDtc->partys(), mapForceHandles); msdl_1::MilitaryScenarioType::Options_type opType = Private::createTagOptions(); msdl_1::MilitaryScenarioType miType(scIDType, opType, foType); msdl_1::MilitaryScenarioType::Environment_type enType = Private::createTagEnvironment(); unitsType unitsTy = Private::createTagUnits(participants, mapForceHandles, mapParticipantsUUIDs); equipType equipmentTy = Private::createTagEquipment(participants, mapParticipantsUUIDs, m_ppmDtc->participantPositions(), m_ppmDtc->types(), m_ppmDtc->equipmentTypes(), mapForceHandles, mLogger); equipType::EquipmentItem_sequence &eqItSeq(equipmentTy.EquipmentItem()); organizationsType orTy(unitsTy); miType.Environment(enType); if ( eqItSeq.size() > 0) { INFO_LOG(mLogger) << "orTy.Equipment(equipmentTy)"; orTy.Equipment(equipmentTy); } miType.Organizations(orTy); QString fileName = mUi->leExportFile->text(); QFileInfo fileInfo(fileName); if ( !fileInfo.exists(fileName)) { QFile file(fileName); file.open(QIODevice::WriteOnly); file.close(); } if (!fileInfo.isWritable()) LtsWidgets::LtsMessageDialog::showMessage(this, tr("MSDL export file \"%1\" can not be written").arg(fileName)); else { Private::writeMilitaryScenario(miType, fileName.toStdString()); LtsWidgets::LtsMessageDialog::showMessage(this, tr("MSDL export file has successfully been created")); } } catch (const std::exception &e) { // There is so much that could be wrong when importing or exporting MSDL files (missing tags, optional tags, ...) LtsWidgets::LtsMessageDialog::showMessage(this, tr("MSDL export failed!")); ERROR_LOG(mLogger) << "MSDL export failed with an exception, e.what(): " << e.what(); } close(); } }