diff --git a/.gitignore b/.gitignore index 75c107b..5c0a0da 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ *.pro.user +cmake-build-debug +.idea +cmake-build-debug-visual-studio diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..74bd1a6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.22) +project(ProtocolDeveloppement) + +set(CMAKE_CXX_STANDARD 14) + +#set(CMAKE_PREFIX_PATH "/Qt/6.5.0/android_arm64_v8a/lib/cmake") +#set(CMAKE_PREFIX_PATH "D:/programme/Qt/6.5.0/mingw_64/lib/cmake") + + +find_package(Qt6Widgets REQUIRED) +find_package(Qt6Network REQUIRED) +find_package(Qt6Gui REQUIRED) + +add_executable(${PROJECT_NAME} + main.cpp + stompframe.cpp + stomp.cpp + app.cpp + Vector2D.cpp +) + +link_directories( ${PCL_LIBRARY_DIRS} ) + +target_link_libraries(${PROJECT_NAME} + Qt6::Network + Qt6::Gui + Qt6::Widgets +) diff --git a/Vector2D.cpp b/Vector2D.cpp new file mode 100644 index 0000000..b2889e8 --- /dev/null +++ b/Vector2D.cpp @@ -0,0 +1,49 @@ +#include "Vector2D.h" + +Vector2D::Vector2D(Point point) { + point_.x = point.x; + point_.y = point.y; + lenght_ = sqrt(pow(point.x, 2) + pow(point.y, 2)); + angle_ = atan2(point.y, point.x); +} + +Vector2D::Vector2D(double lenght, double angle) { + lenght_ = lenght; + angle_ = angle; + point_.x = lenght * cos(angle); + point_.y = lenght * sin(angle); +} + +Vector2D::Point Vector2D::CreatePoint(double x, double y) { + Point p; + p.x = x; + p.y = y; + return p; +} + +void Vector2D::normalize(double max) { + lenght_ = (1/lenght_); + point_.x = lenght_ * cos(angle_); + point_.y = lenght_ * sin(angle_); +} + +Vector2D Vector2D::reverse() { + Point p; + p.x = -point_.x; + p.y = -point_.y; + return Vector2D(p); +} + +Vector2D Vector2D::operator +(Vector2D v) const { + Point p; + p.x = point_.x + v.x(); + p.y = point_.y + v.y(); + return Vector2D(p); +} + +Vector2D Vector2D::operator -(Vector2D v) const { + Point p; + p.x = point_.x - v.x(); + p.y = point_.y - v.y(); + return Vector2D(p); +} \ No newline at end of file diff --git a/Vector2D.h b/Vector2D.h new file mode 100644 index 0000000..2997e03 --- /dev/null +++ b/Vector2D.h @@ -0,0 +1,41 @@ +#ifndef VECTOR2D_H +#define VECTOR2D_H + +#include + +class Vector2D { + +public: + typedef struct { + double x; + double y; + } Point; + Vector2D() = default; + Vector2D(Point point); + Vector2D(double lenght, double angle); + ~Vector2D() = default; + + static Point CreatePoint(double x, double y); + + double x() {return point_.x;} + double y() {return point_.y;} + Point point() {return point_;} + double lenght() {return lenght_;} + double angle() {return angle_;} + + void normalize(double max); + Vector2D reverse(); + + Vector2D operator +(Vector2D v) const; + Vector2D operator -(Vector2D v) const; + +private: + Point point_; + double lenght_; + double angle_; + +}; + + + +#endif //VECTOR2D_H diff --git a/app.cpp b/app.cpp new file mode 100644 index 0000000..6c7bea6 --- /dev/null +++ b/app.cpp @@ -0,0 +1,149 @@ +#include "app.h" + + +App::App(Stomp* st) { + st_ = st; + st_->connectRequest("sdi.hevs.ch", 61614, "/", "sdi10", "809c02f36becb0868da98761fe3209f6"); + st_->subscribeRequest("/topic/sdi10.gem.field", 1); + +} + +void App::connectConfirmation(bool success, QString version) { + +} + +void App::sendConfirmation(bool success) { + +} + +void App::subscribeConfirmation(bool success) { +} + +void App::receiveIndication(int id, QString destination, QString body) { + //qDebug() << "Indication " << id << " : " << destination << Qt::endl << body << Qt::endl; + if(destination.contains("field")){ + fillField(body); + } + computeMove(); +} + +void App::disconnectConfirmation() { + +} + +void App::disconnectIndication() { + +} + +void App::addGem(int x, int y, int pts) { + Gem g; + g.coordinate = Vector2D(Vector2D::CreatePoint(x, GRID_SIZE-y)); + g.pts = pts; + gems_.append(g); +} + +void App::fillField(QString body) { + int x = 0; + int y = 0; + gems_.clear(); + for(int i = 0; icoordinate.x() - myVehicle_.x()); + int deltaY = abs(g->coordinate.y() - myVehicle_.y()); + g->relativeDistanceToMe = deltaX+deltaY; + g->relativeDistanceToOtherPlayer = MAX_LENGHT*2; + for(Vector2D v : otherVehicles_) { + deltaX = abs(g->coordinate.x() - v.x()); + deltaY = abs(g->coordinate.y() - v.y()); + if(deltaX+deltaY < g->relativeDistanceToOtherPlayer) { + g->relativeDistanceToOtherPlayer = deltaX+deltaY; + } + } +} + +void App::computeMove() { + static const double PI = 3.14159265358979323846; + Vector2D myRelativePts; + for(Gem g : gems_) { + computeRelativeDistance(&g); + Vector2D v = computeRelativePts(g); + myRelativePts = myRelativePts+v; + if(g.relativeDistanceToMe <= g.relativeDistanceToOtherPlayer) { + myRelativePts = myRelativePts+v; + } + } + double angle = myRelativePts.angle(); + + if(angle <0) angle = angle+2*PI; + angle *= 180/PI; + + qDebug() << "Angle: " << angle << "°"; + qDebug() << "Length: " << myRelativePts.lenght() << Qt::endl; + + if(angle > 360) { + qDebug() << "Error angle: " << angle << Qt::endl; + } + else if(angle <= -360) { + qDebug() << "Error angle: " << angle << Qt::endl; + } + + else if(angle > 315) { // angle > 315° + st_->sendRequest("/topic/sdi10.gem.command", "right"); + } + else if(angle <= -315) { // angle <= -315° || angle <= 45° + st_->sendRequest("/topic/sdi10.gem.command", "right"); + } + + else if(angle > 225) { // angle > 225° + st_->sendRequest("/topic/sdi10.gem.command", "down"); + } + else if(angle <= -225) { // angle <= -225° || angle <= 135° + st_->sendRequest("/topic/sdi10.gem.command", "up"); + } + + else if(angle > 135) { // angle > 135° + st_->sendRequest("/topic/sdi10.gem.command", "left"); + } + else if(angle <= -135) { // angle <= -135° || angle <= 225° + st_->sendRequest("/topic/sdi10.gem.command", "left"); + } + + else if(angle > 45) { // angle > 45° + st_->sendRequest("/topic/sdi10.gem.command", "up"); + } + else if(angle <= -45) { // angle <= -45° || angle <= 315° + st_->sendRequest("/topic/sdi10.gem.command", "down"); + } + + else { + st_->sendRequest("/topic/sdi10.gem.command", "right"); + } +} + diff --git a/app.h b/app.h new file mode 100644 index 0000000..52e558d --- /dev/null +++ b/app.h @@ -0,0 +1,57 @@ +#ifndef APP_H +#define APP_H + +#include +#include "interface/iStompObserver.h" +#include "stomp.h" +#include +#include + +#include "Vector2D.h" + +#define GRID_SIZE 32 + + +class App : public QObject, public interface::iStompObserver { +public: + App(Stomp* st); + ~App() = default; + + const double MAX_LENGHT = sqrt(GRID_SIZE*GRID_SIZE + GRID_SIZE*GRID_SIZE); + // iStompObserver interface +private: + void connectConfirmation(bool success, QString version); + void sendConfirmation(bool success); + void subscribeConfirmation(bool success); + void receiveIndication(int id, QString destination, QString body); + void disconnectConfirmation(); + void disconnectIndication(); + +protected: + Stomp* st_; + + typedef struct { + Vector2D coordinate; + int relativeDistanceToMe; + int relativeDistanceToOtherPlayer; + int pts; + } Gem; + + typedef struct { + int x; + int y; + bool me; + } Vehicle; + + QVector gems_; + Vector2D myVehicle_; + QVector otherVehicles_; + void addGem(int x, int y, int pts); + void fillField(QString body); + Vector2D computeRelativePts(Gem g); + void computeRelativeDistance(Gem* g); + void computeMove(); + +}; + +#endif // APP_H diff --git a/interface/iStompObserver.h b/interface/iStompObserver.h new file mode 100644 index 0000000..28185a6 --- /dev/null +++ b/interface/iStompObserver.h @@ -0,0 +1,24 @@ +#ifndef ISTOMPOBSERVER_H +#define ISTOMPOBSERVER_H + +#include + +namespace interface { +class iStompObserver { + +public: + virtual ~iStompObserver() {} + +protected: + iStompObserver() {} + +public: + virtual void connectConfirmation(bool success, QString version) = 0; + virtual void sendConfirmation(bool success) = 0; + virtual void subscribeConfirmation(bool success) = 0; + virtual void receiveIndication(int id, QString destination, QString body) = 0; + virtual void disconnectConfirmation() = 0; + virtual void disconnectIndication() = 0; +}; +} +#endif // ISTOMPOBSERVER_H diff --git a/interface/iStompSubject.h b/interface/iStompSubject.h new file mode 100644 index 0000000..1924fd6 --- /dev/null +++ b/interface/iStompSubject.h @@ -0,0 +1,36 @@ +#ifndef ISTOMPSUBJECT_H +#define ISTOMPSUBJECT_H + +#include "iStompObserver.h" +#include + +namespace interface { +class iStompSubject { + +public: + virtual ~iStompSubject() {} + +protected: + iStompSubject() {} + +public: + virtual bool subscribe(iStompObserver* obs) = 0; + virtual void unsubscribe(iStompObserver* obs) = 0; + + virtual int connectRequest(QString host, int port, QString vhost, QString username, QString password) = 0; + virtual void sendRequest(QString destination, const QByteArray& body) = 0; + virtual void subscribeRequest(QString destination, int id) = 0; + virtual void disconnectRequest() = 0; + +protected: + virtual void notifyConnectConfirmation(bool success, QString version) = 0; + virtual void notifySendConfirmation(bool success) = 0; + virtual void notifySubscribeConfirmation(bool success) = 0; + virtual void notifyReceiveIndication(int id, QString destination, QString body) = 0; + virtual void notifyDisconnectConfirmation() = 0; + virtual void notifyDisconnectIndication() = 0; + +}; +} // namespace + +#endif // ISTOMPSUBJECT_H diff --git a/main.cpp b/main.cpp index bf2b52a..8439daf 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,16 @@ #include +#include +#include + +#include "stomp.h" +#include "app.h" int main(int argc, char *argv[]) { QApplication application(argc, argv); - + + Stomp st; + App app(&st); + st.subscribe(&app); + return application.exec(); } diff --git a/stomp.cpp b/stomp.cpp new file mode 100644 index 0000000..38a4616 --- /dev/null +++ b/stomp.cpp @@ -0,0 +1,157 @@ +#include "stomp.h" + +Stomp::Stomp() { + for(int i = 0; i< MAX_OBSERVER; i++) { + observer_[i] = nullptr; + } + socket_.setPeerVerifyMode(QSslSocket::VerifyNone); + QObject::connect(&socket_, &QSslSocket::readyRead, [&] { + STOMPFrame frame = STOMPFrame::receive(socket_); + + switch(frame.command()) { + case STOMPFrame::CONNECTED: + qDebug() << "Connected !" << Qt::endl + << "Version:" << frame.headers().value("version"); + notifyConnectConfirmation(true,frame.headers().value("version")); + break; + + case STOMPFrame::MESSAGE: + notifyReceiveIndication(1, frame.headers().value("destination"), frame.body()); + //qDebug() << "Message" << Qt::endl; + break; + + case STOMPFrame::RECEIPT: + notifySendConfirmation(true); + qDebug() << "Succesfully send" << Qt::endl; + break; + + case STOMPFrame::ERROR: + notifyConnectConfirmation(false,frame.headers().value("version")); + notifySendConfirmation(false); + qDebug() << Qt::endl + << "-----ERROR-----" << Qt::endl + << "Command: " << frame.command() << Qt::endl + << "Header: " << frame.headers() << Qt::endl + << "Body: " << frame.body() << Qt::endl + << Qt::endl; + break; + + default: + qDebug() << Qt::endl + << "-----Other STOMP frame-----" << Qt::endl + << "Command: " << frame.command() << Qt::endl + << "Header: " << frame.headers() << Qt::endl + << "Body: " << frame.body() << Qt::endl + << Qt::endl; + break; + + } + }); +} + +Stomp::~Stomp() { + +} + + +bool Stomp::subscribe(interface::iStompObserver* obs) { + for(int i = 0; i < MAX_OBSERVER; i++) { + if (observer_[i] == nullptr) { + observer_[i] = obs; + return true; + } + } + return false; +} + +void Stomp::unsubscribe(interface::iStompObserver* obs) { + for(int i = 0; i < MAX_OBSERVER; i++) { + if(observer_[i] == obs) { + observer_[i] = nullptr; + } + } +} + +int Stomp::connectRequest(QString host, int port, QString vhost, QString username, QString password) { + + socket_.connectToHostEncrypted(host, port); + if(!socket_.waitForConnected()) return -1; + + STOMPFrame(STOMPFrame::STOMP, { + {"accept-version", "1.2"}, + {"host", vhost}, + {"login", username}, + {"passcode", password} + }).send(socket_); + + return 0; + +} + +void Stomp::sendRequest(QString destination, const QByteArray& body) { + + STOMPFrame(STOMPFrame::SEND, { + {"destination", destination}, + }, body).send(socket_); +} + +void Stomp::subscribeRequest(QString destination, int id) { + QString sid = QString::number(id); + STOMPFrame(STOMPFrame::SUBSCRIBE, { + {"destination", destination}, + {"id", sid} + }).send(socket_); +} + +void Stomp::disconnectRequest() { + +} + +void Stomp::notifyConnectConfirmation(bool success, QString version) { + for(int i = 0; i < MAX_OBSERVER; i++) { + if (observer_[i] != nullptr){ + observer_[i]->connectConfirmation(success, version); + } + } +} + +void Stomp::notifySendConfirmation(bool success) { + for(int i = 0; i < MAX_OBSERVER; i++) { + if (observer_[i] != nullptr){ + observer_[i]->sendConfirmation(success); + } + } +} + +void Stomp::notifySubscribeConfirmation(bool success) { + for(int i = 0; i < MAX_OBSERVER; i++) { + if (observer_[i] != nullptr){ + observer_[i]->subscribeConfirmation(success); + } + } +} + +void Stomp::notifyReceiveIndication(int id, QString destination, QString body) { + for(int i = 0; i < MAX_OBSERVER; i++) { + if (observer_[i] != nullptr){ + observer_[i]->receiveIndication(id, destination, body); + } + } +} + +void Stomp::notifyDisconnectConfirmation() { + for(int i = 0; i < MAX_OBSERVER; i++) { + if (observer_[i] != nullptr){ + observer_[i]->disconnectConfirmation(); + } + } +} + +void Stomp::notifyDisconnectIndication() { + for(int i = 0; i < MAX_OBSERVER; i++) { + if (observer_[i] != nullptr){ + observer_[i]->disconnectIndication(); + } + } +} + diff --git a/stomp.h b/stomp.h new file mode 100644 index 0000000..201ab7d --- /dev/null +++ b/stomp.h @@ -0,0 +1,46 @@ +#ifndef STOMP_H +#define STOMP_H + +#include +#include "interface/iStompSubject.h" +#include +#include "stompframe.h" + +#define MAX_OBSERVER 5 + +class Stomp : public QObject, public interface::iStompSubject{ +public: + Stomp(); + ~Stomp(); + + + // iStompSubject interface +public: + bool subscribe(interface::iStompObserver* obs); + void unsubscribe(interface::iStompObserver* obs); + int connectRequest(QString host, int port, QString vhost, QString username, QString password); + void sendRequest(QString destination, const QByteArray& body); + void subscribeRequest(QString destination, int id); + void disconnectRequest(); + +protected: + void notifyConnectConfirmation(bool success, QString version); + void notifySendConfirmation(bool success); + void notifySubscribeConfirmation(bool success); + void notifyReceiveIndication(int id, QString destination, QString body); + void notifyDisconnectConfirmation(); + void notifyDisconnectIndication(); + +protected: + interface::iStompObserver* observer_[MAX_OBSERVER]; + +private: + QSslSocket socket_; + QString host_ = "sdi.hevs.ch"; + QString vHost_ = "/"; + int port_ = 61614; + QString user_ = "sdi10"; + QString password_ = "809c02f36becb0868da98761fe3209f6"; +}; + +#endif // STOMP_H diff --git a/stompframe.cpp b/stompframe.cpp index 0b40080..9e8b8d0 100644 --- a/stompframe.cpp +++ b/stompframe.cpp @@ -2,21 +2,26 @@ STOMPFrame::STOMPFrame(Command command, std::initializer_list> headers, const QByteArray& body): command_(command), body_(body) { + for (const auto& header: headers) { headers_[header.first] = header.second; } } qint64 STOMPFrame::send(QIODevice& device) { + QByteArray encoded; QTextStream out {&encoded}; out << command_ << "\n"; + for (const auto& key: headers_.keys()) { out << key << ":" << headers_[key] << "\n"; } + if (!headers_.contains("content-length")) { out << "content-length" << ":" << body_.size() << "\n"; } + out << "\n" << body_ << '\0'; out.flush(); return device.write(encoded);