mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-08 07:22:25 +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 <QtScript/QScriptValue>
|
||||
|
||||
namespace controller {
|
||||
#include <QJSonObject>
|
||||
#include <QJSonArray>
|
||||
|
||||
Filter::Pointer Filter::parse(const QJsonObject& json) {
|
||||
// FIXME parse the json object and determine the instance type to create
|
||||
return Filter::Pointer();
|
||||
#include "SharedUtil.h"
|
||||
|
||||
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 <numeric>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
#include <QtCore/QEasingCurve>
|
||||
|
||||
class QJsonObject;
|
||||
class QJsonArray;
|
||||
|
||||
|
||||
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
|
||||
class Filter {
|
||||
public:
|
||||
|
@ -30,18 +66,71 @@ namespace controller {
|
|||
using List = std::list<Pointer>;
|
||||
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 {
|
||||
public:
|
||||
// LambdaFilter() {}
|
||||
LambdaFilter(Lambda f) : _function(f) {};
|
||||
|
||||
virtual float apply(float value) const {
|
||||
return _function(value);
|
||||
}
|
||||
|
||||
virtual bool parseParameters(const QJsonArray& parameters) { return true; }
|
||||
|
||||
// REGISTER_FILTER_CLASS(LambdaFilter);
|
||||
private:
|
||||
Lambda _function;
|
||||
};
|
||||
|
@ -50,17 +139,21 @@ namespace controller {
|
|||
public:
|
||||
|
||||
};
|
||||
|
||||
class ScaleFilter : public Filter {
|
||||
public:
|
||||
ScaleFilter() {}
|
||||
ScaleFilter(float scale): _scale(scale) {}
|
||||
|
||||
//class ScaleFilter : public Filter {
|
||||
//public:
|
||||
// ScaleFilter(float scale);
|
||||
// virtual float apply(float scale) const override {
|
||||
// return value * _scale;
|
||||
// }
|
||||
virtual float apply(float value) const override {
|
||||
return value * _scale;
|
||||
}
|
||||
virtual bool parseParameters(const QJsonArray& parameters);
|
||||
|
||||
//private:
|
||||
// const float _scale;
|
||||
//};
|
||||
REGISTER_FILTER_CLASS(ScaleFilter);
|
||||
private:
|
||||
float _scale = 1.0f;
|
||||
};
|
||||
|
||||
//class AbstractRangeFilter : public Filter {
|
||||
//public:
|
||||
|
@ -84,6 +177,23 @@ namespace controller {
|
|||
// 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 {
|
||||
////public:
|
||||
//// DeadzoneFilter(float min, float max = 1.0f);
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#include <QtCore/QHash>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <QJSONObject>
|
||||
#include <qjsonarray.h>
|
||||
#include <QJSonObject>
|
||||
#include <QJSonArray>
|
||||
|
||||
#include "RouteBuilderProxy.h"
|
||||
#include "../NewControllerScriptingInterface.h"
|
||||
|
@ -71,8 +71,6 @@ void MappingBuilderProxy::parseRoute(const QJsonValue& json) {
|
|||
auto route = dynamic_cast<RouteBuilderProxy*>(newRoute);
|
||||
route->filters(jsonChannel[JSON_CHANNEL_FILTERS]);
|
||||
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 QScriptValue;
|
||||
class QJsonValue;
|
||||
|
||||
namespace controller {
|
||||
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <QJSonObject>
|
||||
#include <QJSonArray>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include "MappingBuilderProxy.h"
|
||||
|
@ -61,9 +64,7 @@ QObject* RouteBuilderProxy::clamp(float min, float max) {
|
|||
}
|
||||
|
||||
QObject* RouteBuilderProxy::scale(float multiplier) {
|
||||
addFilter([=](float value) {
|
||||
return value * multiplier;
|
||||
});
|
||||
addFilter(Filter::Pointer(new ScaleFilter(multiplier)));
|
||||
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) {
|
||||
Filter::Pointer filter = std::make_shared<PulseFilter>(interval);
|
||||
addFilter(filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
|
||||
Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda);
|
||||
addFilter(filterPointer);
|
||||
|
@ -141,4 +115,34 @@ void RouteBuilderProxy::addFilter(Filter::Pointer 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 QScriptValue;
|
||||
class QJsonValue;
|
||||
|
||||
namespace controller {
|
||||
|
||||
|
|
Loading…
Reference in a new issue