mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 19:41:20 +02:00
Refactoring the filter for supporting the factory
This commit is contained in:
parent
fb4ff240ef
commit
cb62527bf9
6 changed files with 218 additions and 52 deletions
|
@ -11,11 +11,66 @@
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtScript/QScriptValue>
|
#include <QtScript/QScriptValue>
|
||||||
|
|
||||||
namespace controller {
|
#include <QJSonObject>
|
||||||
|
#include <QJSonArray>
|
||||||
|
|
||||||
Filter::Pointer Filter::parse(const QJsonObject& json) {
|
#include "SharedUtil.h"
|
||||||
// FIXME parse the json object and determine the instance type to create
|
|
||||||
return Filter::Pointer();
|
using namespace controller;
|
||||||
|
|
||||||
|
|
||||||
|
const QString JSON_FILTER_TYPE = QStringLiteral("type");
|
||||||
|
const QString JSON_FILTER_PARAMS = QStringLiteral("params");
|
||||||
|
|
||||||
|
Filter::Factory Filter::_factory;
|
||||||
|
|
||||||
|
Filter::Pointer Filter::parse(const QJsonObject& json) {
|
||||||
|
// The filter is an object, now let s check for type and potential arguments
|
||||||
|
Filter::Pointer filter;
|
||||||
|
auto filterType = json[JSON_FILTER_TYPE];
|
||||||
|
if (filterType.isString()) {
|
||||||
|
filter.reset(Filter::getFactory().create(filterType.toString().toStdString()));
|
||||||
|
if (filter) {
|
||||||
|
// Filter is defined, need to read the parameters and validate
|
||||||
|
auto parameters = json[JSON_FILTER_PARAMS];
|
||||||
|
if (parameters.isArray()) {
|
||||||
|
if (filter->parseParameters(parameters.toArray())) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return Filter::Pointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Filter::Factory::ClassEntry<ScaleFilter> ScaleFilter::_factoryEntry;
|
||||||
|
|
||||||
|
bool ScaleFilter::parseParameters(const QJsonArray& parameters) {
|
||||||
|
if (parameters.size() > 1) {
|
||||||
|
_scale = parameters[0].toDouble();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Filter::Factory::ClassEntry<PulseFilter> PulseFilter::_factoryEntry;
|
||||||
|
|
||||||
|
|
||||||
|
float PulseFilter::apply(float value) const {
|
||||||
|
float result = 0.0;
|
||||||
|
|
||||||
|
if (0.0 != value) {
|
||||||
|
float now = secTimestampNow();
|
||||||
|
float delta = now - _lastEmitTime;
|
||||||
|
if (delta >= _interval) {
|
||||||
|
_lastEmitTime = now;
|
||||||
|
result = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PulseFilter::parseParameters(const QJsonArray& parameters) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -14,13 +14,49 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <QtCore/QEasingCurve>
|
#include <QtCore/QEasingCurve>
|
||||||
|
|
||||||
class QJsonObject;
|
class QJsonObject;
|
||||||
|
class QJsonArray;
|
||||||
|
|
||||||
|
|
||||||
namespace controller {
|
namespace controller {
|
||||||
|
/*
|
||||||
|
template <class T> class Factory {
|
||||||
|
public:
|
||||||
|
|
||||||
|
template <class T> class Entry {
|
||||||
|
public:
|
||||||
|
virtual T* create() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, class S> class DefaultEntry{
|
||||||
|
public:
|
||||||
|
T* create() { return new S(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
using EntryMap = std::map<std::string, std::unique_ptr<Entry<T>>>;
|
||||||
|
|
||||||
|
void registerEntry(const std::string& name, std::unique_ptr<Entry<T>>& entry) {
|
||||||
|
if (entry) {
|
||||||
|
_entries[name] = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T* create(const std::string& name) const {
|
||||||
|
auto& entryIt = _entries.find(name);
|
||||||
|
if (entryIt != _entries.end()) {
|
||||||
|
return (*entryIt).second->create();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
EntryMap _entries;
|
||||||
|
};
|
||||||
|
*/
|
||||||
// Encapsulates part of a filter chain
|
// Encapsulates part of a filter chain
|
||||||
class Filter {
|
class Filter {
|
||||||
public:
|
public:
|
||||||
|
@ -30,18 +66,71 @@ namespace controller {
|
||||||
using List = std::list<Pointer>;
|
using List = std::list<Pointer>;
|
||||||
using Lambda = std::function<float(float)>;
|
using Lambda = std::function<float(float)>;
|
||||||
|
|
||||||
static Filter::Pointer parse(const QJsonObject& json);
|
// Factory features
|
||||||
};
|
virtual bool parseParameters(const QJsonArray& parameters) = 0;
|
||||||
|
|
||||||
|
class Factory {
|
||||||
|
public:
|
||||||
|
|
||||||
|
class Entry {
|
||||||
|
public:
|
||||||
|
virtual Filter* create() = 0;
|
||||||
|
|
||||||
|
Entry() = default;
|
||||||
|
virtual ~Entry() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> class ClassEntry {
|
||||||
|
public:
|
||||||
|
virtual Filter* create() { return (Filter*) new T(); }
|
||||||
|
|
||||||
|
ClassEntry() = default;
|
||||||
|
virtual ~ClassEntry() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
using EntryMap = std::map<std::string, std::shared_ptr<Entry>>;
|
||||||
|
|
||||||
|
void registerEntry(const std::string& name, const std::shared_ptr<Entry>& entry) {
|
||||||
|
if (entry) {
|
||||||
|
_entries.insert(EntryMap::value_type(name, entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Filter* create(const std::string& name) const {
|
||||||
|
auto& entryIt = _entries.find(name);
|
||||||
|
if (entryIt != _entries.end()) {
|
||||||
|
return (*entryIt).second->create();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
EntryMap _entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Filter::Pointer parse(const QJsonObject& json);
|
||||||
|
static Factory& getFactory() { return _factory; }
|
||||||
|
protected:
|
||||||
|
static Factory _factory;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#define REGISTER_FILTER_CLASS(classEntry) static Filter::Factory::ClassEntry<classEntry> _factoryEntry;
|
||||||
|
|
||||||
|
namespace controller {
|
||||||
|
|
||||||
class LambdaFilter : public Filter {
|
class LambdaFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
|
// LambdaFilter() {}
|
||||||
LambdaFilter(Lambda f) : _function(f) {};
|
LambdaFilter(Lambda f) : _function(f) {};
|
||||||
|
|
||||||
virtual float apply(float value) const {
|
virtual float apply(float value) const {
|
||||||
return _function(value);
|
return _function(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool parseParameters(const QJsonArray& parameters) { return true; }
|
||||||
|
|
||||||
|
// REGISTER_FILTER_CLASS(LambdaFilter);
|
||||||
private:
|
private:
|
||||||
Lambda _function;
|
Lambda _function;
|
||||||
};
|
};
|
||||||
|
@ -50,17 +139,21 @@ namespace controller {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ScaleFilter : public Filter {
|
||||||
|
public:
|
||||||
|
ScaleFilter() {}
|
||||||
|
ScaleFilter(float scale): _scale(scale) {}
|
||||||
|
|
||||||
//class ScaleFilter : public Filter {
|
virtual float apply(float value) const override {
|
||||||
//public:
|
return value * _scale;
|
||||||
// ScaleFilter(float scale);
|
}
|
||||||
// virtual float apply(float scale) const override {
|
virtual bool parseParameters(const QJsonArray& parameters);
|
||||||
// return value * _scale;
|
|
||||||
// }
|
|
||||||
|
|
||||||
//private:
|
REGISTER_FILTER_CLASS(ScaleFilter);
|
||||||
// const float _scale;
|
private:
|
||||||
//};
|
float _scale = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
//class AbstractRangeFilter : public Filter {
|
//class AbstractRangeFilter : public Filter {
|
||||||
//public:
|
//public:
|
||||||
|
@ -84,6 +177,23 @@ namespace controller {
|
||||||
// const float _interval;
|
// const float _interval;
|
||||||
//};
|
//};
|
||||||
|
|
||||||
|
|
||||||
|
class PulseFilter : public Filter {
|
||||||
|
public:
|
||||||
|
REGISTER_FILTER_CLASS(PulseFilter);
|
||||||
|
PulseFilter() {}
|
||||||
|
PulseFilter(float interval) : _interval(interval) {}
|
||||||
|
|
||||||
|
|
||||||
|
virtual float apply(float value) const override;
|
||||||
|
|
||||||
|
virtual bool parseParameters(const QJsonArray& parameters);
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable float _lastEmitTime{ -std::numeric_limits<float>::max() };
|
||||||
|
float _interval = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
////class DeadzoneFilter : public AbstractRangeFilter {
|
////class DeadzoneFilter : public AbstractRangeFilter {
|
||||||
////public:
|
////public:
|
||||||
//// DeadzoneFilter(float min, float max = 1.0f);
|
//// DeadzoneFilter(float min, float max = 1.0f);
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
#include <QtCore/QHash>
|
#include <QtCore/QHash>
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
#include <QJSONObject>
|
#include <QJSonObject>
|
||||||
#include <qjsonarray.h>
|
#include <QJSonArray>
|
||||||
|
|
||||||
#include "RouteBuilderProxy.h"
|
#include "RouteBuilderProxy.h"
|
||||||
#include "../NewControllerScriptingInterface.h"
|
#include "../NewControllerScriptingInterface.h"
|
||||||
|
@ -71,8 +71,6 @@ void MappingBuilderProxy::parseRoute(const QJsonValue& json) {
|
||||||
auto route = dynamic_cast<RouteBuilderProxy*>(newRoute);
|
auto route = dynamic_cast<RouteBuilderProxy*>(newRoute);
|
||||||
route->filters(jsonChannel[JSON_CHANNEL_FILTERS]);
|
route->filters(jsonChannel[JSON_CHANNEL_FILTERS]);
|
||||||
route->to(jsonChannel[JSON_CHANNEL_TO]);
|
route->to(jsonChannel[JSON_CHANNEL_TO]);
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,6 +85,3 @@ QObject* MappingBuilderProxy::from(const QJsonValue& json) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Filter::List MappingBuilderProxy::parseFilters(const QJsonValue& json) const {
|
|
||||||
return Filter::List();
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
class QJSValue;
|
class QJSValue;
|
||||||
class QScriptValue;
|
class QScriptValue;
|
||||||
|
class QJsonValue;
|
||||||
|
|
||||||
namespace controller {
|
namespace controller {
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
|
#include <QJSonObject>
|
||||||
|
#include <QJSonArray>
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
|
|
||||||
#include "MappingBuilderProxy.h"
|
#include "MappingBuilderProxy.h"
|
||||||
|
@ -61,9 +64,7 @@ QObject* RouteBuilderProxy::clamp(float min, float max) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* RouteBuilderProxy::scale(float multiplier) {
|
QObject* RouteBuilderProxy::scale(float multiplier) {
|
||||||
addFilter([=](float value) {
|
addFilter(Filter::Pointer(new ScaleFilter(multiplier)));
|
||||||
return value * multiplier;
|
|
||||||
});
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,39 +100,12 @@ QObject* RouteBuilderProxy::constrainToPositiveInteger() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PulseFilter : public Filter {
|
|
||||||
public:
|
|
||||||
PulseFilter(float interval) : _interval(interval) {}
|
|
||||||
|
|
||||||
virtual float apply(float value) const override {
|
|
||||||
float result = 0.0;
|
|
||||||
|
|
||||||
if (0.0 != value) {
|
|
||||||
float now = secTimestampNow();
|
|
||||||
float delta = now - _lastEmitTime;
|
|
||||||
if (delta >= _interval) {
|
|
||||||
_lastEmitTime = now;
|
|
||||||
result = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable float _lastEmitTime{ -std::numeric_limits<float>::max() };
|
|
||||||
const float _interval;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
QObject* RouteBuilderProxy::pulse(float interval) {
|
QObject* RouteBuilderProxy::pulse(float interval) {
|
||||||
Filter::Pointer filter = std::make_shared<PulseFilter>(interval);
|
Filter::Pointer filter = std::make_shared<PulseFilter>(interval);
|
||||||
addFilter(filter);
|
addFilter(filter);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
|
void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
|
||||||
Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda);
|
Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda);
|
||||||
addFilter(filterPointer);
|
addFilter(filterPointer);
|
||||||
|
@ -141,4 +115,34 @@ void RouteBuilderProxy::addFilter(Filter::Pointer filter) {
|
||||||
_route->_filters.push_back(filter);
|
_route->_filters.push_back(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QObject* RouteBuilderProxy::filters(const QJsonValue& json) {
|
||||||
|
// We expect an array of objects to define the filters
|
||||||
|
if (json.isArray()) {
|
||||||
|
const auto& jsonFilters = json.toArray();
|
||||||
|
for (auto jsonFilter : jsonFilters) {
|
||||||
|
if (jsonFilter.isObject()) {
|
||||||
|
// The filter is an object, now let s check for type and potential arguments
|
||||||
|
Filter::Pointer filter = Filter::parse(jsonFilter.toObject());
|
||||||
|
if (filter) {
|
||||||
|
addFilter(filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouteBuilderProxy::to(const QJsonValue& json) {
|
||||||
|
if (json.isString()) {
|
||||||
|
|
||||||
|
return to(_parent.endpointFor(_parent.inputFor(json.toString())));
|
||||||
|
} else if (json.isObject()) {
|
||||||
|
// Endpoint is defined as an object, we expect a js function then
|
||||||
|
return to(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
class QJSValue;
|
class QJSValue;
|
||||||
class QScriptValue;
|
class QScriptValue;
|
||||||
|
class QJsonValue;
|
||||||
|
|
||||||
namespace controller {
|
namespace controller {
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue