void interplanetaryDialog::on_buttonBox_accepted() { // Create a new scenario SpaceScenario* scenario = new SpaceScenario(); scenario->setName("This is a demo"); ScenarioSC* sc = new ScenarioSC(); sc->setName("my satellite demo"); sc->ElementIdentifier()->setName("my satellite demo"); // Create the initial position (Keplerian elements) ScenarioKeplerianElementsType* elements = new ScenarioKeplerianElementsType(); elements->setSemiMajorAxis(87000.0); elements->setEccentricity(0.0045); elements->setInclination(27.456); elements->setRAAN(132.34); elements->setArgumentOfPeriapsis(231.34); elements->setTrueAnomaly(45.32); // Create the initial attitude (Euler elements) ScenarioEulerType* initAtt = new ScenarioEulerType(); initAtt->setPhi(0.00000); initAtt->setTheta(0.00000); initAtt->setPsi(0.00000); initAtt->setPhiDot(0.00000); initAtt->setThetaDot(0.00000); initAtt->setPsiDot(0.00000); // Create the trajectory arc ScenarioLoiteringType* loitering = new ScenarioLoiteringType(); loitering->ElementIdentifier()->setName("loitering"); loitering->ElementIdentifier()->setColorName("Yellow"); loitering->Environment()->CentralBody()->setName("Earth"); loitering->InitialPosition()->setCoordinateSystem("INERTIAL J2000"); loitering->PropagationPosition()->setTimeStep(60.0); loitering->PropagationPosition()->setPropagator("TWO BODY"); loitering->PropagationPosition()->setIntegrator("RK4"); loitering->InitialAttitude()->setCoordinateSystem("EULER 123"); loitering->PropagationAttitude()->setIntegrator(""); // Not defined in STA yet loitering->PropagationAttitude()->setTimeStep(60.0); // Time-line QDateTime TheCurrentDateAndTime = QDateTime::currentDateTime(); // Get the current epoch loitering->TimeLine()->setStartTime(TheCurrentDateAndTime); loitering->TimeLine()->setEndTime(TheCurrentDateAndTime.addDays(1)); loitering->TimeLine()->setStepTime(60.0); loitering->InitialPosition()->setAbstract6DOFPosition(QSharedPointer<ScenarioAbstract6DOFPositionType>(elements)); //loitering->InitialAttitude()->setAbstract6DOFAttitude(initAtt); loitering->InitialAttitude()->setAbstract6DOFAttitude(QSharedPointer<ScenarioAbstract6DOFAttitudeType>(initAtt)); // Create the spacecraft sc->SCMission()->TrajectoryPlan()->AbstractTrajectory().append(QSharedPointer<ScenarioAbstractTrajectoryType>(loitering)); // Add it to the scenario scenario->AbstractParticipant().append(QSharedPointer<ScenarioParticipantType>(sc)); mainwindow->setScenario(scenario); return; }
/* This slot is signalled when an inline edit is performed on an item * in the scenario tree. */ void ScenarioTree::editItemInline(QTreeWidgetItem* item, int column) { ScenarioObject* object = objectForItem(item); if (object == NULL) return; // TODO: If we allow more objects to be editing in the scenario // tree view, we need to add an edit method. if (dynamic_cast<ScenarioParticipant*>(object) && column == 1) { // Change the name of a participant ScenarioParticipant* participant = dynamic_cast<ScenarioParticipant*>(object); participant->setName(item->text(1)); } else if (dynamic_cast<SpaceScenario*>(object) && column == 1) { SpaceScenario* scenario = dynamic_cast<SpaceScenario*>(object); scenario->setName(item->text(1)); } }
/** Load an OEM file and convert it to an STA Space Scenario. * * Not all features of the OEM format are supported by the OemImporter * class. An oem file that uses an unsupported feature will fail to load; * details of the problem are available via the errorMessage() method. * * The current implementation has the following limitations: * - TIME_STANDARD must be TDB * - REF_FRAME must be EME2000 or ECLIP2000 * - CENTER_NAME must be an object with an ephemeris * * \return a pointer to a complete space scenario, or NULL if * there was an error loading the scenario. */ SpaceScenario* OemImporter::loadScenario() { readHeader(); SpaceScenario* scenario = new SpaceScenario(); scenario->setName("New scenario"); QSharedPointer<ScenarioSC> sc(new ScenarioSC()); scenario->AbstractParticipant().append(sc); ScenarioExternalType* trajectory; bool skip = false; QString line; QString objectName; StaBody* center = NULL; sta::CoordinateSystemType coordSys = sta::COORDSYS_INVALID; QRegExp whiteSpaceRegExp("\\s+"); // This is the state machine for parsing OEM files. Roughly, the structure // of an OEM file is: // Header // // Metadata // Ephemeris data // Metadata // Ephemeris data // ... // // Where the metadata and ephemeris data blocks alternate; any number // of metadata/ephemeris data pairs may appear in the file. For full // details see Recommended Standard CCSDS 502.0-B-2. while (m_parserState != Oem_End && m_parserState != Oem_Error) { if (skip) { skip = false; } else { line = m_stream->readLine().trimmed(); m_lineNumber++; } if (m_stream->atEnd()) { m_parserState = Oem_End; } else if (line.isEmpty()) { // Nothing to do } else { switch (m_parserState) { case Oem_Begin: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "CCSDS_OEM_VERS") { m_parserState = Oem_AfterVersion; } else { raiseError("Version expected in header"); } } break; case Oem_AfterVersion: if (line.startsWith("COMMENT")) { // Skip and do nothing } else { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "CREATION_DATE") { m_parserState = Oem_AfterCreationDate; } else { raiseError("Creation date expected in header"); } } break; case Oem_AfterCreationDate: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "ORIGINATOR") { m_parserState = Oem_AfterHeader; } else { raiseError("Creation date expected in header"); } } break; case Oem_AfterHeader: if (line.startsWith("COMMENT")) { // Skip and do nothing } else if (line == "META_START") { m_parserState = Oem_MetaStart; } else { raiseError("Metadata block expected"); } break; case Oem_MetaStart: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "OBJECT_NAME") { m_parserState = Oem_AfterObjectName; objectName = kv.value; } else { raiseError("Object name expected"); } } break; case Oem_AfterObjectName: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "OBJECT_ID") { m_parserState = Oem_AfterObjectId; } else { raiseError("Object ID expected"); } } break; case Oem_AfterObjectId: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "CENTER_NAME") { m_parserState = Oem_AfterCenterName; center = STA_SOLAR_SYSTEM->lookup(kv.value); if (!center) { raiseError("Unknown central body " + kv.value); } } else { raiseError("Center name expected"); } } break; case Oem_AfterCenterName: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "REF_FRAME") { m_parserState = Oem_AfterRefFrame; if (kv.value == "EME2000") { coordSys = sta::COORDSYS_EME_J2000; } else if (kv.value == "ECLIP2000") { coordSys = sta::COORDSYS_ECLIPTIC_J2000; } else { raiseError("Unsupported reference frame " + kv.value); } } else { raiseError("Reference frame expected"); } } break; case Oem_AfterRefFrame: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "REF_FRAME_EPOCH") { } else { skip = true; } m_parserState = Oem_AfterRefFrameEpoch; } break; case Oem_AfterRefFrameEpoch: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "TIME_SYSTEM") { m_parserState = Oem_AfterTimeSystem; if (kv.value != "TDB") { raiseError("Unsupported time system " + kv.value); } } else { raiseError("Time system expected"); } } break; case Oem_AfterTimeSystem: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "START_TIME") { m_parserState = Oem_AfterStartTime; } else { raiseError("Start time expected"); } } break; case Oem_AfterStartTime: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "USEABLE_START_TIME") { } else { skip = true; } m_parserState = Oem_AfterUseableStartTime; } break; case Oem_AfterUseableStartTime: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "USEABLE_STOP_TIME") { } else { skip = true; } m_parserState = Oem_AfterUseableStopTime; } break; case Oem_AfterUseableStopTime: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "STOP_TIME") { m_parserState = Oem_AfterStopTime; } else { raiseError("Stop time expected"); } } break; case Oem_AfterStopTime: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "INTERPOLATION") { } else { skip = true; } m_parserState = Oem_AfterInterpolation; } break; case Oem_AfterInterpolation: { OemKeyValue kv = ParseKeyValue(line); if (kv.key == "INTERPOLATION_DEGREE") { } else { skip = true; } m_parserState = Oem_AfterInterpolationDegree; } break; case Oem_AfterInterpolationDegree: if (line == "META_STOP") { m_parserState = Oem_AfterMetaStop; trajectory = new ScenarioExternalType(); int trajectoryIndex = sc->SCMission()->TrajectoryPlan()->AbstractTrajectory().size(); trajectory->CentralBody()->setName(center->name()); trajectory->setCoordinateSystem(sta::CoordinateSystem(coordSys).name()); trajectory->ElementIdentifier()->setName(QString("%1 - %2").arg(objectName).arg(trajectoryIndex + 1)); trajectory->ElementIdentifier()->setColorName("Yellow"); sc->SCMission()->TrajectoryPlan()->AbstractTrajectory().append(QSharedPointer<ScenarioAbstractTrajectoryType>(trajectory)); } else { raiseError("End of metadata (META_STOP) expected"); } break; case Oem_AfterMetaStop: if (line.startsWith("COMMENT")) { // Ignore the comment } else { skip = true; m_parserState = Oem_EphemerisData; } break; case Oem_EphemerisData: if (line == "META_START") { m_parserState = Oem_MetaStart; } else { // Parse the ephemeris line QStringList values = line.split(whiteSpaceRegExp); if (values.size() != 7) { raiseError("Bad or unsupported ephemeris data record"); } else { QDateTime dateTime; int secondsDecimal = values[0].lastIndexOf('.'); if (secondsDecimal > 0) { bool msecOk = false; double sec = values[0].right(values[0].length() - secondsDecimal).toDouble(&msecOk); if (msecOk) { dateTime = QDateTime::fromString(values[0].left(secondsDecimal), Qt::ISODate); dateTime.setTimeSpec(Qt::UTC); int msec = (int) (sec * 1000.0); dateTime = dateTime.addMSecs((int) (sec * 1000.0)); } } else { dateTime = QDateTime::fromString(values[0], Qt::ISODate); } if (!dateTime.isValid()) { raiseError(QString("Bad time value in ephemeris data (%1)").arg(values[0])); } else { bool stateValid = true; double state[6]; for (int i = 0; i < 6; ++i) { bool ok = false; state[i] = values[i + 1].toDouble(&ok); if (!ok) { stateValid = false; } } if (!stateValid) { raiseError("Non-number in ephemeris data"); } else { trajectory->TimeTags().append(dateTime); for (int i = 0; i < 6; ++i) { trajectory->States() << state[i]; } } } } } break; default: m_parserState = Oem_Error; break; } } } // Validate trajectory by making sure that there are no overlapping segments or gaps if (sc) { for (int i = 1; i < sc->SCMission()->TrajectoryPlan()->AbstractTrajectory().size(); ++i) { ScenarioExternalType* prev = dynamic_cast<ScenarioExternalType*>(sc->SCMission()->TrajectoryPlan()->AbstractTrajectory().at(i - 1).data()); ScenarioExternalType* curr = dynamic_cast<ScenarioExternalType*>(sc->SCMission()->TrajectoryPlan()->AbstractTrajectory().at(i).data()); if (prev && curr && !prev->TimeTags().isEmpty() && !curr->TimeTags().isEmpty()) { QDateTime prevEnd = prev->TimeTags().last(); QDateTime currStart = curr->TimeTags().first(); if (currStart < prevEnd) { raiseError(QString("Ephemeris segments %1 and %2 overlap.").arg(i - 1).arg(i)); } else if (currStart > prevEnd) { raiseError(QString("Gap between ephemeris segments %1 and %2.").arg(i - 1).arg(i)); } } } } if (m_parserState == Oem_Error) { qDebug() << "Error while importing OEM file: " << errorMessage(); delete scenario; scenario = NULL; } else { scenario->setName(objectName); sc->setName(objectName); sc->ElementIdentifier()->setName(objectName); } return scenario; }