diff --git a/CMakeLists.txt b/CMakeLists.txt index 85436e1070..8a02ab368c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,7 +92,7 @@ include_directories(${GHOUL_ROOT_DIR}/ext/boost) find_package(SGCT REQUIRED) include_directories(${SGCT_INCLUDE_DIRECTORIES}) set(DEPENDENT_LIBS ${DEPENDENT_LIBS} ${SGCT_LIBRARIES}) -if (UNIX) +if (UNIX AND (NOT APPLE)) set(DEPENDENT_LIBS ${DEPENDENT_LIBS} Xcursor Xinerama) endif () @@ -145,7 +145,11 @@ endif () ######################################################################################### add_subdirectory(src) -add_subdirectory(gui) + +option(BUILD_GUI_APPLICATIONS "Build GUI Applications" OFF) +if (BUILD_GUI_APPLICATIONS) + add_subdirectory(gui) +endif () ######################################################################################### # File Fetch diff --git a/ext/ghoul b/ext/ghoul index 3c444b9a99..a41ea37b6b 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 3c444b9a993846cd1eaac1b8f3c33f3f294eecfb +Subproject commit a41ea37b6bdeda6775e8f95b49134bf8a309569f diff --git a/gui/timelineview/CMakeLists.txt b/gui/timelineview/CMakeLists.txt index 86dd6b9a9c..da453d23bd 100644 --- a/gui/timelineview/CMakeLists.txt +++ b/gui/timelineview/CMakeLists.txt @@ -6,5 +6,5 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) find_package(Qt5Widgets) find_package(Qt5Network) -add_executable(TimelineView main.cpp mainwindow.cpp configurationwidget.cpp informationwidget.cpp timecontrolwidget.cpp timelinewidget.cpp) +add_executable(TimelineView main.cpp mainwindow.cpp configurationwidget.cpp informationwidget.cpp controlwidget.cpp timelinewidget.cpp) target_link_libraries(TimelineView Qt5::Widgets Qt5::Network) \ No newline at end of file diff --git a/gui/timelineview/common.h b/gui/timelineview/common.h new file mode 100644 index 0000000000..ddc0bad206 --- /dev/null +++ b/gui/timelineview/common.h @@ -0,0 +1,37 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2015 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +struct Image { + double beginning; + double ending; + std::string beginningString; + std::string endingString; + std::string target; + std::vector instruments; +}; + +#endif // __COMMON_H__ diff --git a/gui/timelineview/configurationwidget.cpp b/gui/timelineview/configurationwidget.cpp index 900a02d5c1..8f2043fed5 100644 --- a/gui/timelineview/configurationwidget.cpp +++ b/gui/timelineview/configurationwidget.cpp @@ -31,15 +31,11 @@ ConfigurationWidget::ConfigurationWidget(QWidget* parent) , _ipAddress(new QLineEdit("localhost")) , _port(new QLineEdit("20500")) , _connect(new QPushButton("Connect")) - , _playbook(new QLineEdit) - , _load(new QPushButton("Load")) { QGridLayout* layout = new QGridLayout; layout->addWidget(_ipAddress, 0, 0); layout->addWidget(_port, 0, 1); layout->addWidget(_connect, 0, 2); - layout->addWidget(_playbook, 1, 0, 1, 2); - layout->addWidget(_load, 1, 2); setLayout(layout); @@ -50,3 +46,9 @@ ConfigurationWidget::ConfigurationWidget(QWidget* parent) void ConfigurationWidget::onConnectButton() { emit connect(_ipAddress->text(), _port->text()); } + +void ConfigurationWidget::socketConnected() { +} + +void ConfigurationWidget::socketDisconnected() { +} diff --git a/gui/timelineview/configurationwidget.h b/gui/timelineview/configurationwidget.h index dfc305005b..ae6fd8b654 100644 --- a/gui/timelineview/configurationwidget.h +++ b/gui/timelineview/configurationwidget.h @@ -34,6 +34,9 @@ Q_OBJECT public: ConfigurationWidget(QWidget* parent); + void socketConnected(); + void socketDisconnected(); + signals: void connect(QString host, QString port); @@ -44,9 +47,6 @@ private: QLineEdit* _ipAddress; QLineEdit* _port; QPushButton* _connect; - - QLineEdit* _playbook; - QPushButton* _load; }; #endif // __CONFIGURATIONWIDGET_H__ diff --git a/gui/timelineview/timecontrolwidget.cpp b/gui/timelineview/controlwidget.cpp similarity index 55% rename from gui/timelineview/timecontrolwidget.cpp rename to gui/timelineview/controlwidget.cpp index c2693c7aae..ad53a9903e 100644 --- a/gui/timelineview/timecontrolwidget.cpp +++ b/gui/timelineview/controlwidget.cpp @@ -22,7 +22,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include "timecontrolwidget.h" +#include "controlwidget.h" #include #include @@ -31,7 +31,43 @@ #include #include -TimeControlWidget::TimeControlWidget(QWidget* parent) +namespace { + struct ImportantDate { + QString date; + QString focus; + QString coordinateSystem; + }; + + const ImportantDate ImportantDates[] = { + { "2007-02-27T16:40:00.00", "JupiterProjection", "Jupiter" }, + { "2015-07-14T10:10:00.00", "PlutoProjection", "Pluto" }, + { "2015-07-14T10:50:00.00", "PlutoProjection", "Pluto" }, + { "2015-07-14T11:22:00.00", "PlutoProjection", "Pluto" }, + { "2015-07-14T11:36:40.00", "PlutoProjection", "Pluto" }, + { "2015-07-14T11:48:43.00", "PlutoProjection", "Pluto" }, + { "2015-07-14T12:04:35.00", "PlutoProjection", "Pluto" }, + { "2015-07-14T15:02:46.00", "PlutoProjection", "Pluto" } + }; + + struct FocusNode { + QString guiName; + QString name; + QString coordinateSystem; + }; + const FocusNode FocusNodes[] = { + { "Earth", "Earth", "Sun" }, + { "Sun", "Sun", "Sun" }, + { "Pluto", "PlutoProjection", "Pluto" }, + { "Charon", "Charon", "Pluto" }, + { "Jupiter", "JupiterProjection", "Jupiter" }, + { "New Horizons", "NewHorizons", "" }, + { "Nix", "Nix", "Pluto" }, + { "Kerberos", "Kerberos", "Pluto" }, + { "Hydra", "Hydra", "Pluto" }, + }; +} + +ControlWidget::ControlWidget(QWidget* parent) : QWidget(parent) , _currentTime(new QLabel("Current Time")) , _setTime(new QComboBox) @@ -41,7 +77,26 @@ TimeControlWidget::TimeControlWidget(QWidget* parent) , _pause(new QPushButton("||")) , _play(new QPushButton("|>")) , _forward(new QPushButton(">>")) + , _focusNode(new QComboBox) { + for (const ImportantDate& d : ImportantDates) + _setTime->addItem(d.date); + QObject::connect( + _setTime, + SIGNAL(currentIndexChanged(int)), + this, + SLOT(onDateChange()) + ); + + for (const FocusNode& f : FocusNodes) + _focusNode->addItem(f.guiName); + QObject::connect( + _focusNode, + SIGNAL(currentIndexChanged(int)), + this, + SLOT(onFocusChange()) + ); + _setDelta->setMinimum(-100); _setDelta->setMaximum(100); _setDelta->setValue(0); @@ -96,36 +151,89 @@ TimeControlWidget::TimeControlWidget(QWidget* parent) controlContainer->setLayout(controlContainerLayout); layout->addWidget(controlContainer, 3, 0, 1, 2); + layout->addWidget(_focusNode, 4, 0, 1, 2); + setLayout(layout); } -void TimeControlWidget::update(QString currentTime, QString currentDelta) { +void ControlWidget::update(QString currentTime, QString currentDelta) { _currentTime->setText(currentTime); _currentDelta->setText(currentDelta); } -void TimeControlWidget::onValueChange() { - QString script = "openspace.time.setDeltaTime(" + QString::number(_setDelta->value()) + ");"; +void ControlWidget::onValueChange() { + float value = static_cast(_setDelta->value()); + + int delta; + if (value < 0.f) { + value = -value; + float d = std::pow(2, value / 10); + delta = static_cast(-d); + } + else { + float d = std::pow(2, value / 10); + delta = static_cast(d); + } + + QString script = "openspace.time.setDeltaTime(" + QString::number(delta) + ");"; emit scriptActivity(script); } -void TimeControlWidget::onRewindButton() { +void ControlWidget::onRewindButton() { QString script = "openspace.time.setDeltaTime(-openspace.time.deltaTime());"; emit scriptActivity(script); } -void TimeControlWidget::onPauseButton() { +void ControlWidget::onPauseButton() { QString script = "openspace.time.setPause(true);"; emit scriptActivity(script); } -void TimeControlWidget::onPlayButton() { +void ControlWidget::onPlayButton() { QString script = "openspace.time.setPause(false);"; emit scriptActivity(script); } -void TimeControlWidget::onForwardButton() { +void ControlWidget::onForwardButton() { QString script = "openspace.time.setDeltaTime(-openspace.time.deltaTime());"; emit scriptActivity(script); } + +void ControlWidget::onDateChange() { + int index = _setTime->currentIndex(); + QString date = ImportantDates[index].date; + QString focus = ImportantDates[index].focus; + QString coordinateSystem = ImportantDates[index].coordinateSystem; + QString script = + "openspace.time.setTime('" + date + "');\ + openspace.setOrigin('" + focus + "');\ + openspace.changeCoordinateSystem('" + coordinateSystem + "');"; + emit scriptActivity(script); +} + +void ControlWidget::onFocusChange() { + int index = _focusNode->currentIndex(); + QString name = FocusNodes[index].name; + QString coordinateSystem = FocusNodes[index].coordinateSystem; + if (coordinateSystem.isEmpty()) { + int date = _currentTime->text().left(4).toInt(); + if (date < 2008) + coordinateSystem = "Jupiter"; + else if (date < 2014) + coordinateSystem = "Sun"; + else + coordinateSystem = "Pluto"; + + } + QString script = "openspace.setOrigin('" + name + "');openspace.changeCoordinateSystem('" + coordinateSystem + "');"; + emit scriptActivity(script); +} + +void ControlWidget::socketConnected() { + setDisabled(false); +} + +void ControlWidget::socketDisconnected() { + setDisabled(true); +} diff --git a/gui/timelineview/timecontrolwidget.h b/gui/timelineview/controlwidget.h similarity index 90% rename from gui/timelineview/timecontrolwidget.h rename to gui/timelineview/controlwidget.h index 8265184cf3..970040cfb7 100644 --- a/gui/timelineview/timecontrolwidget.h +++ b/gui/timelineview/controlwidget.h @@ -22,8 +22,8 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __TIMECONTROLWIDGET_H__ -#define __TIMECONTROLWIDGET_H__ +#ifndef __CONTROLWIDGET_H__ +#define __CONTROLWIDGET_H__ #include @@ -32,18 +32,23 @@ class QLabel; class QPushButton; class QSlider; -class TimeControlWidget : public QWidget { +class ControlWidget : public QWidget { Q_OBJECT public: - TimeControlWidget(QWidget* parent); + ControlWidget(QWidget* parent); void update(QString currentTime, QString currentDelta); + void socketConnected(); + void socketDisconnected(); + signals: void scriptActivity(QString script); private slots: void onValueChange(); + void onDateChange(); + void onFocusChange(); void onRewindButton(); void onPauseButton(); void onPlayButton(); @@ -58,8 +63,7 @@ private: QPushButton* _pause; QPushButton* _play; QPushButton* _forward; - - bool _stateNoNotification = false; + QComboBox* _focusNode; }; -#endif // __TIMECONTROLWIDGET_H__ +#endif // __CONTROLWIDGET_H__ diff --git a/gui/timelineview/informationwidget.cpp b/gui/timelineview/informationwidget.cpp index f53147b510..0647f9fb32 100644 --- a/gui/timelineview/informationwidget.cpp +++ b/gui/timelineview/informationwidget.cpp @@ -31,3 +31,11 @@ InformationWidget::InformationWidget(QWidget* parent) : QTextEdit(parent) { } + +void InformationWidget::socketConnected() { + setDisabled(false); +} + +void InformationWidget::socketDisconnected() { + setDisabled(true); +} diff --git a/gui/timelineview/informationwidget.h b/gui/timelineview/informationwidget.h index b0f4df3aed..abf56897a9 100644 --- a/gui/timelineview/informationwidget.h +++ b/gui/timelineview/informationwidget.h @@ -31,6 +31,8 @@ class InformationWidget : public QTextEdit { Q_OBJECT public: InformationWidget(QWidget* parent); + void socketConnected(); + void socketDisconnected(); }; #endif // __INFORMATIONWIDGET_H__ diff --git a/gui/timelineview/mainwindow.cpp b/gui/timelineview/mainwindow.cpp index a6b2bb9b24..3574f4dbfe 100644 --- a/gui/timelineview/mainwindow.cpp +++ b/gui/timelineview/mainwindow.cpp @@ -25,7 +25,7 @@ #include "mainwindow.h" #include "configurationwidget.h" -#include "timecontrolwidget.h" +#include "controlwidget.h" #include "informationwidget.h" #include "timelinewidget.h" @@ -36,6 +36,28 @@ #include #include +template +T readFromBuffer(char* buffer, size_t& currentReadLocation) { + union { + T value; + std::array data; + } b; + std::memmove(b.data.data(), buffer + currentReadLocation, sizeof(T)); + currentReadLocation += sizeof(T); + return b.value; +} + +template <> +std::string readFromBuffer(char* buffer, size_t& currentReadLocation) { + uint8_t size = readFromBuffer(buffer, currentReadLocation); + + std::string result(buffer + currentReadLocation, buffer + currentReadLocation + size); + currentReadLocation += size; + return result; +} + + + MainWindow::MainWindow() : QWidget(nullptr) , _configurationWidget(nullptr) @@ -47,7 +69,7 @@ MainWindow::MainWindow() setWindowTitle("OpenSpace Timeline"); _configurationWidget = new ConfigurationWidget(this); - _timeControlWidget = new TimeControlWidget(this); + _timeControlWidget = new ControlWidget(this); _informationWidget = new InformationWidget(this); _timelineWidget = new TimelineWidget(this); @@ -68,8 +90,12 @@ MainWindow::MainWindow() this, SLOT(sendScript(QString)) ); - setLayout(layout); + + _configurationWidget->socketDisconnected(); + _timeControlWidget->socketDisconnected(); + _informationWidget->socketDisconnected(); + _timelineWidget->socketDisconnected(); } MainWindow::~MainWindow() { @@ -80,26 +106,56 @@ void MainWindow::onConnect(QString host, QString port) { delete _socket; _socket = new QTcpSocket(this); - connect(_socket, SIGNAL(readyRead()), SLOT(readTcpData())); + QObject::connect(_socket, SIGNAL(readyRead()), SLOT(readTcpData())); + QObject::connect(_socket, SIGNAL(connected()), SLOT(onSocketConnected())); + QObject::connect(_socket, SIGNAL(disconnected()), SLOT(onSocketDisconnected())); + _socket->connectToHost(host, port.toUInt()); } void MainWindow::readTcpData() { - static const uint8_t MessageTypeStatus = 0; + static const uint16_t MessageTypeStatus = 0; + static const uint16_t MessageTypePlayBook = 2; QByteArray data = _socket->readAll(); + //QString debug(data); + //qDebug() << debug; + if (QString(data) == "Connected to SGCT!\r\n") return; if (QString(data) == "OK\r\n") return; - uint8_t messageType = data[0]; + QByteArray messageTypeData = data.left(2); + union { + uint16_t value; + std::array data; + } messageType; + std::memcpy(messageType.data.data(), messageTypeData.data(), sizeof(uint16_t)); - if (messageType == MessageTypeStatus) - handleStatusMessage(data.mid(1)); - handleStatusMessage(data.right(data.length() - 1)); + switch (messageType.value) { + case MessageTypeStatus: + handleStatusMessage(data.mid(2)); + break; + case MessageTypePlayBook: + { + const char* payloadDebug = data.mid(2).data(); + + size_t beginning = 0; + uint32_t size = readFromBuffer(data.mid(2).data(), beginning); + + while (_socket->waitForReadyRead() && data.size() < size) { + //while (data.size() < size) { + data = data.append(_socket->readAll()); + } + handlePlaybook(data.mid(2)); + break; + } + default: + qDebug() << "Unknown message of type '" << messageType.value << "'"; + } } void MainWindow::handleStatusMessage(QByteArray data) { @@ -124,8 +180,89 @@ void MainWindow::handleStatusMessage(QByteArray data) { QString::fromStdString(std::string(timeString.begin(), timeString.end())), QString::number(delta.value) ); + _timelineWidget->setCurrentTime(std::string(timeString.begin(), timeString.end()), et.value); +} + +std::vector instrumentsFromId(uint16_t instrumentId, std::map instrumentMap) { + std::vector results; + for (int i = 0; i < 16; ++i) { + uint16_t testValue = 1 << i; + if ((testValue & instrumentId) != 0) { + std::string t = instrumentMap.at(testValue); + if (t.empty()) + qDebug() << "Empty instrument"; + results.push_back(t); + } + } + return results; +} + +void MainWindow::handlePlaybook(QByteArray data) { + char* buffer = data.data(); + size_t currentReadLocation = 0; + + uint32_t totalData = readFromBuffer(buffer, currentReadLocation); + + uint8_t nTargets = readFromBuffer(buffer, currentReadLocation); + qDebug() << "Targets: " << nTargets; + std::map targetMap; + for (uint8_t i = 0; i < nTargets; ++i) { + uint8_t id = readFromBuffer(buffer, currentReadLocation); + std::string value = readFromBuffer(buffer, currentReadLocation); + qDebug() << QString::fromStdString(value); + targetMap[id] = value; + } + + uint8_t nInstruments = readFromBuffer(buffer, currentReadLocation); + qDebug() << "Instruments: " << nInstruments; + std::map instrumentMap; + for (uint8_t i = 0; i < nInstruments; ++i) { + uint16_t id = readFromBuffer(buffer, currentReadLocation); + std::string value = readFromBuffer(buffer, currentReadLocation); + qDebug() << QString::fromStdString(value); + instrumentMap[id] = value; + } + + uint32_t nImages = readFromBuffer(buffer, currentReadLocation); + std::vector images; + for (uint32_t i = 0; i < nImages; ++i) { + Image image; + image.beginning = readFromBuffer(buffer, currentReadLocation); + image.ending = readFromBuffer(buffer, currentReadLocation); + + image.beginningString = readFromBuffer(buffer, currentReadLocation); + image.endingString = readFromBuffer(buffer, currentReadLocation); + + uint8_t targetId = readFromBuffer(buffer, currentReadLocation); + uint16_t instrumentId = readFromBuffer(buffer, currentReadLocation); + image.target = targetMap[targetId]; + image.instruments = instrumentsFromId(instrumentId, instrumentMap); + if (image.instruments.empty()) + qDebug() << "Instruments were empty"; + images.push_back(image); + } + + _timelineWidget->setData(std::move(images), std::move(targetMap), std::move(instrumentMap)); + + _configurationWidget->socketConnected(); + _timeControlWidget->socketConnected(); + _informationWidget->socketConnected(); + _timelineWidget->socketConnected(); } void MainWindow::sendScript(QString script) { - _socket->write(("0" + script + "\r\n").toLatin1()); + if (_socket) + _socket->write(("0" + script + "\r\n").toLatin1()); } + +void MainWindow::onSocketConnected() { + _socket->write(QString("1\r\n").toLatin1()); +} + +void MainWindow::onSocketDisconnected() { + _configurationWidget->socketDisconnected(); + _timeControlWidget->socketDisconnected(); + _informationWidget->socketDisconnected(); + _timelineWidget->socketDisconnected(); +} + diff --git a/gui/timelineview/mainwindow.h b/gui/timelineview/mainwindow.h index 9fdd10b1d3..594e400583 100644 --- a/gui/timelineview/mainwindow.h +++ b/gui/timelineview/mainwindow.h @@ -28,8 +28,10 @@ #include #include +#include "common.h" + class ConfigurationWidget; -class TimeControlWidget; +class ControlWidget; class InformationWidget; class TimelineWidget; @@ -45,14 +47,18 @@ public slots: private slots: void onConnect(QString host, QString port); + void onSocketConnected(); + void onSocketDisconnected(); + //void onConnectButton(); //void sendCommandButton(); void readTcpData(); void handleStatusMessage(QByteArray data); + void handlePlaybook(QByteArray data); private: ConfigurationWidget* _configurationWidget; - TimeControlWidget* _timeControlWidget; + ControlWidget* _timeControlWidget; InformationWidget* _informationWidget; TimelineWidget* _timelineWidget; diff --git a/gui/timelineview/timelinewidget.cpp b/gui/timelineview/timelinewidget.cpp index 7028482f30..d8f2b0c3e6 100644 --- a/gui/timelineview/timelinewidget.cpp +++ b/gui/timelineview/timelinewidget.cpp @@ -24,19 +24,237 @@ #include "timelinewidget.h" +#include #include #include +#include +#include + +namespace { + static const int LegendHeight = 105; + static const int TimeWidth = 200; + + static const int TextOffset = 5; + + //const QColor targetColors[] = { + // QColor(251, 180, 174), + // QColor(179, 205, 227), + // QColor(204, 235, 197), + // QColor(222, 203, 228), + // QColor(254, 217, 166), + // QColor(255, 255, 204) + //}; + + const QColor instrumentColors[] = { + QColor(228, 26, 28), + QColor(55, 126, 184), + QColor(77, 175, 74), + QColor(152, 78, 163), + QColor(255, 127, 0), + QColor(255, 255, 51), + QColor(166, 86, 40), + QColor(247, 129, 191), + QColor(153, 153, 153), + }; + + const double etSpread = 100.0; +} + TimelineWidget::TimelineWidget(QWidget* parent) : QWidget(parent) { - setMinimumWidth(300); - setMinimumHeight(500); + setMinimumWidth(600); + setMinimumHeight(600); } void TimelineWidget::paintEvent(QPaintEvent* event) { QPainter painter(this); - painter.setBrush(QBrush(Qt::white)); - painter.drawRect(contentsRect()); + QRectF fullRect = contentsRect(); + QRectF contentRect(0, 0, fullRect.width() - 1, fullRect.height() - LegendHeight); + QRectF legendRect(0, fullRect.bottom() - LegendHeight, fullRect.right(), fullRect.bottom()); + + painter.save(); + drawContent(painter, contentRect); + painter.restore(); + + painter.save(); + painter.translate(0, fullRect.height() - LegendHeight); + drawLegend(painter, QRectF(legendRect)); + painter.restore(); +} + +void TimelineWidget::setData(std::vector images, std::map targetMap, std::map instrumentMap) { + _images = std::move(images); + + std::sort(_images.begin(), _images.end(), [](const Image& a, const Image& b) { return a.beginning < b.beginning; }); + + _targetMap = std::move(targetMap); + _instrumentMap = std::move(instrumentMap); + + _instruments.clear(); + std::set instruments; + for (auto p : _instrumentMap) + instruments.insert(p.second); + std::copy(instruments.begin(), instruments.end(), std::back_inserter(_instruments)); + + _targets.clear(); + std::set targets; + for (auto p : _targetMap) + targets.insert(p.second); + std::copy(targets.begin(), targets.end(), std::back_inserter(_targets)); + + repaint(); +} + +void TimelineWidget::drawContent(QPainter& painter, QRectF rect) { + QRectF timelineRect(0, 0, rect.width() - TimeWidth, rect.height()); + QRectF dateRect(rect.width() - TimeWidth, 0, TimeWidth, rect.height()); + + // Draw background + painter.setBrush(QBrush(Qt::white)); painter.drawRect(timelineRect); + painter.setBrush(QBrush(Qt::gray)); painter.drawRect(dateRect); + + const double lowerTime = _currentTime.et - etSpread; + const double upperTime = _currentTime.et + etSpread; + + std::vector images; + for (Image& i : _images) { + if (i.beginning <= upperTime && i.ending >= lowerTime) + images.push_back(&i); + } + + + //std::vector::const_iterator lower = std::lower_bound(_images.begin(), _images.end(), lowerTime, [](const Image& i, double time) { return i.beginning < time; }); + //std::vector::const_iterator upper = std::lower_bound(_images.begin(), _images.end(), upperTime, [](const Image& i, double time) { return i.ending < time; }); + //if (lower != _images.end() && upper != _images.end()) + // drawImages(painter, timelineRect, std::vector(lower, upper), lowerTime, upperTime); + + drawImages(painter, timelineRect, images, lowerTime, upperTime); + + + // Draw current time + painter.setBrush(QBrush(Qt::black)); + painter.setPen(QPen(Qt::black)); + painter.drawLine(QPointF(0, timelineRect.height() / 2), QPointF(timelineRect.width(), timelineRect.height() / 2)); + painter.drawText(timelineRect.width(), timelineRect.height() / 2 + TextOffset, QString::fromStdString(_currentTime.time)); +} + +void TimelineWidget::drawLegend(QPainter& painter, QRectF rect) { + static const int HalfHeight = LegendHeight / 2; + static const int Padding = 5; + static const int BoxSize = 20; + + // Draw Targets + int currentHorizontalPosition = Padding; + int currentVerticalPosition = Padding; + //for (int i = 0; i < _targets.size(); ++i) { + + // const std::string& target = _targets[i]; + // + // painter.setBrush(QBrush(targetColors[i])); + // painter.drawRect(currentHorizontalPosition, currentVerticalPosition, BoxSize, BoxSize); + // currentHorizontalPosition += BoxSize + Padding; + + // painter.drawText(currentHorizontalPosition, currentVerticalPosition + BoxSize / 2 + TextOffset, QString::fromStdString(target)); + // int textWidth = painter.boundingRect(QRect(), QString::fromStdString(target)).width(); + // currentHorizontalPosition += std::max(textWidth, 25) + Padding; + //} + + // Draw Instruments + currentHorizontalPosition = Padding; + currentVerticalPosition = Padding + BoxSize + Padding; + for (int i = 0; i < _instruments.size(); ++i) { + if (i == _instruments.size() / 3 || i == _instruments.size() * 2 / 3) { + currentVerticalPosition += BoxSize + Padding; + currentHorizontalPosition = Padding; + } + + const std::string& instrument = _instruments[i]; + + //painter.setBrush(QBrush(instrumentColors[i])); + painter.setBrush(QBrush(instrumentColors[i])); + painter.setPen(QPen(instrumentColors[i])); + painter.drawRect(currentHorizontalPosition, currentVerticalPosition, BoxSize, BoxSize); + currentHorizontalPosition += BoxSize + Padding; + + painter.setPen(QPen(Qt::black)); + painter.drawText(currentHorizontalPosition, currentVerticalPosition + BoxSize / 2 + TextOffset, QString::fromStdString(instrument)); + int textWidth = painter.boundingRect(QRect(), QString::fromStdString(instrument)).width(); + currentHorizontalPosition += std::max(textWidth, 25) + Padding; + } +} + +void TimelineWidget::setCurrentTime(std::string currentTime, double et) { + _currentTime.time = std::move(currentTime); + _currentTime.et = std::move(et); + repaint(); + +} + +void TimelineWidget::drawImages( + QPainter& painter, + QRectF timelineRect, + std::vector images, + double minimumTime, double maximumTime) +{ + int width = timelineRect.width(); + + int nInstruments = 0; + std::set instrumentSet; + for (Image* i : images) { + for (std::string instrument : i->instruments) + instrumentSet.insert(instrument); + } + std::map instruments; + for (std::set::const_iterator it = instrumentSet.begin(); it != instrumentSet.end(); ++it) + instruments[*it] = std::distance(instrumentSet.begin(), it); + + for (Image* i : images) { + double tBeg = (i->beginning - minimumTime) / (maximumTime - minimumTime); + tBeg = std::max(tBeg, 0.0); + double tEnd = (i->ending - minimumTime) / (maximumTime - minimumTime); + tEnd = std::min(tEnd, 1.0); + + int loc = timelineRect.top() + timelineRect.height() * tBeg; + int height = (timelineRect.top() + timelineRect.height() * tEnd) - loc; + height = std::max(height, 5); + + std::string target = i->target; + auto it = std::find(_targets.begin(), _targets.end(), target); + int iTarget = std::distance(_targets.begin(), it); + + //std::vector colors; + for (std::string instrument : i->instruments) { + auto it = std::find(_instruments.begin(), _instruments.end(), instrument); + if (it == _instruments.end()) + qDebug() << "Instrument not found"; + int i = std::distance(_instruments.begin(), it); + + painter.setBrush(QBrush(instrumentColors[i])); + + double width = timelineRect.width() / instruments.size(); + double pos = instruments[instrument] * width; + + painter.drawRect(pos, loc, width, height); + } + + painter.setBrush(QBrush(Qt::black)); + painter.setPen(QPen(Qt::black)); + QString line = QString::fromStdString(i->beginningString) + QString(" (") + QString::fromStdString(i->target) + QString(")"); + + painter.drawText(timelineRect.width(), loc + height / 2 + TextOffset, line); + } +} + +void TimelineWidget::socketConnected() { + setDisabled(false); +} + +void TimelineWidget::socketDisconnected() { + setDisabled(true); + _images.clear(); + _instruments.clear(); + _targets.clear(); } diff --git a/gui/timelineview/timelinewidget.h b/gui/timelineview/timelinewidget.h index def40ffe6c..86ec18779d 100644 --- a/gui/timelineview/timelinewidget.h +++ b/gui/timelineview/timelinewidget.h @@ -27,6 +27,12 @@ #include +#include "common.h" + +#include +#include +#include + class QPaintEvent; class TimelineWidget : public QWidget { @@ -34,9 +40,29 @@ Q_OBJECT public: TimelineWidget(QWidget* parent); + void setData(std::vector images, std::map targetMap, std::map instrumentMap); + void setCurrentTime(std::string currentTime, double et); + void socketConnected(); + void socketDisconnected(); + protected: void paintEvent(QPaintEvent* event); + void drawContent(QPainter& painter, QRectF rect); + void drawLegend(QPainter& painter, QRectF rect); + void drawImages(QPainter& painter, QRectF timelineRect, std::vector images, double minimumTime, double maximumTime); +private: + std::vector _images; + std::map _targetMap; + std::map _instrumentMap; + + std::vector _targets; + std::vector _instruments; + + struct { + std::string time; + double et; + } _currentTime; }; #endif // __TIMELINEWIDGET_H__ diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 2beeafa486..155a9f9e33 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -69,6 +69,7 @@ public: interaction::InteractionHandler* interactionHandler(); RenderEngine* renderEngine(); scripting::ScriptEngine* scriptEngine(); + NetworkEngine* networkEngine(); LuaConsole* console(); gui::GUI* gui(); diff --git a/include/openspace/network/networkengine.h b/include/openspace/network/networkengine.h index 1d0c03481a..90558f9717 100644 --- a/include/openspace/network/networkengine.h +++ b/include/openspace/network/networkengine.h @@ -25,17 +25,50 @@ #ifndef __NETWORKENGINE_H__ #define __NETWORKENGINE_H__ +#include +#include #include +#include namespace openspace { class NetworkEngine { public: - NetworkEngine() = default; + typedef uint16_t MessageIdentifier; + NetworkEngine(); + + // Receiving messages bool handleMessage(const std::string& message); - void sendStatusMessage(); + // Sending messages + void publishStatusMessage(); + void publishIdentifierMappingMessage(); + void publishMessage(MessageIdentifier identifier, std::vector message); + void sendMessages(); + + // Initial Connection Messages + void setInitialConnectionMessage(MessageIdentifier identifier, std::vector message); + void sendInitialInformation(); + + // Background + MessageIdentifier identifier(std::string name); +private: + std::map _identifiers; + MessageIdentifier _lastAssignedIdentifier; + + struct Message { + MessageIdentifier identifer; + std::vector body; + }; + std::vector _messagesToSend; + + std::vector _initialConnectionMessages; + + + + MessageIdentifier _statusMessageIdentifier; + MessageIdentifier _identifierMappingIdentifier; }; } // namespace openspace diff --git a/include/openspace/util/hongkangparser.h b/include/openspace/util/hongkangparser.h index f6e08c6160..e29f2e4c4a 100644 --- a/include/openspace/util/hongkangparser.h +++ b/include/openspace/util/hongkangparser.h @@ -25,7 +25,7 @@ #ifndef __HONGKANGPARSER_H__ #define __HONGKANGPARSER_H__ -#include +#include #include #include @@ -65,6 +65,7 @@ namespace openspace { std::string spacecraft, std::vector payload, std::vector potentialTargets); + void sendPlaybookInformation(); std::string _defaultCaptureImage; double _metRef = 299180517; diff --git a/include/openspace/util/imagesequencer2.h b/include/openspace/util/imagesequencer2.h index f78674b9c1..184d121139 100644 --- a/include/openspace/util/imagesequencer2.h +++ b/include/openspace/util/imagesequencer2.h @@ -122,11 +122,11 @@ public: * makes the request. If an instance is not registered in the class then the singleton * returns false and no projections will occur. */ - bool ImageSequencer2::getImagePaths(std::vector& captures, + bool getImagePaths(std::vector& captures, std::string projectee, std::string instrumentID); - bool ImageSequencer2::getImagePaths(std::vector& captures, + bool getImagePaths(std::vector& captures, std::string projectee); /* diff --git a/include/openspace/util/labelparser.h b/include/openspace/util/labelparser.h index cea2dce8aa..bfdf65ca7d 100644 --- a/include/openspace/util/labelparser.h +++ b/include/openspace/util/labelparser.h @@ -22,10 +22,9 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ - #ifndef __LABELPARSER_H__ #define __LABELPARSER_H__ -#include +#include #include #include diff --git a/include/openspace/version.h b/include/openspace/version.h index 7f05ca7d21..f238d92af9 100644 --- a/include/openspace/version.h +++ b/include/openspace/version.h @@ -23,6 +23,6 @@ ****************************************************************************************/ #define OPENSPACE_VERSION_MAJOR 0 -#define OPENSPACE_VERSION_MINOR 0 -#define OPENSPACE_VERSION_REVISION 3 -#define OPENSPACE_VERSION_STRING "prerelease-3" +#define OPENSPACE_VERSION_MINOR 1 +#define OPENSPACE_VERSION_REVISION 0 +#define OPENSPACE_VERSION_STRING "prerelease-4" diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 70eb1ad926..0566c9761f 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -701,7 +701,8 @@ void OpenSpaceEngine::encode() { _syncBuffer->write(); } - _networkEngine->sendStatusMessage(); + _networkEngine->publishStatusMessage(); + _networkEngine->sendMessages(); } void OpenSpaceEngine::decode() { @@ -731,4 +732,8 @@ void OpenSpaceEngine::disableBarrier() { sgct::SGCTWindow::setBarrier(false); } +NetworkEngine* OpenSpaceEngine::networkEngine() { + return _networkEngine; +} + } // namespace openspace diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index 9ac16253d6..6017ebb36e 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -556,7 +556,12 @@ void InteractionHandler::setFocusNode(SceneGraphNode* node) { glm::vec3 cameraView = glm::normalize(_camera->viewDirection()); //set new focus position _camera->setFocusPosition(node->worldPosition()); - if (viewDir != cameraView) { + float dot = glm::dot(viewDir, cameraView); + + //static const float Epsilon = 0.001f; + if (dot < 1.f && dot > -1.f) { + //if (glm::length(viewDir - cameraView) < 0.001) { + //if (viewDir != cameraView) { glm::vec3 rotAxis = glm::normalize(glm::cross(viewDir, cameraView)); float angle = glm::angle(viewDir, cameraView); glm::quat q = glm::angleAxis(angle, rotAxis); diff --git a/src/main.cpp b/src/main.cpp index 86a3dfdf2a..d7a851db0f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,7 +79,6 @@ int main(int argc, char** argv) { sgct::MessageHandler::instance()->setLogToCallback(true); sgct::MessageHandler::instance()->setLogCallback(mainLogCallback); - LDEBUG("Creating SGCT Engine"); _sgctEngine = new sgct::Engine(newArgc, newArgv); diff --git a/src/network/networkengine.cpp b/src/network/networkengine.cpp index 1b0c0a2599..c89ce924b3 100644 --- a/src/network/networkengine.cpp +++ b/src/network/networkengine.cpp @@ -27,27 +27,49 @@ #include #include +#include + #include "sgct.h" namespace { const std::string _loggerCat = "NetworkEngine"; - const uint8_t MessageTypeStatus = 0; + const std::string StatusMessageIdentifierName = "StatusMessage"; + const std::string MappingIdentifierIdentifierName = "IdentifierMapping"; + + const char MessageTypeLuaScript = '0'; + const char MessageTypeExternalControlConnected = '1'; } namespace openspace { +NetworkEngine::NetworkEngine() + : _lastAssignedIdentifier(-1) // -1 is okay as we assign one identifier in this ctor +{ + static_assert( + sizeof(MessageIdentifier) == 2, + "MessageIdentifier has to be 2 bytes or dependent applications will break" + ); + _statusMessageIdentifier = identifier(StatusMessageIdentifierName); + _identifierMappingIdentifier = identifier(MappingIdentifierIdentifierName); +} + bool NetworkEngine::handleMessage(const std::string& message) { // The first byte determines the type of message const char type = message[0]; switch (type) { - case '0': // LuaScript + case MessageTypeLuaScript: // LuaScript { std::string script = message.substr(1); //LINFO("Received Lua Script: '" << script << "'"); OsEng.scriptEngine()->queueScript(script); return true; } + case MessageTypeExternalControlConnected: + { + sendInitialInformation(); + return true; + } default: LERROR("Unknown type '" << type << "'"); return false; @@ -55,15 +77,14 @@ bool NetworkEngine::handleMessage(const std::string& message) { } -void NetworkEngine::sendStatusMessage() { +void NetworkEngine::publishStatusMessage() { if (!sgct::Engine::instance()->isExternalControlConnected()) return; - // Protocols: - // 1 byte: type of message + // Protocol: // 8 bytes: time as a ET double // 24 bytes: time as a UTC string // 8 bytes: delta time as double - // Total: 41 + // Total: 40 uint16_t messageSize = 0; @@ -71,27 +92,108 @@ void NetworkEngine::sendStatusMessage() { std::string timeString = Time::ref().currentTimeUTC(); double delta = Time::ref().deltaTime(); - messageSize += sizeof(uint8_t); messageSize += sizeof(time); messageSize += timeString.length(); messageSize += sizeof(delta); - //LINFO(delta); - - ghoul_assert(messageSize == 41, "Message size is not correct"); + ghoul_assert(messageSize == 40, "Message size is not correct"); unsigned int currentLocation = 0; std::vector buffer(messageSize); - std::memcpy(buffer.data(), &MessageTypeStatus, sizeof(MessageTypeStatus)); - currentLocation += sizeof(MessageTypeStatus); std::memmove(buffer.data() + currentLocation, &time, sizeof(time)); currentLocation += sizeof(time); std::memmove(buffer.data() + currentLocation, timeString.c_str(), timeString.length()); currentLocation += timeString.length(); std::memmove(buffer.data() + currentLocation, &delta, sizeof(delta)); - sgct::Engine::instance()->sendMessageToExternalControl(buffer.data(), messageSize); + publishMessage(_statusMessageIdentifier, std::move(buffer)); +} + +void NetworkEngine::publishIdentifierMappingMessage() { + size_t bufferSize = 0; + for (const std::pair& i : _identifiers) { + bufferSize += sizeof(MessageIdentifier); + bufferSize += i.second.size() + 1; // +1 for \0 terminating character + } + + std::vector buffer(bufferSize); + size_t currentWritingPosition = 0; + for (const std::pair& i : _identifiers) { + std::memcpy(buffer.data() + currentWritingPosition, &(i.first), sizeof(MessageIdentifier)); + currentWritingPosition += sizeof(MessageIdentifier); + std::memcpy(buffer.data() + currentWritingPosition, i.second.data(), i.second.size()); + currentWritingPosition += i.second.size(); + buffer[currentWritingPosition] = '\0'; + currentWritingPosition += 1; + } + + publishMessage(_identifierMappingIdentifier, std::move(buffer)); +} + + +NetworkEngine::MessageIdentifier NetworkEngine::identifier(std::string name) { +#ifdef DEBUG + // Check if name has been assigned already + for (const std::pair& p : _identifiers) { + if (p.second == name) { + LERROR("Name '" << name << "' for identifier has been registered before"); + return -1; + } + } +#endif + _lastAssignedIdentifier++; + + MessageIdentifier result = _lastAssignedIdentifier; + + _identifiers[result] = std::move(name); + return result; +} + +void NetworkEngine::publishMessage(MessageIdentifier identifier, std::vector message) { + _messagesToSend.push_back({ std::move(identifier), std::move(message) }); +} + +void NetworkEngine::sendMessages() { + if (!sgct::Engine::instance()->isExternalControlConnected()) + return; + + for (Message& m : _messagesToSend) { + // Protocol: + // 2 bytes: type of message as uint16_t + // Rest of payload depending on the message type + + union { + MessageIdentifier value; + std::array data; + } identifier; + identifier.value = m.identifer; + + // Prepending the message identifier to the front + m.body.insert(m.body.begin(), identifier.data.begin(), identifier.data.end()); + sgct::Engine::instance()->sendMessageToExternalControl(m.body.data(), m.body.size()); + } + + _messagesToSend.clear(); +} + +void NetworkEngine::sendInitialInformation() { + for (const Message& m : _initialConnectionMessages) { + union { + MessageIdentifier value; + std::array data; + } identifier; + identifier.value = m.identifer; + + std::vector payload = m.body; + payload.insert(payload.begin(), identifier.data.begin(), identifier.data.end()); + sgct::Engine::instance()->sendMessageToExternalControl(payload.data(), payload.size()); + } +} + +void NetworkEngine::setInitialConnectionMessage(MessageIdentifier identifier, std::vector message) { + // Add check if a MessageIdentifier already exists ---abock + _initialConnectionMessages.push_back({std::move(identifier), std::move(message)}); } } // namespace openspace diff --git a/src/rendering/model/modelgeometry.cpp b/src/rendering/model/modelgeometry.cpp index a1e955988c..6905b0c9f1 100644 --- a/src/rendering/model/modelgeometry.cpp +++ b/src/rendering/model/modelgeometry.cpp @@ -206,6 +206,11 @@ bool ModelGeometry::loadCachedFile(const std::string& filename) { fileStream.read(reinterpret_cast(&vSize), sizeof(int64_t)); fileStream.read(reinterpret_cast(&iSize), sizeof(int64_t)); + if (vSize == 0 || iSize == 0) { + LERROR("Error opening file '" << filename << "' for loading cache file"); + return false; + } + _vertices.resize(vSize); _indices.resize(iSize); diff --git a/src/rendering/renderablefieldlines.cpp b/src/rendering/renderablefieldlines.cpp index 24b6d465eb..4baa19bacb 100644 --- a/src/rendering/renderablefieldlines.cpp +++ b/src/rendering/renderablefieldlines.cpp @@ -306,7 +306,7 @@ void RenderableFieldlines::update(const UpdateData&) { void RenderableFieldlines::loadSeedPoints() { _seedPoints.clear(); - switch (_seedPointSource) { + switch (_seedPointSource.value()) { case SeedPointSourceFile: loadSeedPointsFromFile(); break; diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index ba54649773..f57d13486f 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -190,7 +190,7 @@ namespace openspace { double t = luaL_checknumber(L, -1); - OsEng.renderEngine()->startFading(1, t); + OsEng.renderEngine()->startFading(1, static_cast(t)); return 0; } /** @@ -205,7 +205,7 @@ namespace openspace { double t = luaL_checknumber(L, -1); - OsEng.renderEngine()->startFading(-1, t); + OsEng.renderEngine()->startFading(-1, static_cast(t)); return 0; } @@ -494,8 +494,9 @@ namespace openspace { } #if 1 -#define PrintText(i, format, ...) Freetype::print(font, 10.f, static_cast(startY - font_size_mono * i * 2), format, __VA_ARGS__); -#define PrintColorText(i, format, size, color, ...) Freetype::print(font, size, static_cast(startY - font_size_mono * i * 2), color, format, __VA_ARGS__); +#define PrintText(__i__, __format__, ...) Freetype::print(font, 10.f, static_cast(startY - font_size_mono * __i__ * 2), __format__, __VA_ARGS__); +#define PrintColorTextArg(__i__, __format__, __size__, __color__, ...) Freetype::print(font, __size__, static_cast(startY - font_size_mono * __i__ * 2), __color__, __format__, __VA_ARGS__); +#define PrintColorText(__i__, __format__, __size__, __color__) Freetype::print(font, __size__, static_cast(startY - font_size_mono * __i__ * 2), __color__, __format__); if (_onScreenInformation._node != -1) { int thisId = sgct_core::ClusterManager::instance()->getThisNodeId(); @@ -536,13 +537,13 @@ namespace openspace { // GUI PRINT // Using a macro to shorten line length and increase readability - int i = 0; + int line = 0; - PrintText(i++, "Date: %s", Time::ref().currentTimeUTC().c_str()); + PrintText(line++, "Date: %s", Time::ref().currentTimeUTC().c_str()); - PrintText(i++, "Avg. Frametime: %.5f", sgct::Engine::instance()->getAvgDt()); - PrintText(i++, "Drawtime: %.5f", sgct::Engine::instance()->getDrawTime()); - PrintText(i++, "Frametime: %.5f", sgct::Engine::instance()->getDt()); + PrintText(line++, "Avg. Frametime: %.5f", sgct::Engine::instance()->getAvgDt()); + PrintText(line++, "Drawtime: %.5f", sgct::Engine::instance()->getDrawTime()); + PrintText(line++, "Frametime: %.5f", sgct::Engine::instance()->getDt()); /* PrintText(i++, "Origin: (% .5f, % .5f, % .5f, % .5f)", origin[0], origin[1], origin[2], origin[3]); PrintText(i++, "Cam pos: (% .5f, % .5f, % .5f, % .5f)", position[0], position[1], position[2], position[3]); @@ -556,8 +557,11 @@ namespace openspace { double t = 1.f - remaining / openspace::ImageSequencer2::ref().getIntervalLength(); std::string progress = "|"; int g = ((t)* 30) + 1; - for (int i = 0; i < g; i++) progress.append("-"); progress.append(">"); - for (int i = 0; i < 31 - g; i++) progress.append(" "); + for (int i = 0; i < g; i++) + progress.append("-"); + progress.append(">"); + for (int i = 0; i < 31 - g; i++) + progress.append(" "); std::string str = ""; openspace::SpiceManager::ref().getDateFromET(openspace::ImageSequencer2::ref().getNextCaptureTime(), str); @@ -566,69 +570,72 @@ namespace openspace { if (remaining > 0){ glm::vec4 g1(0, t, 0, 1); glm::vec4 g2(1 - t); - PrintColorText(i++, "Next projection in:", 10, g1 + g2); - PrintColorText(i++, "%.0f sec %s %.1f %%", 10, g1 + g2, remaining, progress.c_str(), t * 100); + PrintColorText(line++, "Next projection in:", 10, g1 + g2); + PrintColorTextArg(line++, "%.0f sec %s %.1f %%", 10, g1 + g2, remaining, progress.c_str(), t * 100); } glm::vec4 w(1); - PrintColorText(i++, "Ucoming capture : %s", 10, w, str.c_str()); + PrintColorTextArg(line++, "Ucoming capture : %s", 10, w, str.c_str()); std::pair nextTarget = ImageSequencer2::ref().getNextTarget(); std::pair currentTarget = ImageSequencer2::ref().getCurrentTarget(); - int timeleft = nextTarget.first - currentTime; + if (currentTarget.first > 0.0) { + int timeleft = nextTarget.first - currentTime; - int hour = timeleft / 3600; - int second = timeleft % 3600; - int minute = second / 60; - second = second % 60; + int hour = timeleft / 3600; + int second = timeleft % 3600; + int minute = second / 60; + second = second % 60; - std::string hh, mm, ss, coundtown; + std::string hh, mm, ss, coundtown; - if (hour < 10) hh.append("0"); - if (minute < 10) mm.append("0"); - if (second < 10) ss.append("0"); + if (hour < 10) hh.append("0"); + if (minute < 10) mm.append("0"); + if (second < 10) ss.append("0"); - hh.append(std::to_string(hour)); - mm.append(std::to_string(minute)); - ss.append(std::to_string(second)); + hh.append(std::to_string(hour)); + mm.append(std::to_string(minute)); + ss.append(std::to_string(second)); - glm::vec4 b2(1.00, 0.51, 0.00, 1); - PrintColorText(i++, "Switching observation focus in : [%s:%s:%s]", 10, b2, hh.c_str(), mm.c_str(), ss.c_str()); + glm::vec4 b2(1.00, 0.51, 0.00, 1); + PrintColorTextArg(line++, "Switching observation focus in : [%s:%s:%s]", 10, b2, hh.c_str(), mm.c_str(), ss.c_str()); - std::pair> incidentTargets = ImageSequencer2::ref().getIncidentTargetList(2); - std::string space; - glm::vec4 color; - int isize = incidentTargets.second.size(); - for (int p = 0; p < isize; p++){ - double t = (double)(p + 1) / (double)(isize+1); - t = (p > isize / 2) ? 1-t : t; - t += 0.3; - color = (p == isize / 2) ? glm::vec4(1.00, 0.51, 0.00, 1) : glm::vec4(t, t, t, 1); - PrintColorText(i, "%s%s", 10, color, space.c_str(), incidentTargets.second[p].c_str()); - for (int k = 0; k < 10; k++){ space += " "; } - } - i++; + std::pair> incidentTargets = ImageSequencer2::ref().getIncidentTargetList(2); + std::string space; + glm::vec4 color; + int isize = incidentTargets.second.size(); + for (int p = 0; p < isize; p++){ + double t = (double)(p + 1) / (double)(isize + 1); + t = (p > isize / 2) ? 1 - t : t; + t += 0.3; + color = (p == isize / 2) ? glm::vec4(1.00, 0.51, 0.00, 1) : glm::vec4(t, t, t, 1); + PrintColorTextArg(line, "%s%s", 10, color, space.c_str(), incidentTargets.second[p].c_str()); + for (int k = 0; k < 10; k++) + space += " "; + } + line++; - std::map activeMap = ImageSequencer2::ref().getActiveInstruments(); - glm::vec4 active(0.58, 1, 0.00, 1); - glm::vec4 firing(0.58-t, 1-t, 1-t, 1); - glm::vec4 notFiring(0.5, 0.5, 0.5, 1); - PrintColorText(i++, "Active Instruments : ", 10, active); - for (auto t : activeMap){ - if (t.second == false){ - PrintColorText(i, "| |", 10, glm::vec4(0.3, 0.3, 0.3, 1)); - PrintColorText(i++, " %5s", 10, glm::vec4(0.3, 0.3, 0.3, 1), t.first.c_str()); - } - else{ - PrintColorText(i, "|", 10, glm::vec4(0.3, 0.3, 0.3, 1)); - if (t.first == "NH_LORRI"){ - PrintColorText(i, " + ", 10, firing); - } - PrintColorText(i, " |", 10, glm::vec4(0.3, 0.3, 0.3, 1)); - PrintColorText(i++, " %5s", 10, active, t.first.c_str()); - } - } + std::map activeMap = ImageSequencer2::ref().getActiveInstruments(); + glm::vec4 active(0.58, 1, 0.00, 1); + glm::vec4 firing(0.58-t, 1-t, 1-t, 1); + glm::vec4 notFiring(0.5, 0.5, 0.5, 1); + PrintColorText(line++, "Active Instruments : ", 10, active); + for (auto t : activeMap){ + if (t.second == false){ + PrintColorText(line, "| |", 10, glm::vec4(0.3, 0.3, 0.3, 1)); + PrintColorTextArg(line++, " %5s", 10, glm::vec4(0.3, 0.3, 0.3, 1), t.first.c_str()); + } + else{ + PrintColorText(line, "|", 10, glm::vec4(0.3, 0.3, 0.3, 1)); + if (t.first == "NH_LORRI"){ + PrintColorText(line, " + ", 10, firing); + } + PrintColorText(line, " |", 10, glm::vec4(0.3, 0.3, 0.3, 1)); + PrintColorTextArg(line++, " %5s", 10, active, t.first.c_str()); + } + } + } } #undef PrintText @@ -977,7 +984,7 @@ void RenderEngine::changeViewPoint(std::string origin) { SceneGraphNode* jupiterBarycenterNode = scene()->sceneGraphNode("JupiterBarycenter"); - SceneGraphNode* newHorizonsGhostNode = scene()->sceneGraphNode("NewHorizonsGhost"); + //SceneGraphNode* newHorizonsGhostNode = scene()->sceneGraphNode("NewHorizonsGhost"); //SceneGraphNode* dawnNode = scene()->sceneGraphNode("Dawn"); //SceneGraphNode* vestaNode = scene()->sceneGraphNode("Vesta"); @@ -996,7 +1003,7 @@ void RenderEngine::changeViewPoint(std::string origin) { solarSystemBarycenterNode->setParent(plutoBarycenterNode); newHorizonsNode->setParent(plutoBarycenterNode); - newHorizonsGhostNode->setParent(plutoBarycenterNode); + //newHorizonsGhostNode->setParent(plutoBarycenterNode); //dawnNode->setParent(plutoBarycenterNode); //vestaNode->setParent(plutoBarycenterNode); @@ -1056,16 +1063,16 @@ void RenderEngine::changeViewPoint(std::string origin) { //vestaNode->setEphemeris(new SpiceEphemeris(vestaDictionary)); - ghoul::Dictionary newHorizonsGhostDictionary = - { - { std::string("Type"), std::string("Spice") }, - { std::string("Body"), std::string("NEW HORIZONS") }, - { std::string("EphmerisGhosting"), std::string("TRUE") }, - { std::string("Reference"), std::string("GALACTIC") }, - { std::string("Observer"), std::string("PLUTO BARYCENTER") }, - { std::string("Kernels"), ghoul::Dictionary() } - }; - newHorizonsGhostNode->setEphemeris(new SpiceEphemeris(newHorizonsGhostDictionary)); + //ghoul::Dictionary newHorizonsGhostDictionary = + //{ + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("NEW HORIZONS") }, + // { std::string("EphmerisGhosting"), std::string("TRUE") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("PLUTO BARYCENTER") }, + // { std::string("Kernels"), ghoul::Dictionary() } + //}; + //newHorizonsGhostNode->setEphemeris(new SpiceEphemeris(newHorizonsGhostDictionary)); return; } @@ -1075,7 +1082,7 @@ void RenderEngine::changeViewPoint(std::string origin) { plutoBarycenterNode->setParent(solarSystemBarycenterNode); jupiterBarycenterNode->setParent(solarSystemBarycenterNode); newHorizonsNode->setParent(solarSystemBarycenterNode); - newHorizonsGhostNode->setParent(solarSystemBarycenterNode); + //newHorizonsGhostNode->setParent(solarSystemBarycenterNode); //newHorizonsTrailNode->setParent(solarSystemBarycenterNode); //dawnNode->setParent(solarSystemBarycenterNode); @@ -1135,16 +1142,16 @@ void RenderEngine::changeViewPoint(std::string origin) { //vestaNode->setEphemeris(new SpiceEphemeris(vestaDictionary)); - ghoul::Dictionary newHorizonsGhostDictionary = - { - { std::string("Type"), std::string("Spice") }, - { std::string("Body"), std::string("NEW HORIZONS") }, - { std::string("EphmerisGhosting"), std::string("TRUE") }, - { std::string("Reference"), std::string("GALACTIC") }, - { std::string("Observer"), std::string("JUPITER BARYCENTER") }, - { std::string("Kernels"), ghoul::Dictionary() } - }; - newHorizonsGhostNode->setEphemeris(new SpiceEphemeris(newHorizonsGhostDictionary)); + //ghoul::Dictionary newHorizonsGhostDictionary = + //{ + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("NEW HORIZONS") }, + // { std::string("EphmerisGhosting"), std::string("TRUE") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("JUPITER BARYCENTER") }, + // { std::string("Kernels"), ghoul::Dictionary() } + //}; + //newHorizonsGhostNode->setEphemeris(new SpiceEphemeris(newHorizonsGhostDictionary)); return; } @@ -1189,7 +1196,7 @@ void RenderEngine::changeViewPoint(std::string origin) { solarSystemBarycenterNode->setEphemeris(new SpiceEphemeris(solarDictionary)); plutoBarycenterNode->setEphemeris(new SpiceEphemeris(plutoDictionary)); newHorizonsNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary)); - newHorizonsGhostNode->setParent(jupiterBarycenterNode); + //newHorizonsGhostNode->setParent(jupiterBarycenterNode); //newHorizonsTrailNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary)); @@ -1215,17 +1222,17 @@ void RenderEngine::changeViewPoint(std::string origin) { - ghoul::Dictionary newHorizonsGhostDictionary = - { - { std::string("Type"), std::string("Spice") }, - { std::string("Body"), std::string("NEW HORIZONS") }, - { std::string("EphmerisGhosting"), std::string("TRUE") }, - { std::string("Reference"), std::string("GALACTIC") }, - { std::string("Observer"), std::string("JUPITER BARYCENTER") }, - { std::string("Kernels"), ghoul::Dictionary() } - }; - newHorizonsGhostNode->setEphemeris(new SpiceEphemeris(newHorizonsGhostDictionary)); - newHorizonsGhostNode->setParent(jupiterBarycenterNode); + //ghoul::Dictionary newHorizonsGhostDictionary = + //{ + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("NEW HORIZONS") }, + // { std::string("EphmerisGhosting"), std::string("TRUE") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("JUPITER BARYCENTER") }, + // { std::string("Kernels"), ghoul::Dictionary() } + //}; + //newHorizonsGhostNode->setEphemeris(new SpiceEphemeris(newHorizonsGhostDictionary)); + //newHorizonsGhostNode->setParent(jupiterBarycenterNode); return; diff --git a/src/util/hongkangparser.cpp b/src/util/hongkangparser.cpp index 74bc79967a..5fe88b4f9e 100644 --- a/src/util/hongkangparser.cpp +++ b/src/util/hongkangparser.cpp @@ -22,12 +22,14 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -39,6 +41,8 @@ namespace { const std::string _loggerCat = "HongKangParser"; const std::string keyTranslation = "DataInputTranslation"; + + const std::string PlaybookIdentifierName = "Playbook"; } namespace openspace { @@ -248,6 +252,8 @@ void HongKangParser::create(){ } } } + + sendPlaybookInformation(); std::ofstream myfile; myfile.open("HongKangOutput.txt"); @@ -374,4 +380,123 @@ std::vector HongKangParser::getCaptureProgression(){ return _captureProgression; }; + +template +void writeToBuffer(std::vector& buffer, size_t& currentWriteLocation, T value) { + if ((currentWriteLocation + sizeof(T)) > buffer.size()) + buffer.resize(2 * buffer.size()); + + std::memmove(buffer.data() + currentWriteLocation, reinterpret_cast(&value), sizeof(T)); + currentWriteLocation += sizeof(T); +} + +template <> + +void writeToBuffer(std::vector& buffer, size_t& currentWriteLocation, std::string value) { + if ((currentWriteLocation + sizeof(uint8_t) + value.size()) > buffer.size()) + buffer.resize(2 * buffer.size()); + + uint8_t length = value.size(); + std::memcpy(buffer.data() + currentWriteLocation, &length, sizeof(uint8_t)); + currentWriteLocation += sizeof(uint8_t); + + std::memmove(buffer.data() + currentWriteLocation, value.data(), length); + currentWriteLocation += length; +} + + +void HongKangParser::sendPlaybookInformation() { + static const NetworkEngine::MessageIdentifier PlaybookIdentifier = OsEng.networkEngine()->identifier(PlaybookIdentifierName); + + std::vector buffer(1024); + size_t currentWriteLocation = 0; + + // Protocol: + // 4 bytes: Total number of bytes sent + // 1 byte : Number of Targets (i) + // i times: 1 byte (id), 1 byte (length j of name), j bytes (name) + // 1 byte : Number of Instruments (i) + // i times: 1 byte (id), 1 byte (length j of name), j bytes (name) + // 4 byte: Number (n) of images + // n times: 8 byte (beginning time), 8 byte (ending time), 1 byte (target id), 2 byte (instrument id) + + std::map targetMap; + uint8_t currentTargetId = 0; + for (auto target : _subsetMap) { + if (targetMap.find(target.first) == targetMap.end()) + targetMap[target.first] = currentTargetId++; + } + + std::map instrumentMap; + uint16_t currentInstrumentId = 1; + for (auto target : _subsetMap) { + for (auto image : target.second._subset) { + for (auto instrument : image.activeInstruments) { + if (instrumentMap.find(instrument) == instrumentMap.end()) { + instrumentMap[instrument] = currentInstrumentId; + currentInstrumentId = currentInstrumentId << 1; + } + } + } + } + + writeToBuffer(buffer, currentWriteLocation, uint8_t(targetMap.size())); + for (const std::pair& p : targetMap) { + writeToBuffer(buffer, currentWriteLocation, p.second); + writeToBuffer(buffer, currentWriteLocation, p.first); + } + + writeToBuffer(buffer, currentWriteLocation, uint8_t(instrumentMap.size())); + for (const std::pair& p : instrumentMap) { + writeToBuffer(buffer, currentWriteLocation, p.second); + writeToBuffer(buffer, currentWriteLocation, p.first); + } + + uint32_t allImages = 0; + for (auto target : _subsetMap) + allImages += target.second._subset.size(); + writeToBuffer(buffer, currentWriteLocation, allImages); + + for (auto target : _subsetMap){ + for (auto image : target.second._subset){ + writeToBuffer(buffer, currentWriteLocation, image.startTime); + writeToBuffer(buffer, currentWriteLocation, image.stopTime); + + std::string timeBegin; + std::string timeEnd; + SpiceManager::ref().getDateFromET(image.startTime, timeBegin); + SpiceManager::ref().getDateFromET(image.stopTime, timeEnd); + + writeToBuffer(buffer, currentWriteLocation, timeBegin); + writeToBuffer(buffer, currentWriteLocation, timeEnd); + + uint8_t targetId = targetMap[target.first]; + writeToBuffer(buffer, currentWriteLocation, targetId); + uint16_t totalInstrumentId = 0; + if (image.activeInstruments.empty()) { + LERROR("Image had no active instruments"); + } + + for (auto instrument : image.activeInstruments) { + uint16_t thisInstrumentId = instrumentMap[instrument]; + totalInstrumentId |= thisInstrumentId; + } + writeToBuffer(buffer, currentWriteLocation, totalInstrumentId); + } + } + + union { + uint32_t value; + std::array data; + } sizeBuffer; + sizeBuffer.value = currentWriteLocation; + buffer.insert(buffer.begin(), sizeBuffer.data.begin(), sizeBuffer.data.end()); + currentWriteLocation += sizeof(uint32_t); + + buffer.resize(currentWriteLocation); + + //OsEng.networkEngine()->publishMessage(PlaybookIdentifier, buffer); + OsEng.networkEngine()->setInitialConnectionMessage(PlaybookIdentifier, buffer); +} + } \ No newline at end of file diff --git a/src/util/imagesequencer2.cpp b/src/util/imagesequencer2.cpp index 1ef6cc6baf..446cd20bf0 100644 --- a/src/util/imagesequencer2.cpp +++ b/src/util/imagesequencer2.cpp @@ -23,7 +23,7 @@ ****************************************************************************************/ // open space includes -#include +#include #include #include #include @@ -98,9 +98,11 @@ std::pair ImageSequencer2::getCurrentTarget(){ findEqualToThis.first = _currentTime; auto it = std::lower_bound(_targetTimes.begin(), _targetTimes.end(), findEqualToThis, compareTime); - if (it != _targetTimes.end() && it != _targetTimes.begin() ){ + if (it != _targetTimes.end() && it != _targetTimes.begin()){ return *std::prev(it); } + else + return std::make_pair(0.0, "No Target"); } std::pair> ImageSequencer2::getIncidentTargetList(int range){ @@ -235,22 +237,19 @@ bool ImageSequencer2::getImagePaths(std::vector& captures, auto curr = std::lower_bound(begin, end, findCurrent, compareTime); auto prev = std::lower_bound(begin, end, findPrevious, compareTime); - if (curr != begin && curr != end && prev != begin && prev != end){ - if (curr->startTime >= prev->startTime){ - // insert - std::transform(prev, curr, std::back_inserter(captureTimes), - [](const Image& image) { - return image; - }); - std::reverse(captureTimes.begin(), captureTimes.end()); + if (curr != begin && curr != end && prev != begin && prev != end && prev < curr){ + if (curr->startTime >= prev->startTime){ + std::transform(prev, curr, std::back_inserter(captureTimes), + [](const Image& i) { + return i; + }); + std::reverse(captureTimes.begin(), captureTimes.end()); + captures = captureTimes; + if (!captures.empty()) + _latestImage = &captures.back(); - captures = captureTimes; - - if (!captures.empty()) - _latestImage = &captures.back(); - - return true; - } + return true; + } } } return false; @@ -283,11 +282,11 @@ void ImageSequencer2::runSequenceParser(SequenceParser* parser){ std::vector in5 = parser->getCaptureProgression(); // check for sanity - assert(in1.size() > 0, "Sequencer failed to load Translation" ); - assert(in2.size() > 0, "Sequencer failed to load Image data" ); - assert(in3.size() > 0, "Sequencer failed to load Instrument Switching schedule"); - assert(in4.size() > 0, "Sequencer failed to load Target Switching schedule" ); - assert(in5.size() > 0, "Sequencer failed to load Capture progression" ); + ghoul_assert(in1.size() > 0, "Sequencer failed to load Translation" ); + ghoul_assert(in2.size() > 0, "Sequencer failed to load Image data" ); + ghoul_assert(in3.size() > 0, "Sequencer failed to load Instrument Switching schedule"); + ghoul_assert(in4.size() > 0, "Sequencer failed to load Target Switching schedule" ); + ghoul_assert(in5.size() > 0, "Sequencer failed to load Capture progression" ); // append data diff --git a/src/util/labelparser.cpp b/src/util/labelparser.cpp index 7ea41621d8..cf14549fc9 100644 --- a/src/util/labelparser.cpp +++ b/src/util/labelparser.cpp @@ -22,7 +22,6 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include #include #include #include diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index 3f9b24d5d5..e80de5fc5b 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -48,9 +48,9 @@ void SpiceManager::initialize() { _manager->_lastAssignedKernel = 0; // Set the SPICE library to not exit the program if an error occurs - erract_c("SET", 0, static_cast("REPORT")); + erract_c("SET", 0, const_cast("REPORT")); // But we do not want SPICE to print the errors, we will fetch them ourselves - errprt_c("SET", 0, static_cast("NONE")); + errprt_c("SET", 0, const_cast("NONE")); } void SpiceManager::deinitialize() { @@ -61,8 +61,8 @@ void SpiceManager::deinitialize() { _manager = nullptr; // Set values back to default - erract_c("SET", 0, static_cast("DEFAULT")); - errprt_c("SET", 0, static_cast("DEFAULT")); + erract_c("SET", 0, const_cast("DEFAULT")); + errprt_c("SET", 0, const_cast("DEFAULT")); } SpiceManager& SpiceManager::ref() {