Merge branch 'thesis/2020/software-integration' of https://github.com/OpenSpace/OpenSpace into thesis/2020/software-integration

# Conflicts:
#	modules/softwareintegration/softwareintegrationmodule.cpp
This commit is contained in:
Johann Granström
2020-09-24 11:47:21 +02:00
8 changed files with 219 additions and 4378 deletions
@@ -25,11 +25,8 @@
#include <modules/softwareintegration/network/softwareconnection.h>
#include <openspace/rendering/renderable.h>
#include <openspace/query/query.h>
#include <ghoul/logging/logmanager.h>
#include <iomanip>
namespace {
constexpr const char* _loggerCat = "SoftwareConnection";
} // namespace
@@ -44,7 +41,7 @@ namespace openspace {
{}
SoftwareConnection::SoftwareConnectionLostError::SoftwareConnectionLostError()
: ghoul::RuntimeError("Connection lost", "Connection")
: ghoul::RuntimeError("Software connection lost", "SoftwareConnection")
{}
SoftwareConnection::SoftwareConnection(std::unique_ptr<ghoul::io::TcpSocket> socket)
@@ -55,6 +52,14 @@ namespace openspace {
return _socket->isConnected() || _socket->isConnecting();
}
bool SoftwareConnection::sendMessage(std::string message) {
if (!_socket->put<char>(message.data(), message.size())) {
return false;
}
return true;
}
void SoftwareConnection::disconnect() {
if (_socket) {
_socket->disconnect();
@@ -125,6 +130,8 @@ namespace openspace {
return Message(MessageType::Opacity, messageBuffer);
else if( type == "UPSI")
return Message(MessageType::Size, messageBuffer);
else if (type == "TOVI")
return Message(MessageType::Visibility, messageBuffer);
else if (type == "DISC")
return Message(MessageType::Disconnection, messageBuffer);
else {
@@ -133,13 +140,5 @@ namespace openspace {
}
}
bool SoftwareConnection::sendMessage(std::string message) {
if (!_socket->put<char>(message.data(), message.size())) {
return false;
}
return true;
}
} // namespace openspace
@@ -27,7 +27,6 @@
#include <openspace/network/messagestructures.h>
#include <ghoul/io/socket/tcpsocket.h>
#include <vector>
namespace openspace {
@@ -45,6 +44,7 @@ public:
Color,
Opacity,
Size,
Visibility,
Disconnection
};
@@ -65,9 +65,9 @@ public:
SoftwareConnection(std::unique_ptr<ghoul::io::TcpSocket> socket);
bool isConnectedOrConnecting() const;
bool sendMessage(std::string message);
void disconnect();
ghoul::io::TcpSocket* socket();
bool sendMessage(std::string message);
SoftwareConnection::Message receiveMessage();
@@ -103,6 +103,12 @@ namespace openspace {
new DoubleVerifier,
Optional::Yes,
SizeInfo.description
},
{
ToggleVisibilityInfo.identifier,
new BoolVerifier,
Optional::Yes,
ToggleVisibilityInfo.description
}
}
};
@@ -1,53 +0,0 @@
openspace.softwareintegration.documentation = {
{
Name = "addRenderable",
Arguments = "string, vec3, string, float, float, string",
Documentation = "TODO"
},
{
Name = "removeRenderable",
Arguments = "string",
Documentation = "TODO"
},
{
Name = "updateProperties",
Arguments = "string, vec3, vec3",
Documentation = "TODO"
}
}
openspace.softwareintegration.addRenderable = function (id, colors, file, alpha, size, guiName)
local RenderablePointsCloud = {
Identifier = id,
Renderable = {
Type = "RenderablePointsCloud",
Color = colors,
File = file,
Opacity = alpha,
Size = size,
},
GUI = {
Name = guiName,
Path = "/Examples"
}
}
openspace.addSceneGraphNode(RenderablePointsCloud)
end
openspace.softwareintegration.removeRenderable = function (id)
if openspace.hasSceneGraphNode(id) then
openspace.removeSceneGraphNode(id)
end
end
openspace.softwareintegration.updateProperties = function (id, argument, string)
if string == "alpha" then
openspace.setPropertyValueSingle('Scene.' .. id .. '.Renderable.Opacity', argument)
elseif string == "color" then
openspace.setPropertyValueSingle('Scene.' .. id .. '.Renderable.Color', argument)
elseif string == "size" then
openspace.setPropertyValueSingle('Scene.' .. id .. '.Renderable.Size', argument)
end
end
@@ -27,28 +27,14 @@
#include <modules/softwareintegration/rendering/renderablepointscloud.h>
#include <openspace/documentation/documentation.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/factorymanager.h>
#include <openspace/query/query.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/fmt.h>
#include <ghoul/glm.h>
#include <ghoul/io/socket/tcpsocket.h>
#include <ghoul/io/socket/tcpsocketserver.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/assert.h>
#include <ghoul/misc/templatefactory.h>
#include <functional>
#include <iomanip>
#include <sstream>
using namespace std::string_literals;
@@ -66,6 +52,7 @@ namespace openspace {
fRenderable->registerClass<RenderablePointsCloud>("RenderablePointsCloud");
// Open port
start(4700);
}
@@ -86,6 +73,21 @@ namespace openspace {
_socketServer.close();
}
bool SoftwareIntegrationModule::isConnected(const Peer& peer) const {
return peer.status != SoftwareConnection::Status::Connecting &&
peer.status != SoftwareConnection::Status::Disconnected;
}
void SoftwareIntegrationModule::disconnect(Peer& peer) {
if (isConnected(peer)) {
_nConnections = nConnections() - 1;
}
peer.connection.disconnect();
peer.thread.join();
_peers.erase(peer.id);
}
void SoftwareIntegrationModule::handleNewPeers() {
while (!_shouldStop) {
std::unique_ptr<ghoul::io::TcpSocket> socket =
@@ -108,6 +110,13 @@ namespace openspace {
}
}
void SoftwareIntegrationModule::eventLoop() {
while (!_shouldStop) {
PeerMessage pm = _incomingMessages.pop();
handlePeerMessage(std::move(pm));
}
}
std::shared_ptr<SoftwareIntegrationModule::Peer> SoftwareIntegrationModule::peer(size_t id) {
std::lock_guard<std::mutex> lock(_peerListMutex);
auto it = _peers.find(id);
@@ -144,84 +153,12 @@ namespace openspace {
}
}
void SoftwareIntegrationModule::eventLoop() {
while (!_shouldStop) {
PeerMessage pm = _incomingMessages.pop();
handlePeerMessage(std::move(pm));
}
}
void SoftwareIntegrationModule::handleProperties(std::string identifier, const std::shared_ptr<Peer>& peer) {
const Renderable* myRenderable = renderable(identifier);
properties::Property* colorProperty = myRenderable->property("Color");
properties::Property* opacityProperty = myRenderable->property("Opacity");
properties::Property* sizeProperty = myRenderable->property("Size");
// Update color of renderable
auto updateColor = [colorProperty, identifier, peer]() {
std::string lengthOfIdentifier = std::to_string(identifier.length());
std::string propertyValue = colorProperty->getStringValue();
std::string lengthOfValue = std::to_string(propertyValue.length());
std::string messageType = "UPCO";
std::string subject = lengthOfIdentifier + identifier + lengthOfValue + propertyValue;
// Format length of subject to always be 4 digits
std::ostringstream os;
os << std::setfill('0') << std::setw(4) << subject.length();
std::string lengthOfSubject = os.str();
std::string message = messageType + lengthOfSubject + subject;
peer->connection.sendMessage(message);
};
colorProperty->onChange(updateColor);
// Update opacity of renderable
auto updateOpacity = [opacityProperty, identifier, peer]() {
std::string lengthOfIdentifier = std::to_string(identifier.length());
std::string propertyValue = opacityProperty->getStringValue();
std::string lengthOfValue = std::to_string(propertyValue.length());
std::string messageType = "UPOP";
std::string subject = lengthOfIdentifier + identifier + lengthOfValue + propertyValue;
LERROR(fmt::format("OPACITY MESSAGE: {}", propertyValue));
// Format length of subject to always be 4 digits
std::ostringstream os;
os << std::setfill('0') << std::setw(4) << subject.length();
std::string lengthOfSubject = os.str();
std::string message = messageType + lengthOfSubject + subject;
LERROR(fmt::format("OPACITY MESSAGE: {}", message));
peer->connection.sendMessage(message);
};
opacityProperty->onChange(updateOpacity);
// Update size of renderable
auto updateSize = [sizeProperty, identifier, peer]() {
std::string lengthOfIdentifier = std::to_string(identifier.length());
std::string propertyValue = sizeProperty->getStringValue();
std::string lengthOfValue = std::to_string(propertyValue.length());
std::string messageType = "UPSI";
std::string subject = lengthOfIdentifier + identifier + lengthOfValue + propertyValue;
// Format length of subject to always be 4 digits
std::ostringstream os;
os << std::setfill('0') << std::setw(4) << subject.length();
std::string lengthOfSubject = os.str();
std::string message = messageType + lengthOfSubject + subject;
peer->connection.sendMessage(message);
};
sizeProperty->onChange(updateSize);
}
void SoftwareIntegrationModule::handlePeerMessage(PeerMessage peerMessage) {
const size_t peerId = peerMessage.peerId;
auto it = _peers.find(peerId);
if (it == _peers.end()) {
return;
}
std::shared_ptr<Peer>& peer = it->second;
const SoftwareConnection::MessageType messageType = peerMessage.message.type;
@@ -278,18 +215,16 @@ namespace openspace {
}
handleProperties(identifier, peer);
break;
}
case SoftwareConnection::MessageType::RemoveSceneGraphNode: {
std::string identifier(message.begin(), message.end());
LERROR(fmt::format("Identifier: {}", identifier));
LINFO(fmt::format("Scengraph {} removed.", identifier));
openspace::global::scriptEngine.queueScript(
"openspace.removeSceneGraphNode('" + identifier + "');",
scripting::ScriptEngine::RemoteScripting::Yes
);
break;
}
case SoftwareConnection::MessageType::Color: {
@@ -297,8 +232,8 @@ namespace openspace {
glm::vec3 color = readColor(message);
// Update color of renderable
const Renderable* myrenderable = renderable(identifier);
properties::Property* colorProperty = myrenderable->property("Color");
const Renderable* myRenderable = renderable(identifier);
properties::Property* colorProperty = myRenderable->property("Color");
colorProperty->set(color);
break;
}
@@ -307,8 +242,8 @@ namespace openspace {
float opacity = readFloatValue(message);
// Update opacity of renderable
const Renderable* myrenderable = renderable(identifier);
properties::Property* opacityProperty = myrenderable->property("Opacity");
const Renderable* myRenderable = renderable(identifier);
properties::Property* opacityProperty = myRenderable->property("Opacity");
opacityProperty->set(opacity);
break;
}
@@ -317,11 +252,25 @@ namespace openspace {
float size = readFloatValue(message);
// Update size of renderable
const Renderable* myrenderable = renderable(identifier);
properties::Property* sizeProperty = myrenderable->property("Size");
const Renderable* myRenderable = renderable(identifier);
properties::Property* sizeProperty = myRenderable->property("Size");
sizeProperty->set(size);
break;
}
case SoftwareConnection::MessageType::Visibility: {
std::string identifier = readIdentifier(message);
std::string visibility;
visibility.push_back(message[messageOffset]);
// Toggle visibility of renderable
const Renderable* myRenderable = renderable(identifier);
properties::Property* visibilityProperty = myRenderable->property("ToggleVisibility");
if(visibility == "F")
visibilityProperty->set(false);
else
visibilityProperty->set(true);
break;
}
case SoftwareConnection::MessageType::Disconnection: {
disconnect(*peer);
break;
@@ -334,33 +283,97 @@ namespace openspace {
}
}
std::string SoftwareIntegrationModule::readIdentifier(std::vector<char>& message) {
void SoftwareIntegrationModule::handleProperties(std::string identifier, const std::shared_ptr<Peer>& peer) {
const Renderable* myRenderable = renderable(identifier);
properties::Property* colorProperty = myRenderable->property("Color");
properties::Property* opacityProperty = myRenderable->property("Opacity");
properties::Property* sizeProperty = myRenderable->property("Size");
properties::Property* visibilityProperty = myRenderable->property("ToggleVisibility");
std::string length;
length.push_back(message[0]);
length.push_back(message[1]);
// Update color of renderable
auto updateColor = [colorProperty, identifier, peer]() {
std::string lengthOfIdentifier = std::to_string(identifier.length());
std::string propertyValue = colorProperty->getStringValue();
std::string lengthOfValue = std::to_string(propertyValue.length());
std::string messageType = "UPCO";
std::string subject = lengthOfIdentifier + identifier + lengthOfValue + propertyValue;
int lengthOfIdentifier = stoi(length);
int counter = 0;
messageOffset = 2;
// Format length of subject to always be 4 digits
std::ostringstream os;
os << std::setfill('0') << std::setw(4) << subject.length();
std::string lengthOfSubject = os.str();
std::string identifier;
while (counter != lengthOfIdentifier)
{
identifier.push_back(message[messageOffset]);
messageOffset++;
counter++;
}
std::string message = messageType + lengthOfSubject + subject;
peer->connection.sendMessage(message);
};
colorProperty->onChange(updateColor);
return identifier;
// Update opacity of renderable
auto updateOpacity = [opacityProperty, identifier, peer]() {
std::string lengthOfIdentifier = std::to_string(identifier.length());
std::string propertyValue = opacityProperty->getStringValue();
std::string lengthOfValue = std::to_string(propertyValue.length());
std::string messageType = "UPOP";
std::string subject = lengthOfIdentifier + identifier + lengthOfValue + propertyValue;
// Format length of subject to always be 4 digits
std::ostringstream os;
os << std::setfill('0') << std::setw(4) << subject.length();
std::string lengthOfSubject = os.str();
std::string message = messageType + lengthOfSubject + subject;
peer->connection.sendMessage(message);
};
opacityProperty->onChange(updateOpacity);
// Update size of renderable
auto updateSize = [sizeProperty, identifier, peer]() {
std::string lengthOfIdentifier = std::to_string(identifier.length());
std::string propertyValue = sizeProperty->getStringValue();
std::string lengthOfValue = std::to_string(propertyValue.length());
std::string messageType = "UPSI";
std::string subject = lengthOfIdentifier + identifier + lengthOfValue + propertyValue;
// Format length of subject to always be 4 digits
std::ostringstream os;
os << std::setfill('0') << std::setw(4) << subject.length();
std::string lengthOfSubject = os.str();
std::string message = messageType + lengthOfSubject + subject;
peer->connection.sendMessage(message);
};
sizeProperty->onChange(updateSize);
// Toggle visibility of renderable
auto toggleVisibility = [visibilityProperty, identifier, peer]() {
std::string lengthOfIdentifier = std::to_string(identifier.length());
std::string messageType = "TOVI";
std::string propertyValue;
if (visibilityProperty->getStringValue() == "false")
propertyValue = "F";
else
propertyValue = "T";
std::string subject = lengthOfIdentifier + identifier + propertyValue;
// We don't need a lengthOfValue here because it will always be 1 character
// Format length of subject to always be 4 digits
std::ostringstream os;
os << std::setfill('0') << std::setw(4) << subject.length();
std::string lengthOfSubject = os.str();
std::string message = messageType + lengthOfSubject + subject;
peer->connection.sendMessage(message);
};
visibilityProperty->onChange(toggleVisibility);
}
// Read size value or opacity value
float SoftwareIntegrationModule::readFloatValue(std::vector<char>& message) {
std::string length;
length.push_back(message[messageOffset]);
messageOffset += 1;
messageOffset++;
int lengthOfValue = stoi(length);
std::string value;
@@ -376,61 +389,33 @@ namespace openspace {
return floatValue;
}
glm::vec3 SoftwareIntegrationModule::readColor(std::vector<char>& message) {
std::string SoftwareIntegrationModule::readIdentifier(std::vector<char>& message) {
std::string length;
length.push_back(message[0]);
length.push_back(message[1]);
std::string lengthOfColor; // Not used for now, but sent in message
lengthOfColor.push_back(message[messageOffset]);
lengthOfColor.push_back(message[messageOffset + 1]);
messageOffset += 2;
int lengthOfIdentifier = stoi(length);
int counter = 0;
messageOffset = 2; // Resets messageOffset
// Red
std::string red;
while (message[messageOffset] != ',')
std::string identifier;
while (counter != lengthOfIdentifier)
{
if (message[messageOffset] == '(')
messageOffset++;
else {
red.push_back(message[messageOffset]);
messageOffset++;
}
}
// Green
std::string green;
messageOffset++;
while (message[messageOffset] != ',')
{
green.push_back(message[messageOffset]);
identifier.push_back(message[messageOffset]);
messageOffset++;
counter++;
}
// Blue
std::string blue;
messageOffset++;
while (message[messageOffset] != ')')
{
blue.push_back(message[messageOffset]);
messageOffset++;
}
messageOffset++;
// Convert rgb string to floats
float r = std::stof(red);
float g = std::stof(green);
float b = std::stof(blue);
glm::vec3 color(r, g, b);
return color;
return identifier;
}
// Read File path or GUI Name
std::string SoftwareIntegrationModule::readString(std::vector<char>& message) {
std::string length;
length.push_back(message[messageOffset]);
length.push_back(message[messageOffset + 1]);
messageOffset += 2;
messageOffset++;
length.push_back(message[messageOffset]);
messageOffset++;
int lengthOfString = stoi(length);
std::string name;
@@ -445,19 +430,51 @@ namespace openspace {
return name;
}
bool SoftwareIntegrationModule::isConnected(const Peer& peer) const {
return peer.status != SoftwareConnection::Status::Connecting &&
peer.status != SoftwareConnection::Status::Disconnected;
}
glm::vec3 SoftwareIntegrationModule::readColor(std::vector<char>& message) {
std::string lengthOfColor; // Not used for now, but sent in message
lengthOfColor.push_back(message[messageOffset]);
messageOffset++;
lengthOfColor.push_back(message[messageOffset]);
messageOffset++;
void SoftwareIntegrationModule::disconnect(Peer& peer) {
if (isConnected(peer)) {
_nConnections = nConnections() - 1;
// Color is sent in format (redValue, greenValue, blueValue)
// Therefor, we have to iterate through the message and ignore characters
// "( , )" and separate the values in the string
std::string red;
while (message[messageOffset] != ',')
{
if (message[messageOffset] == '(')
messageOffset++;
else {
red.push_back(message[messageOffset]);
messageOffset++;
}
}
peer.connection.disconnect();
peer.thread.join();
_peers.erase(peer.id);
std::string green;
messageOffset++;
while (message[messageOffset] != ',')
{
green.push_back(message[messageOffset]);
messageOffset++;
}
std::string blue;
messageOffset++;
while (message[messageOffset] != ')')
{
blue.push_back(message[messageOffset]);
messageOffset++;
}
messageOffset++;
// Convert red, green, blue strings to floats
float r = std::stof(red);
float g = std::stof(green);
float b = std::stof(blue);
glm::vec3 color(r, g, b);
return color;
}
size_t SoftwareIntegrationModule::nConnections() const {
@@ -470,13 +487,5 @@ namespace openspace {
};
}
scripting::LuaLibrary SoftwareIntegrationModule::luaLibrary() const {
scripting::LuaLibrary res;
res.name = "softwareintegration";
res.scripts = {
absPath("${MODULE_SOFTWAREINTEGRATION}/scripts/network.lua")
};
return res;
}
} // namespace openspace
@@ -27,14 +27,10 @@
#include <modules/softwareintegration/network/softwareconnection.h>
#include <openspace/util/openspacemodule.h>
#include <openspace/documentation/documentation.h>
#include <openspace/util/concurrentqueue.h>
#include <ghoul/glm.h>
#include <openspace/util/openspacemodule.h>
#include <ghoul/io/socket/tcpsocketserver.h>
#include <atomic>
#include <string>
#include <unordered_map>
namespace openspace {
@@ -49,10 +45,9 @@ public:
void stop();
size_t nConnections() const;
size_t messageOffset = 0;
size_t messageOffset = 0; // Byt namn till två size begin & end
std::vector<documentation::Documentation> documentations() const override;
scripting::LuaLibrary luaLibrary() const override;
private:
struct Peer {
@@ -68,31 +63,37 @@ private:
SoftwareConnection::Message message;
};
void internalInitialize(const ghoul::Dictionary&) override;
void internalDeinitializeGL() override;
bool isConnected(const Peer& peer) const;
void disconnect(Peer& peer);
void handleNewPeers();
void eventLoop();
std::shared_ptr<Peer> peer(size_t id);
void handlePeer(size_t id);
void handlePeerMessage(PeerMessage peerMessage);
void handleProperties(std::string identifier, const std::shared_ptr<Peer>& peer);
float readFloatValue(std::vector<char>& message);
std::string readIdentifier(std::vector<char>& message);
std::string readString(std::vector<char>& message);
glm::vec3 readColor(std::vector<char>& message);
std::unordered_map<size_t, std::shared_ptr<Peer>> _peers;
mutable std::mutex _peerListMutex;
std::thread _serverThread;
std::thread _eventLoopThread;
ghoul::io::TcpSocketServer _socketServer;
size_t _nextConnectionId = 1;
std::atomic_bool _shouldStop = false;
std::atomic_size_t _nConnections = 0;
ConcurrentQueue<PeerMessage> _incomingMessages;
std::string readIdentifier(std::vector<char>& message);
float readFloatValue(std::vector<char>& message);
glm::vec3 readColor(std::vector<char>& message);
std::string readString(std::vector<char>& message);
void internalInitialize(const ghoul::Dictionary&) override;
void internalDeinitializeGL() override;
};
} // namespace openspace
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -108,8 +108,8 @@ std::string_view Time::ISO8601() const {
std::memset(b, 0, S);
SpiceManager::ref().dateFromEphemerisTime(_time, b, S, Format);
return std::string_view(b, S);
return std::string_view(b, S-1);
}
void Time::ISO8601(char* buffer) const {