Merge remote-tracking branch 'render/main' into master-new-assignement

# Conflicts:
#	.gitignore
#	main.cpp
#	stompframe.cpp
This commit is contained in:
Rémi Heredero 2024-01-21 22:49:12 +01:00
commit d3a049ac37
12 changed files with 605 additions and 1 deletions

3
.gitignore vendored
View File

@ -1 +1,4 @@
*.pro.user
cmake-build-debug
.idea
cmake-build-debug-visual-studio

28
CMakeLists.txt Normal file
View File

@ -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
)

49
Vector2D.cpp Normal file
View File

@ -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);
}

41
Vector2D.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef VECTOR2D_H
#define VECTOR2D_H
#include <cmath>
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

149
app.cpp Normal file
View File

@ -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; i<body.length(); i++) {
const QChar c = body.at(i);
if(c == 'Y') {
myVehicle_ = Vector2D(Vector2D::CreatePoint(x, GRID_SIZE-y));
}
if(c == 'h') {
otherVehicles_.append(Vector2D(Vector2D::CreatePoint(x, GRID_SIZE-y)));
}
if(c == 'g') addGem(x, y, 100);
if(c == 'G') addGem(x, y, 250);
if(c == 'D') addGem(x, y, 500);
if(c == '\n') {
y++;
x = 0;
} else {
x++;
}
}
}
Vector2D App::computeRelativePts(Gem g) {
Vector2D v = g.coordinate-myVehicle_;
v.reverse();
v.normalize(MAX_LENGHT);
return Vector2D(v.lenght()*g.pts, v.angle());
}
void App::computeRelativeDistance(Gem* g) {
int deltaX = abs(g->coordinate.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");
}
}

57
app.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef APP_H
#define APP_H
#include <QObject>
#include "interface/iStompObserver.h"
#include "stomp.h"
#include <QVector2D>
#include <cmath>
#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<Gem> gems_;
Vector2D myVehicle_;
QVector<Vector2D> 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

View File

@ -0,0 +1,24 @@
#ifndef ISTOMPOBSERVER_H
#define ISTOMPOBSERVER_H
#include <QString>
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

36
interface/iStompSubject.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef ISTOMPSUBJECT_H
#define ISTOMPSUBJECT_H
#include "iStompObserver.h"
#include <QString>
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

View File

@ -1,7 +1,16 @@
#include <QApplication>
#include <QSslSocket>
#include <QThread>
#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();
}

157
stomp.cpp Normal file
View File

@ -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();
}
}
}

46
stomp.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef STOMP_H
#define STOMP_H
#include <QObject>
#include "interface/iStompSubject.h"
#include <QSslSocket>
#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

View File

@ -2,21 +2,26 @@
STOMPFrame::STOMPFrame(Command command, std::initializer_list<QPair<QString, QString>> 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);