Continues migration with DDS, Common

This commit is contained in:
torsten committed 2026-07-17 12:41:42 +02:00
1 parent 9b15cee841
commit fa48db111e
668 files changed
+111841 -2

No files matched your search

+68
View File
@@ -0,0 +1,68 @@
#
# $Id$
# $HeadURL$
# $Author$
#
SET(SRCS_hdr_only
${CMAKE_CURRENT_SOURCE_DIR}/data_modification_enum.h
${CMAKE_CURRENT_SOURCE_DIR}/dds_bitarray.h
${CMAKE_CURRENT_SOURCE_DIR}/dds_vector.h
${CMAKE_CURRENT_SOURCE_DIR}/connection.h
${CMAKE_CURRENT_SOURCE_DIR}/json_object.h
${CMAKE_CURRENT_SOURCE_DIR}/outdated_position.h
${CMAKE_CURRENT_SOURCE_DIR}/qbytearray_byteaccess.h
${CMAKE_CURRENT_SOURCE_DIR}/qpoint3d.h
${CMAKE_CURRENT_SOURCE_DIR}/await.h
)
ADD_LIBRARY(LtsUtilsCoreHeaderOnly INTERFACE)
TARGET_INCLUDE_DIRECTORIES(LtsUtilsCoreHeaderOnly
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
TARGET_SOURCES(LtsUtilsCoreHeaderOnly INTERFACE ${SRCS_hdr_only})
SET(SRCS
pgarray.cpp
qplane3d.cpp
qpoint3d.cpp
scoped_connection.cpp
sfm_bytemessage_converter.cpp
promise.cpp
lts_translatable_identifier.cpp
lts_portrange.cpp
#variant_operators.h
)
NGL_ADD_LIBRARY2(ALL LtsUtilsCore SHARED ${SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(LtsUtilsCore
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(LtsUtilsCore
PUBLIC
Qt5::Core
LtsUtilsCoreHeaderOnly
)
#
# --- Tests --------------------------------------------------------------
#
# IF (TARGET ddscore) // does not work, not yet included
IF((BUILD_WS OR BUILD_SV) AND BUILD_TESTING)
ADD_EXECUTABLE(utils_test
UnitTests/utils_test.cpp
UnitTests/utils_test.h
promise_examples.h
promise_examples.cpp
)
TARGET_LINK_LIBRARIES(utils_test
LtsUtilsCore
Qt5::Core
Qt5::Test
ddscore
)
ADD_TEST(NAME utils_test COMMAND $<TARGET_FILE:utils_test>)
ENDIF()
File diff suppressed because it is too large. Load diff
+62
View File
@@ -0,0 +1,62 @@
#pragma once
#include <QObject>
class LtsUtilsTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void test_toIntArray();
void test_fromIntArray();
void test_toBigintArray();
void test_fromBigintArray();
void test_toIntArray2D();
void test_fromIntArray2D();
void test_toBigintArray2D();
void test_fromBigintArray2D();
void test_QPoint3D();
void test_bitArray();
void test_convert();
void test_connection();
void test_queuedConnection();
void test_signalSignalConnection();
void test_danglingConnection1();
void test_danglingConnection2();
void test_danglingConnection3();
void test_jsonObject_fromJson();
void test_jsonObject_contains();
void test_jsonObject_value();
void test_jsonObject_valueWithError();
void test_jsonObject_valueOr();
void test_jsonObject_integers();
void test_jsonObject_nullValues();
void test_jsonArray_fromJson();
void test_jsonArray();
void test_jsonArray_nullArray();
void test_byteStreamFromSfmMessage();
void test_byteStreamFromSfmMessage2();
void test_byteStreamToSfmMessage();
void test_promise();
void test_promise_example1();
void test_promise_example2();
void test_promise_example3();
void byteAccess();
};
+116
View File
@@ -0,0 +1,116 @@
#pragma once
#include <QObject>
#include <QTimer>
#include <QEventLoop>
#include <memory>
namespace LtsUtils
{
template <typename Func>
void addConnect(QEventLoop &x, bool &success, const typename QtPrivate::FunctionPointer<Func>::Object *sender, Func signal, bool isSuccess)
{
if (isSuccess)
{
QObject::connect(sender, signal, &x, [&success]()
{
success = true;
});
}
QObject::connect(sender, signal, &x, &QEventLoop::quit, Qt::QueuedConnection);
}
template <typename Func, typename... Connect>
void addConnect(QEventLoop &x, bool &success, const typename QtPrivate::FunctionPointer<Func>::Object *sender, Func signal, bool isSuccess, Connect... connects)
{
addConnect(x, success, sender, signal, isSuccess);
addConnect(x, success, connects...);
}
template <typename... Connect>
void await(Connect... connects) noexcept(false)
{
QEventLoop x;
bool success = false;
addConnect(x, success, connects...);
x.exec();
if (!success)
{
throw std::runtime_error("Failed.");
}
}
template <typename... Connect>
void awaitTimeout(const int timeoutMs, Connect... connects) noexcept(false)
{
std::unique_ptr<QTimer> t(new QTimer);
bool timeout = false;
if (timeoutMs > -1)
{
t->setInterval(timeoutMs);
t->setSingleShot(true);
QObject::connect(t.get(), &QTimer::timeout, t.get(), [&timeout](){ fprintf(stderr, "awaitTimeout: timed out!\n"); timeout = true; });
t->start();
}
await(t.get(), &QTimer::timeout, false, connects...);
if (timeout)
{
throw std::runtime_error("Timeout.");
}
}
template <typename Func1, typename Func2>
void awaitWithCancelationSignal(const typename QtPrivate::FunctionPointer<Func1>::Object *sender1, Func1 signal1,
const typename QtPrivate::FunctionPointer<Func2>::Object *sender2, Func2 signal2,
const int timeoutMs = 0) noexcept(false)
{
if (timeoutMs > 0)
{
awaitTimeout(timeoutMs,
sender1, signal1, true,
sender2, signal2, false);
return;
}
await(sender1, signal1, true,
sender2, signal2, false);
}
}
+126
View File
@@ -0,0 +1,126 @@
#pragma once
#include <QObject>
#include <QMetaObject>
#include <QPointer>
#include <QtGlobal>
#include <type_traits>
namespace LtsUtils
{
class IConnection
{
public:
virtual ~IConnection() = default;
virtual void connect(Qt::ConnectionType = Qt::AutoConnection) = 0;
virtual void disconnect() = 0;
};
class DummyConnection : public IConnection
{
public:
void connect(Qt::ConnectionType = Qt::AutoConnection) override {}
void disconnect() override {}
};
namespace detail
{
template<class T>
struct ExtractClass;
template<class T, class Member>
struct ExtractClass<Member T::*>
{
using type = T;
};
}
template<class Signal, class Slot>
class Connection : public IConnection
{
static_assert(std::is_member_function_pointer<Signal>::value, "Must be a pointer to method");
static_assert(std::is_member_function_pointer<Slot>::value, "Must be a pointer to method");
using Emitter = typename detail::ExtractClass<Signal>::type;
using Target = typename detail::ExtractClass<Slot>::type;
static_assert(std::is_base_of<QObject, Emitter>::value, "Must be derived from QObject");
static_assert(std::is_base_of<QObject, Target>::value, "Must be derived from QObject");
public:
Connection(Emitter *emitter, Signal signal, Target *target, Slot slot):
m_emitter(emitter),
m_signal(signal),
m_target(target),
m_slot(slot)
{
Q_ASSERT(emitter);
Q_ASSERT(signal);
Q_ASSERT(target);
Q_ASSERT(slot);
}
void connect(Qt::ConnectionType connectionType = Qt::AutoConnection) override
{
Q_ASSERT(!m_connected);
m_connected = true;
if (!m_emitter || !m_target)
return;
m_conn = QObject::connect(m_emitter.data(), m_signal, m_target.data(), m_slot, connectionType);
Q_ASSERT(m_conn);
}
void disconnect() override
{
Q_ASSERT(m_connected);
if (m_conn)
QObject::disconnect(m_conn);
m_connected = false;
}
private:
bool m_connected{false};
QPointer<Emitter> m_emitter;
Signal m_signal;
QPointer<Target> m_target;
Slot m_slot;
QMetaObject::Connection m_conn;
};
template<class Signal, class Slot>
Connection<Signal, Slot>* createConnection(typename detail::ExtractClass<Signal>::type *emitter, Signal signal,
typename detail::ExtractClass<Slot>::type *target, Slot slot)
{
return new Connection<Signal, Slot>(emitter, signal, target, slot);
}
}
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <ostream>
enum class DataModification
{
eAdded,
eModified,
eRemoved
};
inline std::ostream &operator<<(std::ostream &str, DataModification mod)
{
switch(mod)
{
case DataModification::eAdded:
str << "DataModification::eAdded";
break;
case DataModification::eModified:
str << "DataModification::eModified";
break;
case DataModification::eRemoved:
str << "DataModification::eRemoved";
break;
}
return str;
}
+98
View File
@@ -0,0 +1,98 @@
#pragma once
#ifdef SUPPORT_QBITARRAY
# include <QtCore/QBitArray>
#endif
namespace LtsUtils
{
namespace BitArray
{
constexpr inline int bitNumber(int position)
{
return 7 - (position % 8);
}
template<typename T>
inline bool testBit(const T &bitField, int position, bool *oob = nullptr)
{
const size_t byteNum = position / 8;
if (byteNum >= bitField.size())
{
if (oob)
*oob = true;
return false;
}
if (oob)
*oob = false;
const typename T::value_type mask = 1 << bitNumber(position);
return ((bitField.at(byteNum) & mask) == mask);
}
template<typename T>
inline bool setBit(T &bitField, int position, bool set = true)
{
const size_t byteNum = position / 8;
if (byteNum >= bitField.size())
return false;
const typename T::value_type mask = 1 << bitNumber(position);
if (set)
bitField[byteNum] |= mask;
else
bitField[byteNum] &= ~mask;
return true;
}
template<typename T>
inline bool clearBit(T &bitField, int position)
{
return setBit(bitField, position, false);
}
#ifdef SUPPORT_QBITARRAY
template<typename T>
inline T convert(const QBitArray &bitArray)
{
T ret;
ret.resize((bitArray.size() + 7) / 8, 0);
for (int i = 0; i < bitArray.size(); ++i)
{
const size_t byteNum = i / 8;
const typename T::value_type mask = (1 << bitNumber(i));
if (bitArray[i])
ret[byteNum] |= mask;
else
ret[byteNum] &= ~mask;
}
return ret;
}
template<typename T>
inline QBitArray convert(T &bitField, int realSize)
{
QBitArray ba(realSize);
for (int32_t i = 0; i < realSize; ++i)
{
const size_t byteNum = i / 8;
const typename T::value_type mask = (1 << bitNumber(i));
bool bit = ((bitField[byteNum] & mask) == mask);
ba[i] = bit;
}
return ba;
}
#endif
}
}
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <QByteArray>
#include <QString>
namespace LtsUtils
{
template <typename T, typename S>
inline void convert(const S &in, T &out)
{
static_assert(!std::is_same<S, T>::value, "Try to convert a type to the same type - is useless");
out.reserve(static_cast<int>(in.size()));
std::copy(in.begin(), in.end(), std::back_inserter(out));
}
template <typename T, typename S>
inline T convert(const S &in)
{
static_assert(!std::is_same<S, T>::value, "Try to convert a type to the same type - is useless");
T out;
convert(in, out);
return out;
}
template <typename T>
inline QByteArray toQByteArray(const T &in)
{
return convert<QByteArray>(in);
}
template <typename T, typename V = typename T::value_type>
bool isInVector(const T &vec, const V &valueToSearch)
{
const auto end = vec.end();
return std::find(vec.begin(), end, valueToSearch) != end;
}
}
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include <LtsUtilsCore/ltsutilscore_export.h>
#include <cstdint>
#include <vector>
class QByteArray;
class QPixmap;
class QImage;
namespace LtsUtils
{
LTSUTILSCORE_EXPORT QPixmap getPixmap(const std::vector<uint8_t> &data);
LTSUTILSCORE_EXPORT QPixmap getPixmap(const QByteArray &data);
LTSUTILSCORE_EXPORT QImage getImage(const std::vector<uint8_t> &data);
LTSUTILSCORE_EXPORT QImage getImage(const QByteArray &data);
LTSUTILSCORE_EXPORT std::vector<uint8_t> fromPixmap(const QPixmap &pixmap, bool *bIsPng = nullptr);
LTSUTILSCORE_EXPORT std::vector<uint8_t> fromImage(const QImage &image, bool *bIsPng = nullptr);
}
+1
View File
@@ -0,0 +1 @@
#include <LtsUtilsCore/json_object.h>
+696
View File
@@ -0,0 +1,696 @@
#pragma once
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QJsonValue>
#include <QVector>
#include <QMap>
#include <QString>
#include <string>
#include <vector>
#include <map>
#include <exception>
#include <cstdint>
#include <limits>
namespace LtsUtils
{
class JsonParseError : public std::runtime_error
{
public:
JsonParseError(const QJsonParseError &err)
: std::runtime_error("json parse error: " + err.errorString().toStdString() + " - at offset " + std::to_string(err.offset)){}
};
class JsonError : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
};
class JsonKeyError : public JsonError
{
public:
using JsonError::JsonError;
};
class JsonRangeError : public JsonError
{
public:
using JsonError::JsonError;
};
class JsonTypeError : public JsonError
{
public:
using JsonError::JsonError;
};
class JsonObject
{
public:
class Key;
JsonObject() = default;
explicit JsonObject(const QJsonObject &json)
: m_json(json)
, m_jsonIsSet(true)
{}
explicit JsonObject(QJsonObject &&json)
: m_json(std::move(json))
, m_jsonIsSet(true)
{}
static inline JsonObject fromJson(const char *json, int len = -1);
static inline JsonObject fromJson(const QByteArray &json) { return fromJson(json.data(), json.size()); }
static inline JsonObject fromJson(const std::string &json) { return fromJson(json.c_str(), json.size()); }
static inline JsonObject fromJsonSafe(const char *json, int len = -1) noexcept(false);
static inline JsonObject fromJsonSafe(const QByteArray &json) noexcept(false) { return fromJsonSafe(json.data(), json.size()); }
static inline JsonObject fromJsonSafe(const std::string &json) noexcept(false) { return fromJsonSafe(json.c_str(), json.size()); }
template<class T>
bool contains(const Key &key) const;
bool isNull(const Key &key) const { return contains<void>(key); }
bool isEmpty() const { return m_json.isEmpty(); }
bool isValid() const { return m_jsonIsSet; }
template<class T>
T value(const Key &key) const noexcept(false);
template<class T>
T valueOr(const Key &key, const T &defaultValue) const noexcept(false);
template<class T>
bool isMap() const;
template<class T>
QMap<QString, T> toMap() const noexcept(false);
template<class T>
std::map<std::string, T> toStdMap() const;
bool operator==(const JsonObject &other) const { return m_json == other.m_json; }
bool operator!=(const JsonObject &other) const { return !(*this == other); }
class Key
{
public:
Key(const QString &s)
: m_s(s)
{}
Key(const std::string &s)
: m_s(QString::fromStdString(s))
{}
Key(const char *s)
: m_s(QString::fromUtf8(s))
{}
operator const QString &() const { return m_s; }
private:
const QString m_s;
};
operator const QJsonObject &() const { return m_json; }
const QJsonObject &object() const { return m_json; }
private:
bool containsAny(const QString &key) const { return m_json.contains(key); }
QJsonObject m_json;
bool m_jsonIsSet = false;
};
JsonObject JsonObject::fromJson(const char *json, int len)
{
if (len < 0)
len = strlen(json);
QJsonParseError error;
const auto doc = QJsonDocument::fromJson(QByteArray::fromRawData(json, len), &error);
if (error.error != QJsonParseError::NoError)
return JsonObject();
if (!doc.isObject())
return JsonObject();
return JsonObject(doc.object());
}
JsonObject JsonObject::fromJsonSafe(const char *json, int len) noexcept(false)
{
if (len < 0)
len = strlen(json);
QJsonParseError error;
const auto doc = QJsonDocument::fromJson(QByteArray::fromRawData(json, len), &error);
if (error.error != QJsonParseError::NoError)
throw JsonParseError(error);
if (!doc.isObject())
throw JsonTypeError("JSON root is not an object");
return JsonObject(doc.object());
}
class JsonArray
{
public:
JsonArray() = default;
explicit JsonArray(const QJsonArray &json)
: m_json(json)
, m_jsonIsSet(true)
{}
explicit JsonArray(QJsonArray &&json)
: m_json(std::move(json))
, m_jsonIsSet(true)
{}
static inline JsonArray fromJson(const char *json, int len = -1);
static inline JsonArray fromJson(const QByteArray &json) { return fromJson(json.data(), json.size()); }
static inline JsonArray fromJson(const std::string &json) { return fromJson(json.c_str(), json.size()); }
static inline JsonArray fromJsonSafe(const char *json, int len = -1) noexcept(false);
static inline JsonArray fromJsonSafe(const QByteArray &json) noexcept(false) { return fromJson(json.data(), json.size()); }
static inline JsonArray fromJsonSafe(const std::string &json) noexcept(false) { return fromJson(json.c_str(), json.size()); }
int size() const { return m_json.size(); }
bool isEmpty() const { return m_json.isEmpty(); }
bool isValid() const { return m_jsonIsSet; }
template<class T>
bool contains(int index) const noexcept(false);
bool isNull(int index) const noexcept(false) { return contains<void>(index); }
template<class T>
T at(int index) const noexcept(false);
template<class T>
bool isVector() const;
template<class T>
QVector<T> toVector() const noexcept(false);
template<class T>
std::vector<T> toStdVector() const;
bool operator==(const JsonArray &other) const { return m_json == other.m_json; }
bool operator!=(const JsonArray &other) const { return !(*this == other); }
const QJsonArray &operator()() const { return m_json; }
private:
QJsonArray m_json;
bool m_jsonIsSet = false;
};
JsonArray JsonArray::fromJson(const char *json, int len)
{
if (len < 0)
len = strlen(json);
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromRawData(json, len), &error);
if (error.error != QJsonParseError::NoError)
return JsonArray();
if (!doc.isArray())
return JsonArray();
return JsonArray(doc.array());
}
JsonArray JsonArray::fromJsonSafe(const char *json, int len) noexcept(false)
{
if (len < 0)
len = strlen(json);
QJsonParseError error;
const auto doc = QJsonDocument::fromJson(QByteArray::fromRawData(json, len), &error);
if (error.error != QJsonParseError::NoError)
throw JsonParseError(error);
if (!doc.isArray())
throw JsonTypeError("JSON root is not an array");
return JsonArray(doc.array());
}
template<class T>
struct JsonValue;
template<class Int>
struct JsonLimits
{
static constexpr Int lowest() { return std::numeric_limits<Int>::lowest(); }
static constexpr Int max() { return std::numeric_limits<Int>::max(); }
};
template<>
struct JsonLimits<int64_t>
{
static constexpr int64_t lowest() { return -(static_cast<int64_t>(1) << 53) + 1; }
static constexpr int64_t max() { return (static_cast<int64_t>(1) << 53) - 1; }
};
template<>
struct JsonLimits<uint64_t>
{
static constexpr uint64_t lowest() { return 0; }
static constexpr uint64_t max() { return JsonLimits<int64_t>::max(); }
};
template<class Int>
struct JsonIntValue
{
static bool matchesType(const QJsonValue &value)
{
if (!value.isDouble())
return false;
double val = value.toDouble();
if (val < JsonLimits<Int>::lowest())
return false;
if (val > JsonLimits<Int>::max())
return false;
double wholeInt = static_cast<Int>(val);
return val == wholeInt;
}
static Int value(const QJsonValue &value) noexcept(false)
{
if (!matchesType(value))
throw JsonTypeError("JSON value not of type Int");
return static_cast<Int>(value.toDouble());
}
};
template<>
struct JsonValue<int16_t> : JsonIntValue<int16_t>
{};
template<>
struct JsonValue<uint16_t> : JsonIntValue<uint16_t>
{};
template<>
struct JsonValue<int32_t> : JsonIntValue<int32_t>
{};
template<>
struct JsonValue<uint32_t> : JsonIntValue<uint32_t>
{};
template<>
struct JsonValue<int64_t> : JsonIntValue<int64_t>
{};
template<>
struct JsonValue<uint64_t> : JsonIntValue<uint64_t>
{};
template<>
struct JsonValue<double>
{
static bool matchesType(const QJsonValue &value) { return value.isDouble(); }
static double value(const QJsonValue &value) noexcept(false)
{
if (!matchesType(value))
throw JsonTypeError("JSON value not of type Double");
return value.toDouble();
}
};
template<>
struct JsonValue<bool>
{
static bool matchesType(const QJsonValue &value) { return value.isBool(); }
static bool value(const QJsonValue &value) noexcept(false)
{
if (!matchesType(value))
throw JsonTypeError("JSON value not of type Bool");
return value.toBool();
}
};
template<>
struct JsonValue<QString>
{
static bool matchesType(const QJsonValue &value) { return value.isString(); }
static QString value(const QJsonValue &value) noexcept(false)
{
if (!matchesType(value))
throw JsonTypeError("JSON value not of type String");
return value.toString();
}
};
template<>
struct JsonValue<std::string>
{
static bool matchesType(const QJsonValue &value) { return value.isString(); }
static std::string value(const QJsonValue &value)
{
return JsonValue<QString>::value(value).toStdString();
}
};
template<>
struct JsonValue<QJsonObject>
{
static bool matchesType(const QJsonValue &value) { return value.isObject(); }
static QJsonObject value(const QJsonValue &value) noexcept(false)
{
if (!matchesType(value))
throw JsonTypeError("JSON value not of type Object");
return value.toObject();
}
};
template<>
struct JsonValue<JsonObject>
{
static bool matchesType(const QJsonValue &value) { return value.isObject(); }
static JsonObject value(const QJsonValue &value) { return JsonObject(JsonValue<QJsonObject>::value(value)); }
};
template<>
struct JsonValue<void>
{
static bool matchesType(const QJsonValue &value) { return value.isNull(); }
};
template<>
struct JsonValue<QJsonArray>
{
static bool matchesType(const QJsonValue &value) { return value.isArray(); }
static QJsonArray value(const QJsonValue &value) noexcept(false)
{
if (!matchesType(value))
throw JsonTypeError("JSON value not of type Array");
return value.toArray();
}
};
template<>
struct JsonValue<JsonArray>
{
static bool matchesType(const QJsonValue &value) { return value.isArray(); }
static JsonArray value(const QJsonValue &value) { return JsonArray(JsonValue<QJsonArray>::value(value)); }
};
template<class T>
struct JsonValue<QVector<T>>
{
static bool matchesType(const QJsonValue &value)
{
if (!value.isArray())
return false;
const JsonArray array(value.toArray());
return array.isVector<T>();
}
static QVector<T> value(const QJsonValue &value)
{
const JsonArray array(JsonValue<QJsonArray>::value(value));
return array.toVector<T>();
}
};
template<class T>
struct JsonValue<std::vector<T>>
{
static bool matchesType(const QJsonValue &value)
{
return JsonValue<QVector<T>>::matchesType(value);
}
static std::vector<T> value(const QJsonValue &value)
{
const JsonArray array(JsonValue<QJsonArray>::value(value));
return array.toStdVector<T>();
}
};
template<class T>
struct JsonValue<QMap<QString, T>>
{
static bool matchesType(const QJsonValue &value)
{
if (!value.isObject())
return false;
const JsonObject obj(JsonValue<QJsonObject>::value(value));
return obj.isMap<T>();
}
static QMap<QString, T> value(const QJsonValue &value)
{
const JsonObject obj(JsonValue<QJsonObject>::value(value));
return obj.toMap<T>();
}
};
template<class T>
struct JsonValue<std::map<std::string, T>>
{
static bool matchesType(const QJsonValue &value)
{
return JsonValue<QMap<QString, T>>::matchesType(value);
}
static std::map<std::string, T> value(const QJsonValue &value)
{
const JsonObject obj(JsonValue<QJsonObject>::value(value));
return obj.toStdMap<T>();
}
};
template<class T>
bool JsonObject::contains(const Key &key) const
{
if (!m_json.contains(key))
return false;
return JsonValue<T>::matchesType(m_json.value(key));
}
template<class T>
T JsonObject::value(const Key &key) const noexcept(false)
{
if (!containsAny(key))
throw JsonKeyError("no element with key: " + static_cast<const QString &>(key).toStdString());
try
{
return JsonValue<T>::value(m_json.value(key));
}
catch(const JsonTypeError &typeError)
{
throw JsonTypeError(std::string(typeError.what()) + " - key: " + static_cast<const QString &>(key).toStdString());
}
}
template<class T>
T JsonObject::valueOr(const Key &key, const T &defaultValue) const
{
try
{
return value<T>(key);
}
catch (const JsonKeyError &)
{
return defaultValue;
}
}
template<class T>
bool JsonObject::isMap() const
{
const QStringList keys = m_json.keys();
for (const auto &key : keys)
if (!JsonValue<T>::matchesType(m_json.value(key)))
return false;
return true;
}
template<class T>
QMap<QString, T> JsonObject::toMap() const
{
QMap<QString, T> result;
for (auto current = m_json.begin(); current != m_json.end(); ++current)
result.insert(current.key(), JsonValue<T>::value(current.value()));
return result;
}
template<class T>
std::map<std::string, T> JsonObject::toStdMap() const
{
std::map<std::string, T> result;
for (auto current = m_json.begin(); current != m_json.end(); ++current)
result.insert({current.key().toStdString(), JsonValue<T>::value(current.value())});
return result;
}
template<class T>
bool JsonArray::contains(int index) const noexcept(false)
{
if (index < 0 || index >= m_json.size())
throw JsonRangeError("index out of range: " + std::to_string(index));
return JsonValue<T>::matchesType(m_json.at(index));
}
template<class T>
T JsonArray::at(int index) const noexcept(false)
{
if (index < 0 || index >= m_json.size())
throw JsonRangeError("index out of range: " + std::to_string(index));
return JsonValue<T>::value(m_json.at(index));
}
template<class T>
bool JsonArray::isVector() const
{
for (const QJsonValue &value : m_json)
if (!JsonValue<T>::matchesType(value))
return false;
return true;
}
template<class T>
QVector<T> JsonArray::toVector() const
{
QVector<T> result;
result.reserve(m_json.size());
for (const QJsonValue &value : m_json)
result.push_back(JsonValue<T>::value(value));
return result;
}
template<class T>
std::vector<T> JsonArray::toStdVector() const
{
std::vector<T> result;
result.reserve(m_json.size());
for (const QJsonValue &value : m_json)
result.push_back(JsonValue<T>::value(value));
return result;
}
}
+14
View File
@@ -0,0 +1,14 @@
#include "lts_portrange.h"
namespace LtsUtils
{
LtsUtils::LtsPortRange fromQPoint(const QPoint &point)
{
if (point.x() < 1025 || point.y() > 65535 || point.x() > point.y())
return {};
return {static_cast<quint16>(point.x()), static_cast<quint16>(point.y())};
}
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <LtsUtilsCore/ltsutilscore_export.h>
#include <QPair>
#include <QPoint>
namespace LtsUtils
{
typedef QPair<quint16, quint16> LtsPortRange;
LTSUTILSCORE_EXPORT LtsPortRange fromQPoint(const QPoint &point);
}
@@ -0,0 +1,25 @@
#include "lts_translatable_identifier.h"
#include <QCoreApplication>
namespace LtsUtils
{
LtsTranslatableIdentifier::LtsTranslatableIdentifier(const QString &identifier, const QObject *context,
const char *translatableText)
: m_identifier(identifier)
, m_translationContext(context->metaObject()->className())
, m_translatableText(translatableText)
{}
const QString LtsTranslatableIdentifier::translatedText(const char *disambiguation, int n) const
{
if (m_identifier.isEmpty() || m_translationContext == nullptr || m_translatableText == nullptr)
return {};
return QCoreApplication::translate(m_translationContext, m_translatableText, disambiguation, n);
}
}
@@ -0,0 +1,33 @@
#pragma once
#include <LtsUtilsCore/ltsutilscore_export.h>
#include <QObject>
#include <QString>
namespace LtsUtils
{
class LTSUTILSCORE_EXPORT LtsTranslatableIdentifier
{
public:
LtsTranslatableIdentifier()
: m_translationContext(nullptr)
, m_translatableText("")
{}
LtsTranslatableIdentifier(const QString &identifier, const QObject *context, const char *translatableText);
const QString &identifier() const { return m_identifier; }
const QString translatedText(const char *disambiguation = nullptr, int n = -1) const;
const QString _context() const { return QString::fromUtf8(m_translationContext); }
private:
QString m_identifier;
const char *m_translationContext;
const char *m_translatableText;
};
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <qglobal.h>
namespace LtsUtils
{
inline bool isPositionTimeOutdated(qint64 curTime, qint64 posTime)
{
return curTime > posTime + 11 * 60 * 1000;
}
}
+169
View File
@@ -0,0 +1,169 @@
#include "pgarray.h"
#include <QVector>
#include <QDebug>
#include <functional>
#include <LtsUtilsCore/ltsutilscore_export.h>
namespace LtsUtils
{
template<typename T>
static inline QString convertToPgString(const std::vector<T> &data)
{
if (data.size() == 0)
return QLatin1String("{}");
QString ret(QLatin1Char('{'));
for (T i : data)
ret += QString::number(i) + QLatin1Char(',');
ret.chop(1);
ret += QLatin1Char('}');
return ret;
}
template<>
LTSUTILSCORE_EXPORT QString IntArray::toPgString() const
{
return convertToPgString(m_data);
}
template<>
LTSUTILSCORE_EXPORT QString BigintArray::toPgString() const
{
return convertToPgString(m_data);
}
template<typename T>
static inline T convertFromPgString(const QString &str, const std::function<typename T::Type(const QStringRef &val, bool *bOk)> &convertFunc)
{
typename T::ContainerType result;
int idxStart = str.indexOf(QLatin1Char('{'));
int idxEnd = str.lastIndexOf(QLatin1Char('}'));
if (idxEnd < idxStart)
return T(result);
if (idxStart < 0 && idxEnd < 0)
{
idxStart = -1;
idxEnd = str.length() + 1;
}
const QStringRef strRef = str.midRef(idxStart + 1, idxEnd - idxStart - 1);
const QVector<QStringRef> vec = strRef.split(QLatin1Char(','), QString::SkipEmptyParts);
result.reserve(vec.size());
for (const QStringRef &s : vec)
{
bool ok = false;
const typename T::Type i = convertFunc(s, &ok);
if (ok)
result.push_back(i);
}
return T(result);
}
template<>
LTSUTILSCORE_EXPORT IntArray IntArray::fromPgString(const QString &str)
{
return convertFromPgString<IntArray>(str,
[](const QStringRef & val, bool * bOk) { return val.toInt(bOk);});
}
template<>
LTSUTILSCORE_EXPORT BigintArray BigintArray::fromPgString(const QString &str)
{
return convertFromPgString<BigintArray>(str,
[](const QStringRef & val, bool * bOk) { return val.toLongLong(bOk);});
}
template<typename T>
static inline QString convertToPgString(const std::map<T, T> &data)
{
if (data.size() == 0)
return QLatin1String("{}");
QString ret(QLatin1Char('{'));
for (const auto &it : data)
{
ret += QLatin1Char('{') + QString::number(it.first) +
QLatin1Char(',') + QString::number(it.second) + QLatin1String("},");
}
ret.chop(1);
ret += QLatin1Char('}');
return ret;
}
template<>
LTSUTILSCORE_EXPORT QString IntArray2D::toPgString() const
{
return convertToPgString<IntArray2D::Type>(m_data);
}
template<>
LTSUTILSCORE_EXPORT QString BigintArray2D::toPgString() const
{
return convertToPgString<BigintArray2D::Type>(m_data);
}
template<typename T>
static inline T convertFromPgString2D(const QString &str, const std::function<typename T::Type(const QStringRef &val)> &convertFunc)
{
typename T::ContainerType ret;
int idxStart = str.indexOf(QLatin1Char('{'));
int idxEnd = str.lastIndexOf(QLatin1Char('}'));
if (idxEnd < idxStart)
return T(ret);
if (idxStart < 0 && idxEnd < 0)
{
idxStart = -1;
idxEnd = str.length() + 1;
}
const QStringRef strRef = str.midRef(idxStart + 1, idxEnd - idxStart - 1);
idxStart = strRef.indexOf(QLatin1Char('{'));
while (idxStart >= 0)
{
idxEnd = strRef.indexOf(QLatin1Char('}'), idxStart);
if (idxEnd < 0)
break;
const QStringRef keyValueStr = strRef.mid(idxStart + 1, idxEnd - idxStart - 1);
const QVector<QStringRef> keyValuePair = keyValueStr.split(QLatin1Char(','), QString::SkipEmptyParts);
if (keyValuePair.size() != 2)
break;
const typename T::Type key = convertFunc(keyValuePair.at(0).trimmed());
const typename T::Type value = convertFunc(keyValuePair.at(1).trimmed());
ret.insert(std::make_pair(key, value));
idxStart = strRef.indexOf(QLatin1Char('{'), idxEnd + 1);
}
return T(ret);
}
template<>
LTSUTILSCORE_EXPORT IntArray2D IntArray2D::fromPgString(const QString &str)
{
return convertFromPgString2D<IntArray2D>(str,
[](const QStringRef & val) { return val.toInt();});
}
template<>
LTSUTILSCORE_EXPORT BigintArray2D BigintArray2D::fromPgString(const QString &str)
{
return convertFromPgString2D<BigintArray2D>(str,
[](const QStringRef & val) { return val.toLongLong();});
}
}
+45
View File
@@ -0,0 +1,45 @@
#pragma once
#include <QString>
#include <map>
#include <vector>
#include <cstdint>
namespace LtsUtils
{
template<typename T, typename C>
class PgArray
{
public:
using Type = T;
using ContainerType = C;
PgArray() = default;
Q_DECL_CONSTEXPR explicit PgArray(const C &data)
: m_data(data)
{}
Q_DECL_CONSTEXPR C operator()()const
{
return m_data;
}
QString toPgString() const;
static PgArray fromPgString(const QString &str);
private:
C m_data;
};
using IntArray = PgArray<int, std::vector<int>>;
using BigintArray = PgArray<int64_t, std::vector<int64_t>>;
using IntArray2D = PgArray<int, std::map<int, int>>;
using BigintArray2D = PgArray<int64_t, std::map<int64_t, int64_t>>;
}
+103
View File
@@ -0,0 +1,103 @@
#include "promise.h"
#include <QTimer>
namespace LtsUtils
{
Promise::Promise(const std::function<void(ResultFunction resolve, ResultFunction reject)> &function, QObject *parent)
: QObject(parent)
, m_functionAlreadySet(false)
, m_timeout(new QTimer(this))
, m_resultSet(false)
, m_timeoutSet(false)
{
m_timeout->setSingleShot(true);
connect(m_timeout, &QTimer::timeout,
this, &Promise::slotTimeout);
setFunction(function);
}
void Promise::setFunction(const std::function<void(ResultFunction resolve, ResultFunction reject)> &function)
{
if (!function || m_functionAlreadySet)
return;
m_functionAlreadySet = true;
if (m_timeoutSet)
m_timeout->start();
QTimer::singleShot(0, this, [this, function]()
{
function([this](const QVariant &value)
{
resolve(value);
}, [this](const QVariant &value)
{
reject(value);
});
});
}
void Promise::setTimeout(int interval)
{
m_timeout->stop();
m_timeout->setInterval(interval);
m_timeoutSet = (interval != 0);
if (interval != 0 && m_functionAlreadySet)
m_timeout->start();
}
void Promise::slotTimeout()
{
reject(QStringLiteral("timeout"));
}
void Promise::resolve(const QVariant &value)
{
if (m_resultSet)
return;
m_resultSet = true;
m_timeout->stop();
m_resolveFn(value);
}
void Promise::reject(const QVariant &value)
{
if (m_resultSet)
return;
m_resultSet = true;
m_timeout->stop();
m_rejectFn(value);
}
Promise &Promise::resolved(ResultFunction resolveFn)
{
m_resolveFn = resolveFn;
return *this;
}
Promise &Promise::rejected(ResultFunction rejectFn)
{
m_rejectFn = rejectFn;
return *this;
}
}
+72
View File
@@ -0,0 +1,72 @@
#pragma once
#include <LtsUtilsCore/ltsutilscore_export.h>
#include <QObject>
#include <QVariant>
#include <functional>
class QTimer;
namespace LtsUtils
{
typedef std::function<void(const QVariant &value)> RawResultFunction;
typedef const RawResultFunction &ResultFunction;
class LTSUTILSCORE_EXPORT Promise : public QObject
{
Q_OBJECT
public:
Promise(const std::function<void(ResultFunction resolve, ResultFunction reject)> &function, QObject *parent = nullptr);
void setFunction(const std::function<void(ResultFunction resolve, ResultFunction reject)> &function);
void resolve(const QVariant &value = QVariant());
void reject(const QVariant &value = QVariant());
void setTimeout(int interval);
Promise &resolved(ResultFunction resolveFn);
Promise &rejected(ResultFunction rejectFn);
private:
RawResultFunction m_resolveFn;
RawResultFunction m_rejectFn;
bool m_functionAlreadySet;
QTimer *m_timeout;
bool m_resultSet;
bool m_timeoutSet;
private slots:
void slotTimeout();
};
}
+165
View File
@@ -0,0 +1,165 @@
#include "promise_examples.h"
#include "promise.h"
#include <QTimer>
#include <QTest>
#include <QDebug>
namespace LtsUtils
{
void PromiseExample1_Class::doSomethingAsync1()
{
QTimer::singleShot(200, this, [this]()
{
emit signalDone1(true);
});
}
void PromiseExample1_Class::doSomethingAsync2()
{
QTimer::singleShot(450, this, [this]()
{
emit signalDone2(true, 1234);
});
}
PromiseExample1::PromiseExample1(QObject *parent)
: QObject(parent)
, m_success(false)
{
auto func = [this](ResultFunction resolve
, ResultFunction reject )
{
PromiseExample1_Class *c = new PromiseExample1_Class(this);
connect(c, &PromiseExample1_Class::signalDone1,
this, [this, c, resolve, reject](bool didThisWork)
{
if (!didThisWork)
{
reject(QStringLiteral("First Action did not succeed"));
return;
}
else
{
connect(c, &PromiseExample1_Class::signalDone2,
this, [resolve, reject](bool didThisWork, int someNumberThatReturns)
{
if (didThisWork)
resolve(someNumberThatReturns);
else
reject(QStringLiteral("Second Action did not succeed"));
});
c->doSomethingAsync2();
}
});
c->doSomethingAsync1();
};
Promise *p = new Promise(func, this);
p->resolved([this](const QVariant &value)
{
qDebug() << "example1 promise succeeded! 'someNumberThatReturns' was" << value;
m_success = true;
}).rejected([](const QVariant &value)
{
qDebug() << "example1 promise failed.." << value;
});
}
PromiseExample2::PromiseExample2(QObject *parent)
: QObject(parent)
, m_success(false)
{
Promise *p = new Promise([](ResultFunction , ResultFunction )
{
}, this);
p->setTimeout(1000);
p->resolved([](const QVariant &)
{
QFAIL("This test case's promise should never resolve");
});
p->rejected([this](const QVariant &val)
{
QVERIFY2(val == QStringLiteral("timeout"), "Promise didn't reject with string \"timeout\"");
qDebug() << "Promise rejected as expected";
m_success = true;
});
}
PromiseExample3::PromiseExample3(QObject *parent)
: QObject(parent)
, m_success(true)
, m_alreadyRejected(false)
{
Promise *p = new Promise([](ResultFunction , ResultFunction reject)
{
reject(QString());
}, this);
p->setTimeout(1000);
p->resolved([](const QVariant &)
{
QFAIL("This test case's promise should never resolve");
});
p->rejected([this](const QVariant &val)
{
qDebug() << "rejected with val" << val;
QVERIFY2(val == QString(), "Promise didn't reject with an expected empty string.");
QVERIFY2(!m_alreadyRejected, "Promise rejected more than once");
m_alreadyRejected = true;
qDebug() << "Promise rejected as expected";
});
}
}
+70
View File
@@ -0,0 +1,70 @@
#pragma once
#include <QObject>
namespace LtsUtils
{
class PromiseExample1_Class : public QObject
{
Q_OBJECT
public:
using QObject::QObject;
void doSomethingAsync1();
void doSomethingAsync2();
signals:
void signalDone1(bool didThisWork);
void signalDone2(bool didThisWork, int someNumberThatReturns);
};
class PromiseExample1 : public QObject
{
Q_OBJECT
public:
explicit PromiseExample1(QObject *parent = nullptr);
bool isSuccess() const { return m_success; }
private:
bool m_success;
};
class PromiseExample2 : public QObject
{
Q_OBJECT
public:
explicit PromiseExample2(QObject *parent = nullptr);
bool isSuccess() const { return m_success; }
private:
bool m_success;
};
class PromiseExample3 : public QObject
{
Q_OBJECT
public:
explicit PromiseExample3(QObject *parent = nullptr);
bool isSuccess() const { return m_success; }
private:
bool m_success;
bool m_alreadyRejected;
};
}
+282
View File
@@ -0,0 +1,282 @@
#pragma once
#include <QtCore/QByteArray>
#include <limits>
namespace LtsUtils
{
template<typename T>
void inline set8Byte(const T in, QByteArray& out)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Only integrals allowed for raw byte accessd");
out += (in & 0xFF00000000000000UL) >> 56;
out += (in & 0x00FF000000000000UL) >> 48;
out += (in & 0x0000FF0000000000UL) >> 40;
out += (in & 0x000000FF00000000UL) >> 32;
out += (in & 0x00000000FF000000UL) >> 24;
out += (in & 0x0000000000FF0000UL) >> 16;
out += (in & 0x000000000000FF00UL) >> 8;
out += (in & 0x00000000000000FFUL);
}
template<>
void inline set8Byte(const double in, QByteArray &out)
{
union hack
{
double d;
int64_t i;
} h;
h.d = in;
set8Byte(h.i, out);
}
template<typename T>
bool inline get8Byte(const QByteArray& baData,
size_t &pos,
T& out)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Only integrals allowed for raw byte accessd");
static_assert(sizeof(T) >= 8, "sizeof(out) is smaller than 8 bytes - will not fit");
out = T();
if(size_t(baData.size()) < pos + 8)
return false;
const char *data = baData.data() + pos;
if(std::numeric_limits<T>::is_signed)
out |= static_cast<signed long long>(data[0]) << 56;
else
out |= (data[0] & 0xFFULL) << 56;
out |= (data[1] & 0xFFULL) << 48;
out |= (data[2] & 0xFFULL) << 40;
out |= (data[3] & 0xFFULL) << 32;
out |= (data[4] & 0xFFULL) << 24;
out |= (data[5] & 0xFFULL) << 16;
out |= (data[6] & 0xFFULL) << 8;
out |= (data[7] & 0xFFULL);
pos += 8;
return true;
}
template<>
bool inline get8Byte(const QByteArray& baData,
size_t &pos,
double& out)
{
out = 0.;
union hack
{
double d;
int64_t i;
} h;
if (!get8Byte(baData, pos, h.i))
return false;
out = h.d;
return true;
}
template<typename T>
bool inline get8Byte(const QByteArray& data, T& out)
{
size_t pos = 0;
return get8Byte(data, pos, out);
}
template<typename T>
void inline set4Byte(const T in, QByteArray& out)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Only integrals allowed for raw byte accessd");
out += (in & 0xFF000000) >> 24;
out += (in & 0x00FF0000) >> 16;
out += (in & 0x0000FF00) >> 8;
out += (in & 0x000000FF);
}
template<>
void inline set4Byte(const double in, QByteArray& out)
{
int tmp = qRound(in);
return set4Byte(tmp, out);
}
template<typename T>
bool inline get4Byte(const QByteArray& baData,
size_t &pos,
T& out)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Only integrals allowed for raw byte accessd");
static_assert(sizeof(T) >= 4, "sizeof(out) is smaller than 4 bytes - will not fit");
out = T();
if(size_t(baData.size()) < pos + 4)
return false;
const char *data = baData.data() + pos;
if(std::numeric_limits<T>::is_signed)
out |= data[0] << 24;
else
out |= (data[0] & 0xFFU) << 24;
out |= (data[1] & 0xFFU) << 16;
out |= (data[2] & 0xFFU) << 8;
out |= (data[3] & 0xFFU);
pos += 4;
return true;
}
template<>
bool inline get4Byte(const QByteArray& baData,
size_t &pos,
double& out)
{
out = 0.;
int tmp;
if(!get4Byte(baData, pos, tmp))
return false;
out = tmp;
return true;
}
template<typename T>
bool inline get4Byte(const QByteArray& data, T& out)
{
size_t pos = 0;
return get4Byte(data, pos, out);
}
template<typename T>
void inline set3Byte(const T in, QByteArray& out)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Only integrals allowed for raw byte accessd");
out += (in & 0x00FF0000) >> 16;
out += (in & 0x0000FF00) >> 8;
out += (in & 0x000000FF);
}
template<typename T>
bool inline get3Byte(const QByteArray& baData,
size_t &pos,
T& out)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Only integrals allowed for raw byte accessd");
static_assert(sizeof(T) >= 3, "sizeof(out) is smaller than 3 bytes - will not fit");
out = T();
if(size_t(baData.size()) < pos + 3)
return false;
const char *data = baData.data() + pos;
if(std::numeric_limits<T>::is_signed)
out |= data[0] << 16;
else
out |= (data[0] & 0xFFU) << 16;
out |= (data[1] & 0xFFU) << 8;
out |= (data[2] & 0xFFU);
pos += 3;
return true;
}
template<typename T>
bool inline get3Byte(const QByteArray& data, T& out)
{
size_t pos = 0;
return get3Byte(data, pos, out);
}
template<typename T>
void inline set2Byte(const T in, QByteArray& out)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Only integrals allowed for raw byte accessd");
out += (in & 0x0000FF00) >> 8;
out += (in & 0x000000FF);
}
template<typename T>
bool inline get2Byte(const QByteArray& baData,
size_t &pos,
T& out)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Only integrals allowed for raw byte accessd");
static_assert(sizeof(T) >= 2, "sizeof(out) is smaller than 2 bytes - will not fit");
out = T();
if(size_t(baData.size()) < pos + 2)
return false;
const char *data = baData.data() + pos;
if(std::numeric_limits<T>::is_signed)
out |= data[0] << 8;
else
out |= (data[0] & 0xFFU) << 8;
out |= data[1] & 0xFFU;
pos += 2;
return true;
}
template<typename T>
bool inline get2Byte(const QByteArray& data, T& out)
{
size_t pos = 0;
return get2Byte(data, pos, out);
}
template<typename T>
void inline set1Byte(const T in, QByteArray& out)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Only integrals allowed for raw byte accessd");
unsigned char c = in;
out += c;
}
template<typename T>
bool inline get1Byte(const QByteArray& baData,
size_t &pos,
T& out)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Only integrals allowed for raw byte accessd");
out = T();
if(size_t(baData.size()) < pos + 1)
return false;
const char *data = baData.data() + pos;
if(std::numeric_limits<T>::is_signed)
out = (T)(data[0]);
else
out = (T)(data[0] & 0xFF);
pos += 1;
return true;
}
template<typename T>
bool inline get1Byte(const QByteArray& data, T& out)
{
size_t pos = 0;
return get1Byte(data, pos, out);
}
}
+88
View File
@@ -0,0 +1,88 @@
#include "qplane3d.h"
#include <cmath>
namespace LtsUtils
{
QPlane3D::QPlane3D(const QPoint3D &pos, const QPoint3D &vec1, const QPoint3D &vec2)
: m_pos(pos)
, m_vec1(vec1)
, m_vec2(vec2)
{
m_normal = QPoint3D::crossProduct(m_vec1, m_vec2);
m_planeC = QPoint3D::dotProduct(m_pos, m_normal);
}
QPoint3D QPlane3D::intersection(const QPoint3D &point, const QPoint3D &direction) const
{
const double dotProduct = QPoint3D::dotProduct(direction, m_normal);
if (qFuzzyIsNull(dotProduct))
return inPlane(point) ? point : QPoint3D();
const double distance = distanceTo(point) / std::abs(dotProduct);
return point + distance * direction;
}
bool QPlane3D::intersects(const QPoint3D &direction) const
{
return !isParallel(direction);
}
bool QPlane3D::isParallel(const QPoint3D &direction) const
{
return qFuzzyIsNull(QPoint3D::dotProduct(m_normal, direction));
}
bool QPlane3D::inPlane(const QPoint3D &point) const
{
if (point == m_pos)
return true;
return qFuzzyIsNull(QPoint3D::dotProduct(m_normal, point - m_pos));
}
double QPlane3D::distanceTo(const QPoint3D &point) const
{
return QPoint3D::dotProduct(point - m_pos, m_normal);
}
QPolygon3D::QPolygon3D(const QVector<QPoint3D> &vertices)
: QPlane3D(vertices[0], vertices[1], vertices[2])
, m_vertices(vertices)
{
}
bool QPolygon3D::containsPoint(const QPoint3D &point) const
{
if (!inPlane(point))
return false;
if (contains(point))
return true;
double angleSum = 0.;
double cosTheta = 0.;
const int numberOfVertices = m_vertices.size();
for (int i = 0; i < m_vertices.size(); ++i)
{
const QPoint3D &first = m_vertices[i % numberOfVertices] - point;
const QPoint3D &second = m_vertices[(i + 1) % numberOfVertices] - point;
cosTheta = QPoint3D::dotProduct(first, second) / (first.length() * second.length());
angleSum += acos(cosTheta);
}
return qFuzzyIsNull(M_2_PI - angleSum);
}
}
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include "qpoint3d.h"
#include <LtsUtilsCore/ltsutilscore_export.h>
#include <QVector>
#include <QPointF>
namespace LtsUtils
{
class LTSUTILSCORE_EXPORT QPlane3D
{
public:
QPlane3D(const QPoint3D &pos, const QPoint3D &vec1, const QPoint3D &vec2);
QPoint3D intersection(const QPoint3D &point, const QPoint3D &direction) const;
bool intersects(const QPoint3D &direction) const;
bool isParallel(const QPoint3D &direction) const;
bool inPlane(const QPoint3D &point) const;
double distanceTo(const QPoint3D &point) const;
const QPoint3D &pos() const { return m_pos; }
const QPoint3D &vec1() const { return m_vec1; }
const QPoint3D &vec2() const { return m_vec2; }
const QPoint3D &normal() const { return m_normal; }
double planeC() const { return m_planeC; }
protected:
QPoint3D m_pos;
QPoint3D m_vec1;
QPoint3D m_vec2;
QPoint3D m_normal;
double m_planeC;
};
class LTSUTILSCORE_EXPORT QPolygon3D : public QPlane3D
{
public:
QPolygon3D(const QVector<QPoint3D> &vertices);
bool contains(const QPoint3D &point) const { return m_vertices.contains(point); }
bool containsPoint(const QPoint3D &point) const;
private:
QVector<QPoint3D> m_vertices;
};
}
+48
View File
@@ -0,0 +1,48 @@
#include "qpoint3d.h"
#include <QDataStream>
using namespace LtsUtils;
double QPoint3D::distanceToLine(const QPoint3D &point, const QPoint3D &direction) const
{
if (direction.isNull())
return (*this - point).length();
QPoint3D p = point + dotProduct(*this - point, direction) * direction;
return (*this - p).length();
}
double QPoint3D::distanceToPlane(const QPoint3D &plane, const QPoint3D &normal) const
{
return dotProduct(*this - plane, normal);
}
double QPoint3D::distanceToPlane(const QPoint3D &plane1, const QPoint3D &plane2, const QPoint3D &plane3) const
{
QPoint3D n = normal(plane2 - plane1, plane3 - plane1);
return dotProduct(*this - plane1, n);
}
double QPoint3D::distanceToPoint(const QPoint3D &point) const
{
return (*this - point).length();
}
QDataStream &operator<<(QDataStream &s, const QPoint3D &p)
{
s << p.x() << p.y() << p.z();
return s;
}
QDataStream &operator>>(QDataStream &s, QPoint3D &p)
{
double x, y, z;
s >> x; p.rx() = x;
s >> y; p.ry() = y;
s >> z; p.rz() = z;
return s;
}
+296
View File
@@ -0,0 +1,296 @@
#pragma once
#include <sstream>
#include <cmath>
#include <LtsUtilsCore/ltsutilscore_export.h>
#include <QtCore/qglobal.h>
#include <QtCore/qpoint.h>
namespace LtsUtils
{
class QPoint3D
{
public:
enum class Axis { X, Y, Z };
Q_DECL_CONSTEXPR QPoint3D() = default;
Q_DECL_CONSTEXPR QPoint3D(double xpos, double ypos, double zpos);
template<typename T>
explicit QPoint3D(const T &data)
: xp(data.offsetX())
, yp(data.offsetY())
, zp(data.offsetZ())
{}
inline bool isNull() const;
Q_DECL_CONSTEXPR inline double x() const;
Q_DECL_CONSTEXPR inline double y() const;
Q_DECL_CONSTEXPR inline double z() const;
Q_DECL_RELAXED_CONSTEXPR inline void setX(double xpos);
Q_DECL_RELAXED_CONSTEXPR inline void setY(double ypos);
Q_DECL_RELAXED_CONSTEXPR inline void setZ(double zpos);
Q_DECL_RELAXED_CONSTEXPR inline double &rx();
Q_DECL_RELAXED_CONSTEXPR inline double &ry();
Q_DECL_RELAXED_CONSTEXPR inline double &rz();
Q_DECL_CONSTEXPR inline QPointF toPointF() const;
static QPoint3D fromQPointF(const QPointF &p)
{
return QPoint3D(p.x(), p.y(), .0);
}
inline double lengthSquared() const { return (xp * xp) + (yp * yp) + (zp * zp); }
inline double length() const { return std::sqrt(lengthSquared()); }
inline void normalize()
{
double len = xp * xp + yp * yp + zp * zp;
if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
return;
len = std::sqrt(len);
xp /= len;
yp /= len;
zp /= len;
}
inline QPoint3D normalized() const
{
double len = xp * xp + yp * yp + zp * zp;
if (qFuzzyIsNull(len - 1.0f))
return *this;
else if (!qFuzzyIsNull(len))
return *this / std::sqrt(len);
else
return QPoint3D(*this);
}
inline void rotate(const double &phi, const Axis &axis)
{
const double sin = std::sin(phi);
const double cos = std::cos(phi);
switch (axis)
{
case Axis::X:
{
const double _yp = (cos * yp) - (sin * zp);
const double _zp = (sin * yp) + (cos * zp);
yp = _yp;
zp = _zp;
break;
}
case Axis::Y:
{
const double _xp = (cos * xp) + (sin * zp);
const double _zp = (-sin * xp) + (cos * zp);
xp = _xp;
zp = _zp;
break;
}
case Axis::Z:
{
const double _xp = (cos * xp) - (sin * yp);
const double _yp = (sin * xp) + (cos * yp);
xp = _xp;
yp = _yp;
break;
}
}
}
inline QPoint3D rotated(const double &phi, const Axis &axis) const
{
QPoint3D p(*this);
p.rotate(phi, axis);
return p;
}
inline double distanceToLine(const QPoint3D &point, const QPoint3D &direction) const;
inline double distanceToPlane(const QPoint3D &plane, const QPoint3D &normal) const;
inline double distanceToPlane(const QPoint3D &plane1, const QPoint3D &plane2, const QPoint3D &plane3) const;
inline double distanceToPoint(const QPoint3D &point) const;
friend Q_DECL_CONSTEXPR inline bool operator==(const QPoint3D &p1, const QPoint3D &p2);
friend Q_DECL_CONSTEXPR inline bool operator!=(const QPoint3D &p1, const QPoint3D &p2);
friend Q_DECL_CONSTEXPR inline QPoint3D operator +(const QPoint3D &p1, const QPoint3D &p2)
{
return QPoint3D(p1.xp + p2.xp, p1.yp + p2.yp, p1.zp + p2.zp);
}
friend Q_DECL_CONSTEXPR inline QPoint3D operator -(const QPoint3D &p1, const QPoint3D &p2)
{
return QPoint3D(p1.xp - p2.xp, p1.yp - p2.yp, p1.zp - p2.zp);
}
friend Q_DECL_CONSTEXPR inline QPoint3D operator *(const QPoint3D &p1, double factor)
{
return QPoint3D(p1.xp * factor, p1.yp * factor, p1.zp * factor);
}
friend Q_DECL_CONSTEXPR inline QPoint3D operator *(double factor, const QPoint3D &p1)
{
return QPoint3D(p1.xp * factor, p1.yp * factor, p1.zp * factor);
}
friend Q_DECL_CONSTEXPR inline QPoint3D operator /(const QPoint3D &p1, double factor)
{
return QPoint3D(p1.xp / factor, p1.yp / factor, p1.zp / factor);
}
Q_DECL_RELAXED_CONSTEXPR inline QPoint3D &operator +=(const QPoint3D &o)
{
xp += o.xp;
yp += o.yp;
zp += o.zp;
return *this;
}
Q_DECL_RELAXED_CONSTEXPR inline QPoint3D &operator -=(const QPoint3D &o)
{
xp -= o.xp;
yp -= o.yp;
zp -= o.zp;
return *this;
}
Q_DECL_RELAXED_CONSTEXPR inline QPoint3D &operator *=(double factor)
{
xp *= factor;
yp *= factor;
zp *= factor;
return *this;
}
Q_DECL_RELAXED_CONSTEXPR inline QPoint3D &operator /=(double divisor)
{
xp /= divisor;
yp /= divisor;
zp /= divisor;
return *this;
}
Q_DECL_CONSTEXPR static inline double dotProduct(const QPoint3D& v1, const QPoint3D& v2)
{
return v1.xp * v2.xp + v1.yp * v2.yp + v1.zp * v2.zp;
}
Q_DECL_CONSTEXPR static inline QPoint3D crossProduct(const QPoint3D& v1, const QPoint3D& v2)
{
return QPoint3D(v1.yp * v2.zp - v1.zp * v2.yp,
v1.zp * v2.xp - v1.xp * v2.zp,
v1.xp * v2.yp - v1.yp * v2.xp);
}
static inline QPoint3D normal(const QPoint3D &v1, const QPoint3D &v2)
{
return crossProduct(v1, v2).normalized();
}
static inline QPoint3D normal(const QPoint3D &v1, const QPoint3D &v2, const QPoint3D &v3)
{
return crossProduct((v2 - v1), (v3 - v1)).normalized();
}
Q_DECL_CONSTEXPR friend inline bool qFuzzyCompare(const QPoint3D& v1, const QPoint3D& v2);
private:
double xp = 0;
double yp = 0;
double zp = 0;
};
LTSUTILSCORE_EXPORT QDataStream &operator<<(QDataStream &s, const QPoint3D &p);
LTSUTILSCORE_EXPORT QDataStream &operator>>(QDataStream &s, QPoint3D &p);
Q_DECL_CONSTEXPR inline QPoint3D::QPoint3D(double xpos, double ypos, double zpos) : xp(xpos), yp(ypos), zp(zpos) { }
inline bool QPoint3D::isNull() const
{
return qIsNull(xp) && qIsNull(yp) && qIsNull(zp);
}
Q_DECL_CONSTEXPR inline double QPoint3D::x() const
{
return xp;
}
Q_DECL_CONSTEXPR inline double QPoint3D::y() const
{
return yp;
}
Q_DECL_CONSTEXPR inline double QPoint3D::z() const
{
return zp;
}
Q_DECL_RELAXED_CONSTEXPR inline void QPoint3D::setX(double xpos)
{
xp = xpos;
}
Q_DECL_RELAXED_CONSTEXPR inline void QPoint3D::setY(double ypos)
{
yp = ypos;
}
Q_DECL_RELAXED_CONSTEXPR inline void QPoint3D::setZ(double zpos)
{
zp = zpos;
}
Q_DECL_RELAXED_CONSTEXPR inline double &QPoint3D::rx()
{
return xp;
}
Q_DECL_RELAXED_CONSTEXPR inline double &QPoint3D::ry()
{
return yp;
}
Q_DECL_RELAXED_CONSTEXPR inline double &QPoint3D::rz()
{
return zp;
}
Q_DECL_CONSTEXPR inline QPointF QPoint3D::toPointF() const
{
return QPointF(xp, yp);
}
Q_DECL_CONSTEXPR inline bool operator==(const QPoint3D &p1, const QPoint3D &p2)
{
return p1.xp == p2.xp && p1.yp == p2.yp && p1.zp == p2.zp;
}
Q_DECL_CONSTEXPR inline bool operator!=(const QPoint3D &p1, const QPoint3D &p2)
{
return p1.xp != p2.xp || p1.yp != p2.yp || p1.zp != p2.zp;
}
Q_DECL_CONSTEXPR inline bool qFuzzyCompare(const QPoint3D& v1, const QPoint3D& v2)
{
return ::qFuzzyCompare(v1.xp, v2.xp) &&
::qFuzzyCompare(v1.yp, v2.yp) &&
::qFuzzyCompare(v1.zp, v2.zp);
}
inline std::ostream& operator<< (std::ostream& stream, const QPoint3D& pos)
{
stream << "(" << pos.x() << "," << pos.y() << "," << pos.z() << ")";
return stream;
}
}
Q_DECLARE_TYPEINFO(LtsUtils::QPoint3D, Q_MOVABLE_TYPE);
+22
View File
@@ -0,0 +1,22 @@
#include "scoped_connection.h"
#include "connection.h"
namespace LtsUtils
{
ScopedConnection::ScopedConnection(IConnection *connection, Qt::ConnectionType connType)
: m_conn(connection)
{
Q_ASSERT(connection);
m_conn->connect(connType);
}
ScopedConnection::~ScopedConnection()
{
m_conn->disconnect();
}
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include <LtsUtilsCore/ltsutilscore_export.h>
#include <Qt>
namespace LtsUtils
{
class IConnection;
class LTSUTILSCORE_EXPORT ScopedConnection
{
public:
explicit ScopedConnection(IConnection *connection, Qt::ConnectionType = Qt::AutoConnection);
~ScopedConnection();
private:
IConnection *m_conn;
};
}
@@ -0,0 +1,301 @@
#include "sfm_bytemessage_converter.h"
namespace LtsUtils
{
static constexpr unsigned char XON = 0x11;
static constexpr unsigned char XOFF = 0x13;
static constexpr unsigned char STX = 0x02;
static constexpr unsigned char ETX = 0x03;
static constexpr unsigned char SUBST = 0x80;
static constexpr unsigned char SUB_XON = 0x91;
static constexpr unsigned char SUB_XOFF = 0x93;
static constexpr unsigned char SUB_STX = 0x82;
static constexpr unsigned char SUB_ETX = 0x83;
static constexpr unsigned char SUB_SUBST = 0x00;
static constexpr int HEADER_SIZE = 3;
static constexpr int CHECKSUM_SIZE = 1;
static constexpr int MINIMUM_BYTE_SIZE = 1 + HEADER_SIZE + CHECKSUM_SIZE + 1;
static SfmMessage getSfmMessage(const QByteArray &p_data)
{
unsigned short id = 0;
id |= (((unsigned short)p_data[0]) & 0x7F) << 8;
id |= (((unsigned short)p_data[1]) & 0xFF) << 0;
SfmMessage msg;
msg.setId(id);
msg.setRtr(p_data[0]&0x80);
msg.setPayload(p_data.right(p_data.size() - HEADER_SIZE));
return msg;
}
static QByteArray getHeader(const SfmMessage &p_msg)
{
QByteArray header(2, Qt::Uninitialized);
header[0] = ((p_msg.id() >> 8) & 0x7f) | (p_msg.rtr() << 7);
header[1] = (p_msg.id() >> 0) & 0xff;
return header;
}
static inline char getChecksum(const QByteArray &p_data)
{
char sum = 0;
for (const char c : p_data)
sum += c;
return sum ^ 0xff;
}
static QByteArray removeChecksum(const QByteArray &p_data)
{
QByteArray withoutChecksum(p_data);
ConversionError error ("Checksum error");
if (p_data.size() >= CHECKSUM_SIZE)
{
withoutChecksum.chop(1);
if (p_data.at(p_data.size() - 1) != getChecksum(withoutChecksum))
throw error;
}
else
throw error;
return withoutChecksum;
}
static QByteArray maskData(const QByteArray &p_data)
{
QByteArray maskData;
maskData.reserve(p_data.size() * 8 / 6);
for (const unsigned char byte : p_data)
{
switch (byte)
{
case XON:
maskData.append(SUBST);
maskData.append(SUB_XON);
break;
case XOFF:
maskData.append(SUBST);
maskData.append(SUB_XOFF);
break;
case STX:
maskData.append(SUBST);
maskData.append(SUB_STX);
break;
case ETX:
maskData.append(SUBST);
maskData.append(SUB_ETX);
break;
case SUBST:
maskData.append(SUBST);
maskData.append(static_cast<char>(SUB_SUBST));
break;
default:
maskData.append(byte);
break;
}
}
return maskData;
}
static bool mustBeMasked(const unsigned char byte)
{
switch (byte)
{
case XON:
case XOFF:
case STX:
case ETX:
case SUBST:
return true;
default:
break;
}
return false;
}
int lenMaskedData(const QByteArray &data)
{
int ret = data.length();
const unsigned char upperLen = ((data.length() & 0xff00) >> 8);
const unsigned char lowerLen = ((data.length() & 0x00ff) >> 0);
if (mustBeMasked(upperLen))
++ret;
if (mustBeMasked(lowerLen))
++ret;
for (const unsigned char byte : data)
{
if (mustBeMasked(byte))
++ret;
}
if (mustBeMasked(getChecksum(data)))
++ret;
return ret;
}
static QByteArray unmaskData(const QByteArray &p_data)
{
QByteArray unmaskData;
unmaskData.reserve(p_data.size());
for (int position = 0; position < p_data.size(); ++position)
{
unsigned char byte = p_data.at(position);
if (byte == SUBST)
{
++position;
byte = p_data.at(position);
switch (byte)
{
case SUB_XON: unmaskData.append(XON); break;
case SUB_XOFF: unmaskData.append(XOFF); break;
case SUB_STX: unmaskData.append(STX); break;
case SUB_ETX: unmaskData.append(ETX); break;
case SUB_SUBST: unmaskData.append(SUBST); break;
default: break;
}
}
else
unmaskData.append(byte);
}
return unmaskData;
}
static QByteArray addFrame(const QByteArray &p_data)
{
QByteArray ret;
ret.reserve(2 + p_data.size());
ret.append(STX);
ret.append(p_data);
ret.append(ETX);
return ret;
}
static QByteArray removeFrame(const QByteArray &p_data)
{
if (p_data[0] == STX && p_data[p_data.size() - 1] == ETX)
{
return p_data.mid(1, p_data.size() - 2);
}
else
throw ConversionError("Framing Error");
}
static void checkLength(const QByteArray &p_data)
{
if (p_data.size() < HEADER_SIZE)
throw ConversionError("Telegram too short");
unsigned char length = p_data[HEADER_SIZE - 1];
if (length != p_data.size() - HEADER_SIZE)
throw ConversionError("Telegram length does not match");
}
QByteArray byteStreamFromSfmMessage(const SfmMessage &message)
{
QByteArray byteData(getHeader(message));
byteData.append(message.payload().size());
byteData.append(message.payload());
byteData.append(getChecksum(byteData));
return addFrame(maskData(byteData));
}
SfmMessage byteStreamToSfmMessage(const QByteArray &datastream)
{
if (datastream.size() < MINIMUM_BYTE_SIZE)
throw ConversionError("Can't convert an QByteArray that hasn't the minimum size!");
QByteArray checkMsg;
checkMsg = removeFrame(datastream);
checkMsg = unmaskData(checkMsg);
checkMsg = removeChecksum(checkMsg);
checkLength(checkMsg);
return getSfmMessage(checkMsg);
}
QByteArray byteStreamFromEscMessage(const QByteArray &message)
{
QByteArray byteData = message;
if (message.size() == 1)
{
byteData.append(message);
}
else
byteData.append(getChecksum(byteData));
byteData = maskData(byteData);
byteData = addFrame(byteData);
return byteData;
}
QByteArray byteStreamToEscMessage(const QByteArray &datastream)
{
if (datastream.size() < 2)
return QByteArray("ERROR");
QByteArray checkMsg;
checkMsg = removeFrame(datastream);
checkMsg = unmaskData(checkMsg);
checkMsg.chop(1);
return checkMsg;
}
}
@@ -0,0 +1,64 @@
#pragma once
#include <LtsUtilsCore/ltsutilscore_export.h>
#include <QByteArray>
namespace LtsUtils
{
class LTSUTILSCORE_EXPORT SfmMessage
{
public:
unsigned int id() const { return m_id; }
void setId(unsigned int id) { m_id = id; }
bool rtr() const { return m_rtr; }
void setRtr(bool rtr) { m_rtr = rtr; }
QByteArray payload() const { return m_payload; }
void setPayload(const QByteArray &payload) { m_payload = payload; }
bool operator==(const SfmMessage &msg) const
{
return (m_id == msg.id() &&
m_rtr == msg.rtr() &&
m_payload == msg.payload());
}
protected:
unsigned int m_id = 0;
bool m_rtr = false;
QByteArray m_payload;
};
class ConversionError : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
};
LTSUTILSCORE_EXPORT QByteArray byteStreamFromSfmMessage(const SfmMessage &message);
LTSUTILSCORE_EXPORT SfmMessage byteStreamToSfmMessage(const QByteArray &datastream);
LTSUTILSCORE_EXPORT QByteArray byteStreamFromEscMessage(const QByteArray &message);
LTSUTILSCORE_EXPORT QByteArray byteStreamToEscMessage(const QByteArray &datastream);
LTSUTILSCORE_EXPORT int lenMaskedData(const QByteArray &data);
}
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include <QVariant>
#include <QDateTime>
#include <ngltools/ngltools_dtg.h>
namespace LtsUtils
{
inline bool lessThan(const QVariant &var1, const QVariant &var2)
{
if (var1.canConvert(QMetaType::QString) && var2.canConvert(QMetaType::QString))
{
QString str1(var1.toString());
QString str2(var2.toString());
bool k1 = false;
double d1 = str1.toDouble(&k1);
if (!k1)
return str1 < str2;
bool k2 = false;
double d2 = str2.toDouble(&k2);
if (!k2)
return str1 < str2;
return d1 < d2;
}
else if (var1.canConvert(QMetaType::Double) && var2.canConvert(QMetaType::Double))
return var1.toDouble() < var2.toDouble();
return false;
}
}