Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+79
View File
@@ -0,0 +1,79 @@
cmake_minimum_required(VERSION 3.16)
project(simulator VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Qml Location Network)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Qml Location Network)
set(PROJECT_SOURCES
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(simulator
MANUAL_FINALIZATION
${PROJECT_SOURCES}
main.qrc
markerhelper.h markerhelper.cpp
replayhelper.h replayhelper.cpp
bookmarkhelper.h bookmarkhelper.cpp
)
# Define target properties for Android with Qt 6 as:
# set_property(TARGET simulator APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()
if(ANDROID)
add_library(simulator SHARED
${PROJECT_SOURCES}
)
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else()
add_executable(simulator
${PROJECT_SOURCES}
)
endif()
endif()
target_link_libraries(simulator PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Qml Qt${QT_VERSION_MAJOR}::Location Qt${QT_VERSION_MAJOR}::Network
)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
if(${QT_VERSION} VERSION_LESS 6.1.0)
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.simulator)
endif()
set_target_properties(simulator PROPERTIES
${BUNDLE_ID_OPTION}
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
include(GNUInstallDirs)
install(TARGETS simulator
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(simulator)
endif()
+19
View File
@@ -0,0 +1,19 @@
import QtQuick 2.0
import markerHelper 1.0
import replayHelper 1.0
import bookmarkHelper 1.0
Item {
MarkerHelper {
id: markerHelper
}
ReplayHelper {
id: replayHelper
}
BookmarkHelper {
id: bookmarkHelper
}
property BookmarkHelper bookmarkHelper : bookmarkHelper
property ReplayHelper replayHelper : replayHelper
property MarkerHelper markerHelper : markerHelper
}
+180
View File
@@ -0,0 +1,180 @@
import QtQuick
import QtPositioning
import QtLocation
import QtQuick.Controls
Rectangle {
id: mapContainer
width: parent.width * 3 / 4
height: parent.height
property real bookmarkTimestamp: 0
function statusGen() {
var random = Math.random();
var status;
if (random < 0.01) {
status = 'damaged';
} else if (random < 0.10) {
status = 'destroyed';
} else {
status = 'fully_capable';
}
return status
}
function partieGen() {
var random = Math.random();
var status;
if (random < 0.33) {
status = 'Red';
} else {
status = 'Blue';
}
return status
}
function createMarker() {
var centerLat = 53.5200;
var centerLng = 9.4050;
var latRange = 0.1; // Beschränke auf ±0.1 Grad um centerLat
var lngRange = 0.1; // Beschränke auf ±0.1 Grad um centerLng
for (var i = 1; i <= 200; i++) {
var lat = centerLat + (Math.random() * latRange * 2 - latRange);
var lng = centerLng + (Math.random() * lngRange * 2 - lngRange);
var component = Qt.createComponent("marker.qml");
var sprite = component.createObject(map, {
"lat": lat,
"lng": lng
});
logic.markerHelper.postObject(replay_uuid, i, lng, lat, statusGen(), partieGen());
markers.push(sprite);
}
return markers;
}
Timer {
id: moveTimer
interval: 1000 // Move every second
repeat: true
onTriggered: {
for (var i = 0 ; i < markers.length; i++) {
var newLat = markers[i].lat + (Math.random() * 0.01 - 0.005)
var newLng = markers[i].lng + (Math.random() * 0.01 - 0.005)
markers[i].lat = newLat
markers[i].lng = newLng
logic.markerHelper.postObject(replay_uuid, i+1, newLng, newLat, statusGen(), partieGen())
}
}
}
Plugin {
id: mapPlugin
name: "osm"
PluginParameter {
name: "osm.mapping.custom.host"
value: "https://tile.openstreetmap.de/"
}
}
Map {
id: map
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(53.5200, 9.4050) // Berlin
zoomLevel: 14
z: 1
property geoCoordinate startCentroid
property var markers: []
PinchHandler {
id: pinch
target: null
onActiveChanged: if (active) {
map.startCentroid = map.toCoordinate(
pinch.centroid.position, false)
}
onScaleChanged: delta => {
map.zoomLevel += Math.log2(delta)
map.alignCoordinateToPoint(
map.startCentroid, pinch.centroid.position)
}
onRotationChanged: {} // Deaktiviert Rotation
grabPermissions: PointerHandler.TakeOverForbidden
}
DragHandler {
id: drag
target: map
onTranslationChanged: delta => map.pan(-delta.x, -delta.y)
}
activeMapType: supportedMapTypes[supportedMapTypes.length - 1]
Button {
text: "Start Simulation"
width: parent.width
z: 10
onClicked: {
var sprites = createMarker()
for (var i = 0; i < sprites.length; i++) {
map.addMapItem(sprites[i])
}
moveTimer.start()
}
}
Button {
text: "Add Lesezeichen"
width: parent.width
z:10
y:25
onClicked: {
bookmarkTimestamp = Date.now();
bookmarkDialog.open();
}
}
}
Dialog {
id: bookmarkDialog
title: "Add Lesezeichen"
modal: true
standardButtons: Dialog.Ok | Dialog.Cancel
Column {
spacing: 10
padding: 20
TextField {
id: nameField
placeholderText: "Name"
}
TextArea {
id: descriptionField
placeholderText: "Description"
}
}
onAccepted: {
var name = nameField.text;
var description = descriptionField.text;
logic.bookmarkHelper.postBookmark(replay_uuid, name, description, bookmarkTimestamp)
}
}
}
+102
View File
@@ -0,0 +1,102 @@
import QtQuick
import QtQuick.Controls
Rectangle {
id: replaySidebar
width: parent.width * 1 / 4
height: parent.height
Column {
anchors.fill: parent
spacing: 10
padding: 10
Button {
text: "Add Replay"
onClicked: {
addItemDialog.open()
}
width: parent.width - 20
}
ListView {
id: listView
width: parent.width - 20
height: parent.height
model: itemList
delegate: Item {
width: listView.width
height: 40
Rectangle {
id: background
color: model.selected ? "lightblue" : "white" // Change color if selected
anchors.fill: parent
border.color: "gray"
MouseArea {
anchors.fill: parent
onClicked: {
// Deselect all items first
for (var i = 0; i < itemList.count; i++) {
itemList.setProperty(i, "selected",
false) // Deselect
}
// Select the clicked item
model.selected = true // Select this item
console.log(model.uuid)
replay_uuid = model.uuid // Assuming replay_uuid is declared elsewhere
for (var j = 0; j < markers.length; j++) {
markers[j].visible = false // Unsichtbar machen
markers[j].parent = null // Parent entfernen
markers[j].destroy() // Objekt zerstören
}
markers = [] // Leere das Marker-Array
}
}
}
Button {
text: "Delete"
width: 80
padding: 10
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
background: Rectangle {
color: "red"
}
onClicked: {
logic.replayHelper.deleteReplay(model.uuid)
}
}
Text {
text: model.name
color: "black"
anchors.centerIn: parent
}
}
}
}
Component.onCompleted: {
logic.replayHelper.fetchReplays()
}
Connections {
target: logic.replayHelper
function onReplaysFetched(replays) {
itemList.clear()
for (var i = 0; i < replays.length; i++) {
itemList.append({
"name": replays[i].name,
"uuid": replays[i].uuid,
"time_created": replays[i].time_created,
"selected": false
})
}
}
}
}
+46
View File
@@ -0,0 +1,46 @@
#include "bookmarkhelper.h"
#include <QDebug>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <qeventloop.h>
#include <qqmlengine.h>
#include <QNetworkReply>
BookmarkHelper::BookmarkHelper() {}
void BookmarkHelper::postBookmark(QString uuid, QString name, QString description, qint64 timestamp) {
QNetworkRequest request;
request.setUrl(QUrl("http://localhost:8080/bookmark"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
// SSL-Konfiguration ohne Überprüfung des Zertifikats
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(sslConfig);
QJsonObject obj;
obj["uuid"] = uuid;
obj["name"] = name;
obj["description"] = description;
obj["timestamp"] = timestamp;
QJsonDocument jsonDoc(obj);
QByteArray jsonData = jsonDoc.toJson();
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkReply *reply = manager->post(request, jsonData);
connect(reply, &QNetworkReply::finished, [reply, this] {
if (reply->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
} else {
qDebug() << "Error sending Replay:" << reply->errorString();
}
reply->deleteLater();
});
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef BOOKMARKHELPER_H
#define BOOKMARKHELPER_H
#include <qnetworkaccessmanager.h>
#include <qobject.h>
class BookmarkHelper : public QObject
{
Q_OBJECT
public:
BookmarkHelper();
Q_INVOKABLE void postBookmark(QString uuid, QString name, QString description, qint64 timestamp);
private:
QNetworkAccessManager *m_manager;
};
#endif // BOOKMARKHELPER_H
+26
View File
@@ -0,0 +1,26 @@
#include "bookmarkhelper.h"
#include "markerhelper.h"
#include "replayhelper.h"
#include <QQmlApplicationEngine>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qmlRegisterType<MarkerHelper>("markerHelper", 1, 0, "MarkerHelper");
qmlRegisterType<ReplayHelper>("replayHelper", 1, 0, "ReplayHelper");
qmlRegisterType<BookmarkHelper>("bookmarkHelper", 1,0, "BookmarkHelper");
QQmlApplicationEngine engine;
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &a, [] () { QCoreApplication::exit(-1); }, Qt::QueuedConnection);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if(engine.rootObjects().isEmpty()) {
return -1;
}
return a.exec();
}
+72
View File
@@ -0,0 +1,72 @@
import QtQuick
import QtQuick.Controls
Window {
id: window
visible: true
width: 1920
height: 1080
title: "RME-Simulator"
property string replay_uuid: ""
property var markers: []
Logic {
id: logic
}
ListModel {
id: itemList
}
Rectangle {
id: main
width: parent.width
height: parent.height
visible: true
Dialog {
id: addItemDialog
title: "Add New Replay"
modal: true
standardButtons: Dialog.Ok | Dialog.Cancel
Column {
spacing: 10
padding: 10
Label {
text: "Enter Replay Name:"
}
TextField {
id: replayNameField
width: 200
placeholderText: "Replay Name"
}
}
onAccepted: {
if(replayNameField.text !== "") {
itemList.append({"name": replayNameField.text})
logic.replayHelper.createReplay(replayNameField.text);
replayNameField.text = ""
}
}
Connections {
target: logic.replayHelper
function onReplayCreated() {
logic.replayHelper.fetchReplays(); // Fetch the updated list of replays
}
}
}
SideBar_Component {
id: sidebar
anchors.left: parent.left
}
Map_Component {
id: map
anchors.right: parent.right
}
}
}
+10
View File
@@ -0,0 +1,10 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>mss-symbol.png</file>
<file>marker.qml</file>
<file>Logic.qml</file>
<file>Map_Component.qml</file>
<file>SideBar_Component.qml</file>
</qresource>
</RCC>
+14
View File
@@ -0,0 +1,14 @@
#include "mainwindow.h"
#include "./ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
+31
View File
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
+22
View File
@@ -0,0 +1,22 @@
import QtQuick 2.0
import QtPositioning 5.12
import QtLocation 5.12
MapQuickItem{
property double lat: 0
property double lng: 0
id: mapMarker
anchorPoint.x: image.width/2
anchorPoint.y: image.height/2
sourceItem: Image {
id: image
source: "mss-symbol.png"
width: 250 / 4
height: 150 / 4
}
coordinate: QtPositioning.coordinate(lat,lng)
onLatChanged: coordinate.latitude = lat
onLngChanged: coordinate.longitude = lng
}
+72
View File
@@ -0,0 +1,72 @@
#include "markerhelper.h"
#include <QDebug>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <qeventloop.h>
#include <qqmlengine.h>
#include <QNetworkReply>
MarkerHelper::MarkerHelper() {
m_manager = new QNetworkAccessManager(this);
}
void MarkerHelper::startSimulation(QString replayId) {
}
void MarkerHelper::postObject(QString replayId,int id, double lat, double lng, QString status, QString partie) {
// Erstelle das GeoJSON-Objekt
QString sidic;
if(status == "damaged") {
sidic = "10061000001212000000"; // SIDIC CODE FOR SMYBOL ( DAMAGED )
} else if (status == "destroyed") {
sidic = "10031500001202000000"; // SIDIC CODE FOR SMYBOL ( DESTROYED )
} else if (status == "fully_capable") {
sidic = "30031020000000000000"; // SIDIC CODE FOR SYMBOL ( FULLY_CAPALE )
}
QJsonObject geoJson;
geoJson.insert("type", "Feature");
QJsonObject geometry;
geometry.insert("type", "Point");
QJsonArray coordinates;
coordinates.append(lng);
coordinates.append(lat);
geometry.insert("coordinates", coordinates);
QJsonObject properties;
properties.insert("id", id);
properties.insert("timestamp", QDateTime::currentMSecsSinceEpoch());
properties.insert("replay_id", replayId);
properties.insert("parties", partie);
properties.insert("sidic", sidic);
geoJson.insert("properties", properties);
geoJson.insert("geometry", geometry);
QJsonDocument jsonDoc(geoJson);
QByteArray jsonData = jsonDoc.toJson();
QNetworkRequest request;
request.setUrl(QUrl("http://localhost:8080/objects"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(sslConfig);
QNetworkReply *reply = m_manager->post(request, jsonData);
connect(reply, &QNetworkReply::finished, [reply] {
if (reply->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
// Verarbeite die Antwort
} else {
qDebug() << "Error sending GeoJSON:" << reply->errorString();
}
reply->deleteLater();
});
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef MARKERHELPER_H
#define MARKERHELPER_H
#include <qnetworkaccessmanager.h>
#include <qobject.h>
class MarkerHelper : public QObject
{
Q_OBJECT
public:
MarkerHelper();
Q_INVOKABLE void postObject(QString replayId, int id, double lat, double lng, QString status, QString partie);
Q_INVOKABLE void startSimulation(QString replayId);
private:
QNetworkAccessManager *m_manager;
};
#endif // MARKERHELPER_H
Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

+104
View File
@@ -0,0 +1,104 @@
#include "replayhelper.h"
#include <qjsonarray.h>
#include <qjsondocument.h>
#include <qjsonobject.h>
#include <qnetworkaccessmanager.h>
#include <qnetworkreply.h>
#include <qnetworkrequest.h>
ReplayHelper::ReplayHelper() {
connect(&m_manager, &QNetworkAccessManager::finished, this, &ReplayHelper::onReplaysFetched);
}
QJsonArray ReplayHelper::replays() {
return m_replays;
}
void ReplayHelper::fetchReplays() {
QUrl url("http://localhost:8080/replays");
QNetworkRequest request(url);
// SSL-Konfiguration ohne Überprüfung des Zertifikats
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(sslConfig);
m_manager.get(request);
}
void ReplayHelper::onReplaysFetched(QNetworkReply * reply) {
if(reply->error() != QNetworkReply::NoError) {
qWarning() << "Fehler beim Abrufen der Replays";
reply->deleteLater();
return;
}
QByteArray responseData = reply->readAll();
QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData);
m_replays = QJsonArray();
for(int i = 0; i < jsonDoc.array().size(); i++) {
m_replays.append(jsonDoc.array()[i]);
}
emit replaysFetched(m_replays);
emit replaysChanged();
}
void ReplayHelper::createReplay(QString name) {
QNetworkRequest request;
request.setUrl(QUrl("http://localhost:8080/replays"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
// SSL-Konfiguration ohne Überprüfung des Zertifikats
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(sslConfig);
QJsonObject obj;
obj["name"] = name;
obj["created_by"] = 1;
QJsonDocument jsonDoc(obj);
QByteArray jsonData = jsonDoc.toJson();
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkReply *reply = manager->post(request, jsonData);
connect(reply, &QNetworkReply::finished, [reply, this] {
if (reply->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
emit replayCreated();
fetchReplays(); // Lädt die aktualisierte Liste erneut
} else {
qDebug() << "Error sending Replay:" << reply->errorString();
}
reply->deleteLater();
});
emit replayCreated();
}
void ReplayHelper::deleteReplay(QString replayId) {
QNetworkRequest request;
request.setUrl(QUrl("http://localhost:8080/replays/delete?replayId=" + replayId));
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(sslConfig);
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkReply *reply = manager->deleteResource(request);
connect(reply, &QNetworkReply::finished, [reply, this] {
if (reply->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
fetchReplays();
} else {
qDebug() << "Error sending Replay:" << reply->errorString();
}
reply->deleteLater();
});
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef REPLAYHELPER_H
#define REPLAYHELPER_H
#include <qjsonarray.h>
#include <qnetworkaccessmanager.h>
#include <qobject.h>
class ReplayHelper : public QObject
{
Q_OBJECT
public:
explicit ReplayHelper();
Q_INVOKABLE QJsonArray replays();
Q_INVOKABLE void fetchReplays();
Q_INVOKABLE void createReplay(QString name);
Q_INVOKABLE void deleteReplay(QString replayId);
signals:
void replaysChanged();
void replaysFetched(const QJsonArray &replays);
void replayCreated();
private slots:
void onReplaysFetched(QNetworkReply * reply);
private:
QNetworkAccessManager m_manager;
QJsonArray m_replays;
};
#endif // REPLAYHELPER_H