diff options
Diffstat (limited to 'qfunctionconfigurator')
-rw-r--r-- | qfunctionconfigurator/broken/qfunctionconfiguratorplugin.cpp (renamed from qfunctionconfigurator/qfunctionconfiguratorplugin.cpp) | 47 | ||||
-rw-r--r-- | qfunctionconfigurator/broken/qfunctionconfiguratorplugin.h (renamed from qfunctionconfigurator/qfunctionconfiguratorplugin.h) | 9 | ||||
-rw-r--r-- | qfunctionconfigurator/functionconfig.cpp | 563 | ||||
-rw-r--r-- | qfunctionconfigurator/functionconfig.h | 153 | ||||
-rw-r--r-- | qfunctionconfigurator/qfunctionconfigurator.cpp | 853 | ||||
-rw-r--r-- | qfunctionconfigurator/qfunctionconfigurator.h | 171 |
6 files changed, 691 insertions, 1105 deletions
diff --git a/qfunctionconfigurator/qfunctionconfiguratorplugin.cpp b/qfunctionconfigurator/broken/qfunctionconfiguratorplugin.cpp index 5e98eb39..1a9da10a 100644 --- a/qfunctionconfigurator/qfunctionconfiguratorplugin.cpp +++ b/qfunctionconfigurator/broken/qfunctionconfiguratorplugin.cpp @@ -1,37 +1,9 @@ -/******************************************************************************** -* FaceTrackNoIR This program is a private project of some enthusiastic * -* gamers from Holland, who don't like to pay much for * -* head-tracking. * -* * -* Copyright (C) 2012 Wim Vriend (Developing) * -* Ron Hendriks (Researching and Testing) * -* * -* Homepage http://facetracknoir.sourceforge.net/home/default.htm * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the * -* Free Software Foundation; either version 3 of the License, or (at your * -* option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but * -* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * -* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program; if not, see <http://www.gnu.org/licenses/>. * -* * -* The FunctionConfigurator was made by Stanislaw Halik, and adapted to * -* FaceTrackNoIR. * -* * -* All credits for this nice piece of code should go to Stanislaw. * -* * -* Copyright (c) 2011-2012, Stanislaw Halik <sthalik@misaki.pl> * -* Permission to use, copy, modify, and/or distribute this * -* software for any purpose with or without fee is hereby granted, * -* provided that the above copyright notice and this permission * -* notice appear in all copies. * -********************************************************************************/ +/* Copyright (c) 2011-2012 Stanislaw Halik <sthalik@misaki.pl> + * Adapted to FaceTrackNoIR by Wim Vriend. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ #include "qfunctionconfigurator.h" #include <QtCore/QtPlugin> @@ -110,13 +82,6 @@ QString QFunctionConfiguratorPlugin::domXml() const " <blue>0</blue>\n" " </color>\n" " </property>\n" - " <property name=\"colorBackground\">\n" - " <color>\n" - " <red>192</red>\n" - " <green>192</green>\n" - " <blue>192</blue>\n" - " </color>\n" - " </property>\n" " <property name=\"stringInputEGU\" stdset=\"0\">\n" " <string>Input Yaw (degr.)</string>\n" " </property>\n" diff --git a/qfunctionconfigurator/qfunctionconfiguratorplugin.h b/qfunctionconfigurator/broken/qfunctionconfiguratorplugin.h index c6b65fcc..bc637338 100644 --- a/qfunctionconfigurator/qfunctionconfiguratorplugin.h +++ b/qfunctionconfigurator/broken/qfunctionconfiguratorplugin.h @@ -1,3 +1,9 @@ +/* Copyright (c) 2011-2012 Stanislaw Halik <sthalik@misaki.pl> + * Adapted to FaceTrackNoIR by Wim Vriend. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ #ifndef QFUNCTIONCONFIGURATORPLUGIN_H #define QFUNCTIONCONFIGURATORPLUGIN_H @@ -6,7 +12,8 @@ class QFunctionConfiguratorPlugin : public QObject, public QDesignerCustomWidgetInterface { Q_OBJECT - Q_INTERFACES(QDesignerCustomWidgetInterface) + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface" FILE "analogclock.json") + Q_INTERFACES(QDesignerCustomWidgetInterface) public: QFunctionConfiguratorPlugin(QObject *parent = 0); diff --git a/qfunctionconfigurator/functionconfig.cpp b/qfunctionconfigurator/functionconfig.cpp index 1b06bdc2..97a6db24 100644 --- a/qfunctionconfigurator/functionconfig.cpp +++ b/qfunctionconfigurator/functionconfig.cpp @@ -1,282 +1,281 @@ -/* Copyright (c) 2012, 2013 Stanisław Halik <sthalik@misaki.pl>
-
- * Permission to use, copy, modify, and/or distribute this
- * software for any purpose with or without fee is hereby granted,
- * provided that the above copyright notice and this permission
- * notice appear in all copies.
- */
-
-#include <QMutexLocker>
-#include <QCoreApplication>
-#include <QPointF>
-#include <QList>
-#include "functionconfig.h"
-#include <QtAlgorithms>
-#include <QtAlgorithms>
-#include <QSettings>
-#include <math.h>
-#include <QPixmap>
-#include <QDebug>
-
-//
-// Constructor with List of Points in argument.
-//
-FunctionConfig::FunctionConfig(QString title, int intMaxInput, int intMaxOutput)
-{
- _mutex = new QMutex(QMutex::Recursive);
- _title = title;
- _points = QList<QPointF>();
- _data = 0;
- _size = 0;
- lastValueTracked = QPointF(0,0);
- _tracking_active = false;
- _max_Input = intMaxInput; // Added WVR 20120805
- _max_Output = intMaxOutput;
- QSettings settings("opentrack"); // Registry settings (in HK_USER)
- QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
- QSettings iniFile( currentFile, QSettings::IniFormat );
- loadSettings(iniFile);
- reload();
-}
-
-FunctionConfig::FunctionConfig() :
- _tracking_active(false),
- _max_Input(0),
- _max_Output(0),
- _data(0),
- _mutex(0),
- _size(0)
-{
- _mutex = new QMutex();
-}
-
-//
-// Calculate the value of the function, given the input 'x'.
-// Used to draw the curve and, most importantly, to translate input to output.
-// The return-value is also stored internally, so the Widget can show the current value, when the Tracker is running.
-//
-float FunctionConfig::getValue(float x) {
- QMutexLocker foo(_mutex);
- int x2 = (int) (std::min<float>(std::max<float>(x, -360), 360) * MEMOIZE_PRECISION);
- float ret = getValueInternal(x2);
- lastValueTracked.setX(x);
- lastValueTracked.setY(ret);
- return ret;
-}
-
-//
-// The return-value is also stored internally, so the Widget can show the current value, when the Tracker is running.
-//
-bool FunctionConfig::getLastPoint(QPointF& point ) {
- QMutexLocker foo(_mutex);
- point = lastValueTracked;
- return _tracking_active;
-}
-
-float FunctionConfig::getValueInternal(int x) {
- float sign = x < 0 ? -1 : 1;
- x = x < 0 ? -x : x;
- float ret;
- if (!_data)
- ret = 0;
- else if (_size == 0)
- ret = 0;
- else if (x < 0)
- ret = 0;
- else if (x < _size && x >= 0)
- ret = _data[x];
- else
- ret = _data[_size - 1];
- return ret * sign;
-}
-
-static __inline QPointF ensureInBounds(QList<QPointF> points, int i) {
- int siz = points.size();
- if (siz == 0 || i < 0)
- return QPointF(0, 0);
- if (siz > i)
- return points[i];
- return points[siz - 1];
-}
-
-static bool sortFn(const QPointF& one, const QPointF& two) {
- return one.x() < two.x();
-}
-
-void FunctionConfig::reload() {
- _size = 0;
-
- if (_points.size())
- qStableSort(_points.begin(), _points.end(), sortFn);
-
- if (_data)
- delete[] _data;
- _data = NULL;
- if (_points.size()) {
- _data = new float[_size = MEMOIZE_PRECISION * _points[_points.size() - 1].x()];
-
- for (int i = 0; i < _size; i++)
- _data[i] = -1e6;
-
- for (int k = 0; k < _points[0].x() * MEMOIZE_PRECISION; k++) {
- if (k < _size)
- _data[k] = _points[0].y() * k / (_points[0].x() * MEMOIZE_PRECISION);
- }
-
- for (int i = 0; i < _points.size(); i++) {
- QPointF p0 = ensureInBounds(_points, i - 1);
- QPointF p1 = ensureInBounds(_points, i);
- QPointF p2 = ensureInBounds(_points, i + 1);
- QPointF p3 = ensureInBounds(_points, i + 2);
-
- int end = p2.x() * MEMOIZE_PRECISION;
- int start = p1.x() * MEMOIZE_PRECISION;
-
- for (int j = start; j < end && j < _size; j++) {
- float t = (j - start) / (float) (end - start);
- float t2 = t*t;
- float t3 = t*t*t;
-
- int x = .5 * ((2 * p1.x()) +
- (-p0.x() + p2.x()) * t +
- (2 * p0.x() - 5 * p1.x() + 4 * p2.x() - p3.x()) * t2 +
- (-p0.x() + 3 * p1.x() - 3 * p2.x() + p3.x()) * t3)
- * MEMOIZE_PRECISION;
-
- float y = .5 * ((2 * p1.y()) +
- (-p0.y() + p2.y()) * t +
- (2 * p0.y() - 5 * p1.y() + 4 * p2.y() - p3.y()) * t2 +
- (-p0.y() + 3 * p1.y() - 3 * p2.y() + p3.y()) * t3);
-
- if (x >= 0 && x < _size)
- _data[x] = y;
- }
- }
-
- float last = 0;
-
- for (int i = 0; i < _size; i++)
- {
- if (_data[i] == -1e6)
- _data[i] = last;
- last = _data[i];
- }
- }
-}
-
-FunctionConfig::~FunctionConfig() {
- if (_data)
- delete[] _data;
- if (_mutex)
- delete _mutex;
-}
-
-//
-// Remove a Point from the Function.
-// Used by the Widget.
-//
-void FunctionConfig::removePoint(int i) {
- QMutexLocker foo(_mutex);
- if (i >= 0 && i < _points.size())
- {
- _points.removeAt(i);
- reload();
- }
-}
-
-//
-// Add a Point to the Function.
-// Used by the Widget and by loadSettings.
-//
-void FunctionConfig::addPoint(QPointF pt) {
- QMutexLocker foo(_mutex);
- _points.append(pt);
- reload();
-}
-
-//
-// Move a Function Point.
-// Used by the Widget.
-//
-void FunctionConfig::movePoint(int idx, QPointF pt) {
- QMutexLocker foo(_mutex);
- if (idx >= 0 && idx < _points.size())
- {
- _points[idx] = pt;
- reload();
- }
-}
-
-//
-// Return the List of Points.
-// Used by the Widget.
-//
-QList<QPointF> FunctionConfig::getPoints() {
- QList<QPointF> ret;
- QMutexLocker foo(_mutex);
- for (int i = 0; i < _points.size(); i++) {
- ret.append(_points[i]);
- }
- return ret;
-}
-
-//
-// Load the Points for the Function from the INI-file designated by settings.
-// Settings for a specific Curve are loaded from their own Group in the INI-file.
-//
-void FunctionConfig::loadSettings(QSettings& settings) {
- QMutexLocker foo(_mutex);
- QPointF newPoint;
-
- QList<QPointF> points;
- settings.beginGroup(QString("Curves-%1").arg(_title));
-
- int max = settings.value("point-count", 0).toInt();
-
- qDebug() << _title << "count" << max;
-
- for (int i = 0; i < max; i++) {
- newPoint = QPointF(settings.value(QString("point-%1-x").arg(i), (i + 1) * _max_Input/2).toFloat(),
- settings.value(QString("point-%1-y").arg(i), (i + 1) * _max_Output/2).toFloat());
- //
- // Make sure the new Point fits in the Function Range.
- // Maybe this can be improved?
- //
- if (newPoint.x() > _max_Input) {
- newPoint.setX(_max_Input);
- }
- if (newPoint.y() > _max_Output) {
- newPoint.setY(_max_Output);
- }
- points.append(newPoint);
- }
- settings.endGroup();
- _points = points;
- reload();
-}
-
-//
-// Save the Points for the Function to the INI-file designated by settings.
-// Settings for a specific Curve are saved in their own Group in the INI-file.
-// The number of Points is also saved, to make loading more convenient.
-//
-void FunctionConfig::saveSettings(QSettings& settings) {
- QMutexLocker foo(_mutex);
- settings.beginGroup(QString("Curves-%1").arg(_title));
- int max = _points.size();
- settings.setValue("point-count", max);
- for (int i = 0; i < max; i++) {
- settings.setValue(QString("point-%1-x").arg(i), _points[i].x());
- settings.setValue(QString("point-%1-y").arg(i), _points[i].y());
- }
-
- for (int i = max; true; i++)
- {
- QString x = QString("point-%1-x").arg(i);
- if (!settings.contains(x))
- break;
- settings.remove(x);
- settings.remove(QString("point-%1-y").arg(i));
- }
- settings.endGroup();
-}
+/* Copyright (c) 2012, 2013 Stanisław Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + +#include <QMutexLocker> +#include <QCoreApplication> +#include <QPointF> +#include <QList> +#include "functionconfig.h" +#include <QtAlgorithms> +#include <QtAlgorithms> +#include <QSettings> +#include <math.h> +#include <QPixmap> + +// +// Constructor with List of Points in argument. +// +FunctionConfig::FunctionConfig(QString title, int intMaxInput, int intMaxOutput) : + _mutex(QMutex::Recursive) +{ + _title = title; + _points = QList<QPointF>(); + _data = 0; + _size = 0; + lastValueTracked = QPointF(0,0); + _tracking_active = false; + _max_Input = intMaxInput; // Added WVR 20120805 + _max_Output = intMaxOutput; + QSettings settings("opentrack"); // Registry settings (in HK_USER) + QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); + QSettings iniFile( currentFile, QSettings::IniFormat ); + loadSettings(iniFile); + reload(); +} + +void FunctionConfig::setTrackingActive(bool blnActive) +{ + _tracking_active = blnActive; +} + +FunctionConfig::FunctionConfig() : + _mutex(QMutex::Recursive), + _data(0), + _size(0), + _tracking_active(false), + _max_Input(0), + _max_Output(0) +{ +} + +// +// Calculate the value of the function, given the input 'x'. +// Used to draw the curve and, most importantly, to translate input to output. +// The return-value is also stored internally, so the Widget can show the current value, when the Tracker is running. +// +float FunctionConfig::getValue(float x) { + QMutexLocker foo(&_mutex); + int x2 = (int) (std::min<float>(std::max<float>(x, -360), 360) * MEMOIZE_PRECISION); + float ret = getValueInternal(x2); + lastValueTracked.setX(x); + lastValueTracked.setY(ret); + return ret; +} + +// +// The return-value is also stored internally, so the Widget can show the current value, when the Tracker is running. +// +bool FunctionConfig::getLastPoint(QPointF& point ) { + QMutexLocker foo(&_mutex); + point = lastValueTracked; + return _tracking_active; +} + +float FunctionConfig::getValueInternal(int x) { + float sign = x < 0 ? -1 : 1; + x = x < 0 ? -x : x; + float ret; + if (!_data) + ret = 0; + else if (_size == 0) + ret = 0; + else if (x < 0) + ret = 0; + else if (x < _size && x >= 0) + ret = _data[x]; + else + ret = _data[_size - 1]; + return ret * sign; +} + +static __inline QPointF ensureInBounds(QList<QPointF> points, int i) { + int siz = points.size(); + if (siz == 0 || i < 0) + return QPointF(0, 0); + if (siz > i) + return points[i]; + return points[siz - 1]; +} + +static bool sortFn(const QPointF& one, const QPointF& two) { + return one.x() < two.x(); +} + +void FunctionConfig::reload() { + _size = 0; + + if (_points.size()) + qStableSort(_points.begin(), _points.end(), sortFn); + + if (_data) + delete[] _data; + _data = NULL; + if (_points.size()) { + _data = new float[_size = MEMOIZE_PRECISION * _points[_points.size() - 1].x()]; + + for (int i = 0; i < _size; i++) + _data[i] = -1e6; + + for (int k = 0; k < _points[0].x() * MEMOIZE_PRECISION; k++) { + if (k < _size) + _data[k] = _points[0].y() * k / (_points[0].x() * MEMOIZE_PRECISION); + } + + for (int i = 0; i < _points.size(); i++) { + QPointF p0 = ensureInBounds(_points, i - 1); + QPointF p1 = ensureInBounds(_points, i); + QPointF p2 = ensureInBounds(_points, i + 1); + QPointF p3 = ensureInBounds(_points, i + 2); + + int end = p2.x() * MEMOIZE_PRECISION; + int start = p1.x() * MEMOIZE_PRECISION; + + for (int j = start; j < end && j < _size; j++) { + double t = (j - start) / (double) (end - start); + double t2 = t*t; + double t3 = t*t*t; + + int x = .5 * ((2. * p1.x()) + + (-p0.x() + p2.x()) * t + + (2. * p0.x() - 5. * p1.x() + 4. * p2.x() - p3.x()) * t2 + + (-p0.x() + 3. * p1.x() - 3. * p2.x() + p3.x()) * t3) + * MEMOIZE_PRECISION; + + float y = .5 * ((2. * p1.y()) + + (-p0.y() + p2.y()) * t + + (2. * p0.y() - 5. * p1.y() + 4. * p2.y() - p3.y()) * t2 + + (-p0.y() + 3. * p1.y() - 3. * p2.y() + p3.y()) * t3); + + if (x >= 0 && x < _size) + _data[x] = y; + } + } + + float last = 0; + + for (int i = 0; i < _size; i++) + { + if (_data[i] == -1e6) + _data[i] = last; + last = _data[i]; + } + } +} + +FunctionConfig::~FunctionConfig() { + if (_data) + delete[] _data; +} + +// +// Remove a Point from the Function. +// Used by the Widget. +// +void FunctionConfig::removePoint(int i) { + QMutexLocker foo(&_mutex); + if (i >= 0 && i < _points.size()) + { + _points.removeAt(i); + reload(); + } +} + +// +// Add a Point to the Function. +// Used by the Widget and by loadSettings. +// +void FunctionConfig::addPoint(QPointF pt) { + QMutexLocker foo(&_mutex); + _points.append(pt); + reload(); +} + +// +// Move a Function Point. +// Used by the Widget. +// +void FunctionConfig::movePoint(int idx, QPointF pt) { + QMutexLocker foo(&_mutex); + if (idx >= 0 && idx < _points.size()) + { + _points[idx] = pt; + reload(); + } +} + +// +// Return the List of Points. +// Used by the Widget. +// +QList<QPointF> FunctionConfig::getPoints() { + QList<QPointF> ret; + QMutexLocker foo(&_mutex); + for (int i = 0; i < _points.size(); i++) { + ret.append(_points[i]); + } + return ret; +} + +// +// Load the Points for the Function from the INI-file designated by settings. +// Settings for a specific Curve are loaded from their own Group in the INI-file. +// +void FunctionConfig::loadSettings(QSettings& settings) { + QMutexLocker foo(&_mutex); + QPointF newPoint; + + QList<QPointF> points; + settings.beginGroup(QString("Curves-%1").arg(_title)); + + int max = settings.value("point-count", 0).toInt(); + + for (int i = 0; i < max; i++) { + newPoint = QPointF(settings.value(QString("point-%1-x").arg(i), 0).toFloat(), + settings.value(QString("point-%1-y").arg(i), 0).toFloat()); + // + // Make sure the new Point fits in the Function Range. + // Maybe this can be improved? + // + if (newPoint.x() > _max_Input) { + newPoint.setX(_max_Input); + } + if (newPoint.y() > _max_Output) { + newPoint.setY(_max_Output); + } + points.append(newPoint); + } + settings.endGroup(); + _points = points; + reload(); +} + +// +// Save the Points for the Function to the INI-file designated by settings. +// Settings for a specific Curve are saved in their own Group in the INI-file. +// The number of Points is also saved, to make loading more convenient. +// +void FunctionConfig::saveSettings(QSettings& settings) { + QMutexLocker foo(&_mutex); + settings.beginGroup(QString("Curves-%1").arg(_title)); + int max = _points.size(); + settings.setValue("point-count", max); + for (int i = 0; i < max; i++) { + settings.setValue(QString("point-%1-x").arg(i), _points[i].x()); + settings.setValue(QString("point-%1-y").arg(i), _points[i].y()); + } + + for (int i = max; true; i++) + { + QString x = QString("point-%1-x").arg(i); + if (!settings.contains(x)) + break; + settings.remove(x); + settings.remove(QString("point-%1-y").arg(i)); + } + settings.endGroup(); +} diff --git a/qfunctionconfigurator/functionconfig.h b/qfunctionconfigurator/functionconfig.h index 0f60c979..4d771dfd 100644 --- a/qfunctionconfigurator/functionconfig.h +++ b/qfunctionconfigurator/functionconfig.h @@ -1,78 +1,75 @@ -/* Copyright (c) 2011-2012, Stanislaw Halik <sthalik@misaki.pl>
-
- * Permission to use, copy, modify, and/or distribute this
- * software for any purpose with or without fee is hereby granted,
- * provided that the above copyright notice and this permission
- * notice appear in all copies.
- */
-
-#include <QList>
-#include <QPointF>
-#include <QString>
-#include <QSettings>
-#include <QMutex>
-#include "ftnoir_tracker_base/ftnoir_tracker_base.h"
-
-#ifndef FUNCTION_CONFIG_H
-#define FUNCTION_CONFIG_H
-
-#define MEMOIZE_PRECISION 500
-
-class FTNOIR_TRACKER_BASE_EXPORT FunctionConfig {
-private:
- QMutex* _mutex;
- QList<QPointF> _points;
- void reload();
- float* _data;
- int _size;
- QString _title;
- float getValueInternal(int x);
- QPointF lastValueTracked; // The last input value requested by the Tracker, with it's output-value.
- volatile bool _tracking_active;
- int _max_Input;
- int _max_Output;
- FunctionConfig(const FunctionConfig&) {}
-public:
- //
- // Contructor(s) and destructor
- //
- FunctionConfig();
- FunctionConfig(QString title, int intMaxInput, int intMaxOutput);
- virtual ~FunctionConfig();
-
- float getValue(float x);
- bool getLastPoint(QPointF& point); // Get the last Point that was requested.
-
- //
- // Functions to manipulate the Function
- //
- void removePoint(int i);
- void removeAllPoints() {
- QMutexLocker foo(_mutex);
- _points.clear();
- reload();
- }
-
- void addPoint(QPointF pt);
- void movePoint(int idx, QPointF pt);
- QList<QPointF> getPoints();
- void setMaxInput(int MaxInput) {
- _max_Input = MaxInput;
- }
- void setMaxOutput(int MaxOutput) {
- _max_Output = MaxOutput;
- }
-
- //
- // Functions to load/save the Function-Points to an INI-file
- //
- void saveSettings(QSettings& settings);
- void loadSettings(QSettings& settings);
-
- void setTrackingActive(bool blnActive) {
- _tracking_active = blnActive;
- }
- QString getTitle() { return _title; }
-};
-
-#endif
+/* Copyright (c) 2011-2012, Stanislaw Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + +#pragma once + +#include <QList> +#include <QPointF> +#include <QString> +#include <QSettings> +#include <QMutex> +#include "ftnoir_tracker_base/ftnoir_tracker_base.h" + +#define MEMOIZE_PRECISION 100 + +class FTNOIR_TRACKER_BASE_EXPORT FunctionConfig { +private: + QMutex _mutex; + QList<QPointF> _points; + void reload(); + float* _data; + int _size; + QString _title; + float getValueInternal(int x); + QPointF lastValueTracked; // The last input value requested by the Tracker, with it's output-value. + volatile bool _tracking_active; + int _max_Input; + int _max_Output; + FunctionConfig(const FunctionConfig&) = delete; +public: + int maxInput() const { return _max_Input; } + int maxOutput() const { return _max_Output; } + // + // Contructor(s) and destructor + // + FunctionConfig(); + FunctionConfig(QString title, int intMaxInput, int intMaxOutput); + ~FunctionConfig(); + + float getValue(float x); + bool getLastPoint(QPointF& point); // Get the last Point that was requested. + + // + // Functions to manipulate the Function + // + void removePoint(int i); + void removeAllPoints() { + QMutexLocker foo(&_mutex); + _points.clear(); + reload(); + } + + void addPoint(QPointF pt); + void movePoint(int idx, QPointF pt); + QList<QPointF> getPoints(); + void setMaxInput(int MaxInput) { + _max_Input = MaxInput; + } + void setMaxOutput(int MaxOutput) { + _max_Output = MaxOutput; + } + + // + // Functions to load/save the Function-Points to an INI-file + // + void saveSettings(QSettings& settings); + void loadSettings(QSettings& settings); + + void setTrackingActive(bool blnActive); + QString getTitle() { return _title; } +}; diff --git a/qfunctionconfigurator/qfunctionconfigurator.cpp b/qfunctionconfigurator/qfunctionconfigurator.cpp index 304d252e..55d1e1bc 100644 --- a/qfunctionconfigurator/qfunctionconfigurator.cpp +++ b/qfunctionconfigurator/qfunctionconfigurator.cpp @@ -1,45 +1,10 @@ -/******************************************************************************** -* FaceTrackNoIR This program is a private project of some enthusiastic * -* gamers from Holland, who don't like to pay much for * -* head-tracking. * -* * -* Copyright (C) 2012 Wim Vriend (Developing) * -* Ron Hendriks (Researching and Testing) * -* * -* Homepage http://facetracknoir.sourceforge.net/home/default.htm * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the * -* Free Software Foundation; either version 3 of the License, or (at your * -* option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but * -* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * -* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program; if not, see <http://www.gnu.org/licenses/>. * -* * -* The FunctionConfigurator was made by Stanislaw Halik, and adapted to * -* FaceTrackNoIR. * -* * -* All credits for this nice piece of code should go to Stanislaw. * -* * -* Copyright (c) 2011-2012, Stanislaw Halik <sthalik@misaki.pl> * -* Permission to use, copy, modify, and/or distribute this * -* software for any purpose with or without fee is hereby granted, * -* provided that the above copyright notice and this permission * -* notice appear in all copies. * -********************************************************************************/ -/* - Modifications (last one on top): - 20120830 - WVR: Changed functionality a bit. Now only draw the handles, when the function is drawn. - Only check mouseMoves, when they occur 'in range'. Redraw the curve, when a resize occurs. - Somehow, the curve was not drawn correctly, when this was not done (all points were too high). - After a 'Reset' this would disappear... - 20120828 - WVR: Removed bSkipText, which was used to not show a number below each vertical gridline. -*/ +/* Copyright (c) 2011-2012 Stanislaw Halik <sthalik@misaki.pl> + * Adapted to FaceTrackNoIR by Wim Vriend. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + #include "qfunctionconfigurator/qfunctionconfigurator.h" #include <QPainter> #include <QPaintEvent> @@ -52,323 +17,224 @@ #include <QImage> #include <QPixmap> #include <QTimer> - #include <QtDebug> - -#include <math.h> +#include <cmath> +#include <QTabWidget> +#include <QTabBar> +#include <QFontMetrics> static const int pointSize = 5; QFunctionConfigurator::QFunctionConfigurator(QWidget *parent) : QWidget(parent) { - - // - // Defaults, for when the widget has no values different from the domXML() - // - MaxInput = 50; // Maximum input limit - MaxOutput = 180; // Maximum output limit - pPerEGU_Output = 1; // Number of pixels, per EGU - pPerEGU_Input = 4; // Number of pixels, per EGU - gDistEGU_Input = 5; // Distance of gridlines - gDistEGU_Output = 10; // Distance of gridlines - - - // Change compared to BezierConfigurator: X = horizontal (input), Y = vertical (output) - // This will require the Curve-Dialog to be higher (which was the reason it was reversed in the first place..) - range = QRectF(40, 20, MaxInput * pPerEGU_Input, MaxOutput * pPerEGU_Output); - - setMouseTracking(true); movingPoint = -1; // Index of that same point - - // - // Variables for FunctionConfig - // - _config = 0; - _points = QList<QPointF>(); - _draw_background = true; - _draw_function = true; - -// qDebug() << "QFunctionConfigurator::QFunctionConfigurator object created."; - + _config = 0; + _draw_background = true; + _draw_function = true; + update_range(); + setMouseTracking(true); } -// -// Attach an existing FunctionConfig to the Widget. -// -void QFunctionConfigurator::setConfig(FunctionConfig* config, QString settingsFile) { -QPointF currentPoint; -QPointF drawPoint; -qreal x; - - _config = config; - _points = config->getPoints(); - strSettingsFile = settingsFile; // Remember for Reset() - - qDebug() << "QFunctionConfigurator::setConfig" << config->getTitle(); - setCaption(config->getTitle()); - - // - // Get the Function Points, one for each pixel in the horizontal range. - // If the curve does not change, there is no need to run this code every time (it slows down drawing). - // - for (int j = 0; j < MaxInput * pPerEGU_Input; j++) { - // - // Weird: not casting to float causes C++ to round the number... - // - x = (float) j / (float) pPerEGU_Input; - currentPoint.setX ( x ); - currentPoint.setY (_config->getValue( x )); - drawPoint = graphicalizePoint(currentPoint, "setConfig"); - //if (withinRect(drawPoint, range)) { - //_draw_points.append(drawPoint); -// qDebug() << "QFunctionConfigurator::setConfig _draw_Point to add = " << drawPoint; - //} - } - - _draw_function = true; - this->update(); -} +void QFunctionConfigurator::setConfig(FunctionConfig* config) { + QSettings settings("opentrack"); // Registry settings (in HK_USER) + QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); + QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file) -// -// Load the FunctionConfig (points) from the INI-file. -// -void QFunctionConfigurator::loadSettings(QString settingsFile) { - - QSettings iniFile( settingsFile, QSettings::IniFormat ); // Application settings (in INI-file) - strSettingsFile = settingsFile; // Remember for Reset() - qDebug() << "QFunctionConfigurator::loadSettings = " << settingsFile; - if (_config) { - _config->loadSettings(iniFile); - setConfig(_config, settingsFile); - } + config->loadSettings(iniFile); + _config = config; + _draw_function = _draw_background = true; + update_range(); + update(); } -// -// Save the FunctionConfig (points) to the INI-file. -// void QFunctionConfigurator::saveSettings(QString settingsFile) { - QSettings iniFile( settingsFile, QSettings::IniFormat ); // Application settings (in INI-file) - strSettingsFile = settingsFile; // Remember for Reset() - qDebug() << "QFunctionConfigurator::saveSettings = " << settingsFile; + QSettings iniFile( settingsFile, QSettings::IniFormat ); // Application settings (in INI-file) - if (_config) { - _config->saveSettings(iniFile); - } + if (_config) { + _config->saveSettings(iniFile); + } } -// -// Draw the Background for the graph, the gridlines and the gridpoints. -// The static objects are drawn on a Pixmap, so it does not have to be repeated every paintEvent. Hope this speeds things up... -// -void QFunctionConfigurator::drawBackground(const QRectF &fullRect) +void QFunctionConfigurator::drawBackground() { -int i; -QRect scale; - - qDebug() << "QFunctionConfigurator::drawBackground."; - - _background = QPixmap(fullRect.width(), fullRect.height()); - QPainter painter(&_background); - - painter.save(); - painter.setRenderHint(QPainter::Antialiasing); - painter.fillRect(fullRect, colBackground); - QColor bg_color(112, 154, 209); - painter.fillRect(range, bg_color); - - QFont font("ComicSans", 4); + if (!_config) + return; + _background = QPixmap(width(), height()); + QPainter painter(&_background); + painter.fillRect(rect(), QColor::fromRgb(204, 204, 204)); + painter.setRenderHint(QPainter::Antialiasing); + QColor bg_color(112, 154, 209); + painter.fillRect(range, bg_color); + + QFont font; font.setPointSize(8); painter.setFont(font); + QFontMetrics metrics(font); QPen pen(QColor(55, 104, 170, 127), 1, Qt::SolidLine); - // - // Draw the Caption - // - if (_config) { - strCaption = _config->getTitle(); - } - - scale.setCoords(range.left(), 0, range.right(), 20); - painter.drawText(scale, Qt::AlignCenter, strCaption); - - // - // Draw the horizontal grid - // - for (i = range.bottom() - gDistEGU_Output * pPerEGU_Output; i >= range.top(); i -= gDistEGU_Output * pPerEGU_Output) { - drawLine(&painter, QPointF(40, i), QPointF(range.right(), i), pen); - scale.setCoords(0, i - 5, range.left() - 5, i + 5); - painter.drawText(scale, Qt::AlignRight, tr("%1").arg(((range.bottom() - i))/pPerEGU_Output)); - } - - // - // Draw the vertical guidelines - // - for (i = range.left(); i <= range.right(); i += gDistEGU_Input * pPerEGU_Input) { - drawLine(&painter, QPointF(i, range.top()), QPointF(i, range.bottom()), pen); - scale.setCoords(i - 10, range.bottom() + 2, i + 10, range.bottom() + 15); - painter.drawText(scale, Qt::AlignCenter, tr("%1").arg(abs(((range.left() - i))/pPerEGU_Input))); - } - - scale.setCoords(range.left(), range.bottom() + 20, range.right(), range.bottom() + 35); - painter.drawText(scale, Qt::AlignRight, strInputEGU); - - // - // Draw the EGU of the vertical axis (vertically!) - // - font.setPointSize(10); - painter.translate(range.topLeft().x() - 35, range.topLeft().y()); - painter.rotate(90); - painter.drawText(0,0,strOutputEGU ); - - // - // Draw the two axis - // - pen.setWidth(2); - pen.setColor( Qt::black ); - drawLine(&painter, range.topLeft() - QPointF(2,0), range.bottomLeft() - QPointF(2,0), pen); - drawLine(&painter, range.bottomLeft(), range.bottomRight(), pen); - - painter.restore(); -} + const int xstep = 10, ystep = 10; + const int maxx = _config->maxInput(); + const int maxy = _config->maxOutput(); + + // horizontal grid + + for (int i = 0; i < maxy; i += xstep) + { + double y = range.height() - i * c.y() + range.y(); + drawLine(&painter, + QPointF(range.x(), y), + QPointF(range.x() + range.width(), y), + pen); + painter.drawText(QRectF(10, + y - metrics.height()/2, + range.left(), + metrics.height()), + QString::number(i)); + } + { + const int i = maxy; + double y = range.height() - i * c.y() + range.y(); + drawLine(&painter, + QPointF(range.x(), y), + QPointF(range.x() + range.width(), y), + pen); + painter.drawText(QRectF(10, + y - metrics.height()/2, + range.x() - 10, + metrics.height()), + QString::number(i)); + } -// -// Draw the Function for the graph, on a Pixmap. -// -void QFunctionConfigurator::drawFunction(const QRectF &fullRect) + // vertical grid + + for (int i = 0; i < maxx; i += ystep) + { + double x = range.x() + i * c.x(); + drawLine(&painter, + QPointF(x, range.y()), + QPointF(x, range.y() + range.height()), + pen); + const QString text = QString::number(i); + painter.drawText(QRectF(x - metrics.width(text)/2, + range.height() + 10 + metrics.height(), + metrics.width(text), + metrics.height()), + text); + } + { + const int i = maxx; + double x = range.x() + i * c.x(); + drawLine(&painter, + QPointF(x, range.y()), + QPointF(x, range.y() + range.height()), + pen); + const QString text = QString::number(i); + painter.drawText(QRectF(x - metrics.width(text)/2, + range.height() + 10 + metrics.height(), + metrics.width(text), + metrics.height()), + text); + } +} + +void QFunctionConfigurator::drawFunction() { - if (!_config) - return; -int i; -QPointF prevPoint; -QPointF currentPoint; - - // - // Use the background picture to draw on. - // ToDo: find out how to add Pixmaps, without getting it all green... - // - _function = QPixmap(_background); - QPainter painter(&_function); - - painter.save(); + if (!_config) + return; + int i; + QPointF prevPoint; + QPointF currentPoint; + + _function = QPixmap(_background); + QPainter painter(&_function); + + painter.save(); painter.setRenderHint(QPainter::Antialiasing, true); - // - // Draw the handles for the Points - // - for (i = 0; i < _points.size(); i++) { - currentPoint = graphicalizePoint( _points[i], "drawFunction handles" ); // Get the next point and convert it to Widget measures - drawPoint(&painter, currentPoint, QColor(200, 200, 210, 120)); - lastPoint = currentPoint; // Remember which point is the rightmost in the graph -//qDebug() << "QFunctionConfigurator::paintEvent, drawing handle for " << currentPoint; - } + QList<QPointF> points = _config->getPoints(); + + for (i = 0; i < points.size(); i++) { + currentPoint = point_to_pixel( points[i] ); // Get the next point and convert it to Widget measures + drawPoint(&painter, currentPoint, QColor(200, 200, 210, 120)); + lastPoint = currentPoint; // Remember which point is the rightmost in the graph + } QPen pen(colBezier, 1.2, Qt::SolidLine); - prevPoint = graphicalizePoint( QPointF(0,0), "drawFunction lines" ); // Start at the Axis - double max = maxInputEGU(); - QPointF prev = graphicalizePoint(QPointF(0, 0)); - double step = 1e-1 / (double) pixPerEGU_Input(); - for (double i = 0; i < max; i += step) { - double val = _config->getValue(i); - QPointF cur = graphicalizePoint(QPointF(i, val)); - drawLine(&painter, prev, cur, pen); - prev = cur; - } - painter.restore(); + prevPoint = point_to_pixel( QPointF(0,0) ); // Start at the Axis + double max = _config->maxInput(); + QPointF prev = point_to_pixel(QPointF(0, 0)); + const double step = 1.01; + for (double i = 0; i < max; i += step) { + double val = _config->getValue(i); + QPointF cur = point_to_pixel(QPointF(i, val)); + drawLine(&painter, prev, cur, pen); + prev = cur; + } + painter.restore(); } -// -// The Widget paints the surface every x msecs. -// void QFunctionConfigurator::paintEvent(QPaintEvent *e) { -QPointF prevPoint; -QPointF currentPoint; -QPointF actualPos; -int i; + QPointF prevPoint; + QPointF currentPoint; + QPointF actualPos; + int i; -// qDebug() << "QFunctionConfigurator::paintEvent."; - - QPainter p(this); + QPainter p(this); p.setRenderHint(QPainter::Antialiasing); - p.setClipRect(e->rect()); - - if (_draw_background) { - drawBackground(e->rect()); // Draw the static parts on a Pixmap - p.drawPixmap(0, 0, _background); // Paint the background - _draw_background = false; - } - - if (_draw_function) { - drawFunction(e->rect()); // Draw the Function on a Pixmap - _draw_function = false; - } - p.drawPixmap(0, 0, _function); // Always draw the background and the function - - QPen pen(Qt::white, 1, Qt::SolidLine); - - // - // Draw the Points, that make up the Curve - // - if (_config) { - // - // When moving, also draw a sketched version of the Function. - // - if (movingPoint >= 0 && movingPoint < _points.size()) { - prevPoint = graphicalizePoint( QPointF(0,0), "paintEvent moving" ); // Start at the Axis - for (i = 0; i < _points.size(); i++) { - currentPoint = graphicalizePoint( _points[i], "paintEvent moving" ); // Get the next point and convert it to Widget measures - drawLine(&p, prevPoint, currentPoint, pen); - prevPoint = currentPoint; -// qDebug() << "QFunctionConfigurator::paintEvent, drawing while moving " << currentPoint; - } - - // - // When moving, also draw a few help-lines, so positioning the point gets easier. - // - pen.setWidth(1); - pen.setColor( Qt::white ); - pen.setStyle( Qt::DashLine ); - actualPos = graphicalizePoint(_points[movingPoint], "paintEvent moving help line(s)"); - drawLine(&p, QPoint(range.left(), actualPos.y()), QPoint(actualPos.x(), actualPos.y()), pen); - drawLine(&p, QPoint(actualPos.x(), actualPos.y()), QPoint(actualPos.x(), range.bottom()), pen); - } - - // - // If the Tracker is active, the 'Last Point' it requested is recorded. - // Show that point on the graph, with some lines to assist. - // This new feature is very handy for tweaking the curves! - // - if (_config->getLastPoint( currentPoint )) { - -// qDebug() << "QFunctionConfigurator::paintEvent, drawing tracked Point " << currentPoint; - - actualPos = graphicalizePoint( currentPoint, "paintEvent tracking" ); - drawPoint(&p, actualPos, QColor(255, 0, 0, 120)); - - pen.setWidth(1); - pen.setColor( Qt::black ); - pen.setStyle( Qt::SolidLine ); - drawLine(&p, QPoint(range.left(), actualPos.y()), QPoint(actualPos.x(), actualPos.y()), pen); - drawLine(&p, QPoint(actualPos.x(), actualPos.y()), QPoint(actualPos.x(), range.bottom()), pen); - } - - } - - // - // Draw the delimiters - // - pen.setWidth(1); - pen.setColor( Qt::white ); - pen.setStyle( Qt::SolidLine ); - drawLine(&p, QPoint(lastPoint.x(), range.top()), QPoint(lastPoint.x(), range.bottom()), pen); - drawLine(&p, QPoint(range.left(), lastPoint.y()), QPoint(range.right(), lastPoint.y()), pen); - - //QTimer::singleShot(50, this, SLOT(update())); + + if (_draw_background) { + drawBackground(); + _draw_background = false; + } + p.drawPixmap(e->rect(), _background); + + if (_draw_function) { + drawFunction(); // Draw the Function on a Pixmap + _draw_function = false; + } + p.drawPixmap(e->rect(), _function); // Always draw the background and the function + + if (_config) { + QPen pen(Qt::white, 1, Qt::SolidLine); + QList<QPointF> points = _config->getPoints(); + if (movingPoint >= 0 && movingPoint < points.size()) { + prevPoint = point_to_pixel( QPointF(0,0) ); // Start at the Axis + for (i = 0; i < points.size(); i++) { + currentPoint = point_to_pixel( points[i] ); // Get the next point and convert it to Widget measures + drawLine(&p, prevPoint, currentPoint, pen); + prevPoint = currentPoint; + } + pen.setWidth(1); + pen.setColor( Qt::white ); + pen.setStyle( Qt::DashLine ); + actualPos = point_to_pixel(points[movingPoint]); + drawLine(&p, QPoint(range.left(), actualPos.y()), QPoint(actualPos.x(), actualPos.y()), pen); + drawLine(&p, QPoint(actualPos.x(), actualPos.y()), QPoint(actualPos.x(), range.height() + range.top()), pen); + } + + // + // If the Tracker is active, the 'Last Point' it requested is recorded. + // Show that point on the graph, with some lines to assist. + // This new feature is very handy for tweaking the curves! + // + if (_config->getLastPoint( currentPoint )) { + actualPos = point_to_pixel( QPointF(fabs(currentPoint.x()), fabs(currentPoint.y())) ); + drawPoint(&p, actualPos, QColor(255, 0, 0, 120)); + + pen.setWidth(1); + pen.setColor( Qt::black ); + pen.setStyle( Qt::SolidLine ); + drawLine(&p, QPoint(range.left(), actualPos.y()), QPoint(actualPos.x(), actualPos.y()), pen); + drawLine(&p, QPoint(actualPos.x(), actualPos.y()), QPoint(actualPos.x(), range.width()), pen); + } + + } } // @@ -394,252 +260,144 @@ void QFunctionConfigurator::drawLine(QPainter *painter, const QPointF &start, co painter->restore(); } -// -// If the mousebutton is pressed, check if it is inside one of the Points. -// If so: start moving that Point, until mouse release. -// void QFunctionConfigurator::mousePressEvent(QMouseEvent *e) { - // - // First: check the left mouse-button - // - if (e->button() == Qt::LeftButton) { - - // - // Check to see if the cursor is touching one of the points. - // - bool bTouchingPoint = false; - movingPoint = -1; - if (_config) { - - for (int i = 0; i < _points.size(); i++) { - if ( markContains( graphicalizePoint( _points[i], "mousePressEvent markContains" ), e->pos() ) ) { - bTouchingPoint = true; - movingPoint = i; + if (!_config) + return; + QList<QPointF> points = _config->getPoints(); + if (e->button() == Qt::LeftButton) { + bool bTouchingPoint = false; + movingPoint = -1; + if (_config) { + for (int i = 0; i < points.size(); i++) { + if ( point_within_pixel(points[i], e->pos() ) ) { + bTouchingPoint = true; + movingPoint = i; + timer.restart(); break; - } - } - - // - // If the Left Mouse-button was clicked without touching a Point, add a new Point - // - if (!bTouchingPoint) { - if (withinRect(e->pos(), range)) { - _config->addPoint(normalizePoint(e->pos())); - setConfig(_config, strSettingsFile); - movingPoint = -1; - emit CurveChanged( true ); - } - } - } - } - - // - // Then: check the right mouse-button - // - if (e->button() == Qt::RightButton) { - - // - // Check to see if the cursor is touching one of the points. - // - if (_config) { - - for (int i = 0; i < _points.size(); i++) { - if ( markContains( graphicalizePoint( _points[i], "mousePressEvent RightButton" ), e->pos() ) ) { - movingPoint = i; + } + } + if (!bTouchingPoint) { + _config->addPoint(pixel_coord_to_point(e->pos())); + emit CurveChanged( true ); + } + } + } + + if (e->button() == Qt::RightButton) { + if (_config) { + int found_pt = -1; + for (int i = 0; i < points.size(); i++) { + if ( point_within_pixel(points[i], e->pos() ) ) { + found_pt = i; break; - } - } - - // - // If the Right Mouse-button was clicked while touching a Point, remove the Point - // - if (movingPoint >= 0 && movingPoint < _points.size()) { - _config->removePoint(movingPoint); - movingPoint = -1; - setConfig(_config, strSettingsFile); - emit CurveChanged( true ); - } - else - movingPoint = -1; + } + } + + if (found_pt != -1) { + _config->removePoint(found_pt); + emit CurveChanged( true ); + } + movingPoint = -1; } - } + } + _draw_function = true; + update(); } -// -// If the mouse if moving, make sure the Bezier moves along. -// Of course, only when a Point is selected... -// void QFunctionConfigurator::mouseMoveEvent(QMouseEvent *e) { + if (!_config) + return; + QList<QPointF> points = _config->getPoints(); + const int refresh_delay = 50; + + if (movingPoint >= 0 && movingPoint < points.size()) { + setCursor(Qt::ClosedHandCursor); + + if (timer.isValid() && timer.elapsed() > refresh_delay) + { + timer.restart(); + QPointF new_pt = pixel_coord_to_point(e->pos()); + points[movingPoint] = new_pt; + _config->movePoint(movingPoint, new_pt); + _draw_function = true; + update(); + } + } + else { + bool bTouchingPoint = false; + if (_config) { + for (int i = 0; i < points.size(); i++) { + if ( point_within_pixel(points[i], e->pos() ) ) { + bTouchingPoint = true; + } + } + } - if (movingPoint >= 0 && movingPoint < _points.size()) { - - setCursor(Qt::ClosedHandCursor); - - // - // Change the currently moving Point. - // - _points[movingPoint] = normalizePoint(e->pos()); - update(); + if ( bTouchingPoint ) { + setCursor(Qt::OpenHandCursor); + } + else { + setCursor(Qt::ArrowCursor); + } } - else { - - // - // Check to see if the cursor is touching one of the points. - // - bool bTouchingPoint = false; - if (_config) { - - for (int i = 0; i < _points.size(); i++) { - if ( markContains( graphicalizePoint( _points[i], "mouseMoveEvent" ), e->pos() ) ) { - bTouchingPoint = true; - } - } - } - - if ( bTouchingPoint ) { - setCursor(Qt::OpenHandCursor); - } - else { - setCursor(Qt::ArrowCursor); - } - - } } void QFunctionConfigurator::mouseReleaseEvent(QMouseEvent *e) { + if (!_config) + return; + QList<QPointF> points = _config->getPoints(); + if (e->button() == Qt::LeftButton) { - //qDebug()<<"releasing"; - if (movingPoint >= 0 && movingPoint < _points.size()) { + timer.invalidate(); + if (movingPoint >= 0 && movingPoint < points.size()) { emit CurveChanged( true ); - - // - // Update the Point in the _config - // if (_config) { - _config->movePoint(movingPoint, normalizePoint(e->pos())); - setConfig(_config, strSettingsFile); + _config->movePoint(movingPoint, pixel_coord_to_point(e->pos())); } } setCursor(Qt::ArrowCursor); movingPoint = -1; } -} - -// -// Determine if the mousebutton was pressed within the range of the Point. -// -bool QFunctionConfigurator::markContains(const QPointF &pos, const QPointF &coord) const -{ - QRectF rect(pos.x() - pointSize, - pos.y() - pointSize, - pointSize*2, pointSize*2); - QPainterPath path; - path.addEllipse(rect); - return path.contains(coord); -} -bool QFunctionConfigurator::withinRect( const QPointF &coord, const QRectF &rect ) const -{ - QPainterPath path; - path.addRect(rect); - return path.contains(coord); + _draw_function = true; + update(); } -// -// Convert the Point in the graph, to the real-life Point. -// -QPointF QFunctionConfigurator::normalizePoint(QPointF point) const +bool QFunctionConfigurator::point_within_pixel(QPointF pt, QPointF pixel) const { - QPointF norm; - - norm.setX( (point.x() - range.left()) / pPerEGU_Input ); - norm.setY( (range.bottom() - point.y()) / pPerEGU_Output ); - - if (norm.x() > maxInputEGU()) - norm.setX(maxInputEGU()); - else if (norm.x() < 0) - norm.setX(0); - if (norm.y() > maxOutputEGU()) - norm.setY(maxOutputEGU()); - else if (norm.y() < 0) - norm.setY(0); - - return norm; + QPointF pixel2(range.x() + pt.x() * c.x(), (range.y() + range.height() - pt.y() * c.y())); + return pixel2.x() >= pixel.x() - pointSize && pixel2.x() < pixel.x() + pointSize && + pixel2.y() >= pixel.y() - pointSize && pixel2.y() < pixel.y() + pointSize; } -// -// Convert the real-life Point into the graphical Point. -// -QPointF QFunctionConfigurator::graphicalizePoint(QPointF point, QString source) const +QPointF QFunctionConfigurator::pixel_coord_to_point(QPointF point) const { -QPointF graph; - - graph.setX( range.left() + (fabs(point.x()) * pPerEGU_Input) ); - graph.setY( range.bottom() - (fabs(point.y()) * pPerEGU_Output) ); - -// qDebug() << "QFunctionConfigurator::graphicalizePoint source = " << source << ", point = " << point << ", graph = " << graph; - - return graph; -} + if (!_config) + return QPointF(-1, -1); -void QFunctionConfigurator::setmaxInputEGU(int value) -{ - MaxInput = value; - setMinimumWidth(MaxInput * pPerEGU_Input + 55); -// resetCurve(); - resize( MaxInput * pPerEGU_Input + 55, MaxOutput * pPerEGU_Output + 60 ); -} -void QFunctionConfigurator::setmaxOutputEGU(int value) -{ - MaxOutput = value; - setMinimumHeight(MaxOutput * pPerEGU_Output + 60); -// resetCurve(); - resize( MaxInput * pPerEGU_Input + 55, MaxOutput * pPerEGU_Output + 60 ); -} + double x = (point.x() - range.x()) / c.x(); + double y = (range.height() - point.y() + range.y()) / c.y(); -// -// To make configuration more visibly attractive, the number of pixels 'per EGU' can be defined. -// -void QFunctionConfigurator::setpixPerEGU_Input(int value) -{ - pPerEGU_Input = value; - setMinimumWidth(MaxInput * pPerEGU_Input + 55); - resize( MaxInput * pPerEGU_Input + 55, MaxOutput * pPerEGU_Output + 60 ); -} + if (x < 0) + x = 0; + if (x > _config->maxInput()) + x = _config->maxInput(); -// -// To make configuration more visibly attractive, the number of pixels 'per EGU' can be defined. -// -void QFunctionConfigurator::setpixPerEGU_Output(int value) -{ - pPerEGU_Output = value; - setMinimumHeight(MaxOutput * pPerEGU_Output + 60); - resize( MaxInput * pPerEGU_Input + 55, MaxOutput * pPerEGU_Output + 60 ); -} + if (y < 0) + y = 0; + if (y > _config->maxOutput()) + y = _config->maxOutput(); -// -// Define the distance of the grid 'in EGU' points. -// -void QFunctionConfigurator::setgridDistEGU_Input(int value) -{ - gDistEGU_Input = value; - _draw_background = true; - _draw_function = true; - repaint(); + return QPointF(x, y); } -// -// Define the distance of the grid 'in EGU' points. -// -void QFunctionConfigurator::setgridDistEGU_Output(int value) +QPointF QFunctionConfigurator::point_to_pixel(QPointF point) const { - gDistEGU_Output = value; - _draw_background = true; - _draw_function = true; - repaint(); + return QPointF(range.x() + point.x() * c.x(), + range.y() + range.height() - point.y() * c.y()); } void QFunctionConfigurator::setColorBezier(QColor color) @@ -647,38 +405,9 @@ void QFunctionConfigurator::setColorBezier(QColor color) colBezier = color; update(); } -void QFunctionConfigurator::setColorBackground(QColor color) -{ - colBackground = color; - update(); -} - -void QFunctionConfigurator::setInputEGU(QString egu) -{ - strInputEGU = egu; - update(); -} -void QFunctionConfigurator::setOutputEGU(QString egu) -{ - strOutputEGU = egu; - update(); -} -void QFunctionConfigurator::setCaption(QString cap) -{ - strCaption = cap; - update(); -} -void QFunctionConfigurator::resizeEvent(QResizeEvent *e) +void QFunctionConfigurator::resizeEvent(QResizeEvent *) { - range = QRectF(40, 20, MaxInput * pPerEGU_Input, MaxOutput * pPerEGU_Output); - - qDebug() << "QFunctionConfigurator::resizeEvent, name = " << strCaption << ",range = " << range; - - if (_config) { - setConfig(_config, strSettingsFile); - } - _draw_background = true; - _draw_function = true; - repaint(); + update_range(); + repaint(); } diff --git a/qfunctionconfigurator/qfunctionconfigurator.h b/qfunctionconfigurator/qfunctionconfigurator.h index 963f6b13..1f6b4f78 100644 --- a/qfunctionconfigurator/qfunctionconfigurator.h +++ b/qfunctionconfigurator/qfunctionconfigurator.h @@ -1,44 +1,16 @@ -/******************************************************************************** -* FaceTrackNoIR This program is a private project of some enthusiastic * -* gamers from Holland, who don't like to pay much for * -* head-tracking. * -* * -* Copyright (C) 2012 Wim Vriend (Developing) * -* Ron Hendriks (Researching and Testing) * -* * -* Homepage http://facetracknoir.sourceforge.net/home/default.htm * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the * -* Free Software Foundation; either version 3 of the License, or (at your * -* option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but * -* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * -* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program; if not, see <http://www.gnu.org/licenses/>. * -* * -* The FunctionConfigurator was made by Stanislaw Halik, and adapted to * -* FaceTrackNoIR. * -* * -* All credits for this nice piece of code should go to Stanislaw. * -* * -* Copyright (c) 2011-2012, Stanislaw Halik <sthalik@misaki.pl> * -* Permission to use, copy, modify, and/or distribute this * -* software for any purpose with or without fee is hereby granted, * -* provided that the above copyright notice and this permission * -* notice appear in all copies. * -********************************************************************************/ +/* Copyright (c) 2011-2012 Stanislaw Halik <sthalik@misaki.pl> + * Adapted to FaceTrackNoIR by Wim Vriend. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ #ifndef QFUNCTIONCONFIGURATOR_H #define QFUNCTIONCONFIGURATOR_H #include <QWidget> #include <QtGui> -#include <QtDesigner/QDesignerExportWidget> #include <QPointF> +#include <QElapsedTimer> #include "qfunctionconfigurator/functionconfig.h" #include "ftnoir_tracker_base/ftnoir_tracker_base.h" @@ -49,104 +21,27 @@ // The Function is coded in a separate Class and can exists, without the Widget. When the widget is displayed (therefore 'created'), the Function can be attached to the // Widget and the Widget used to change the Function. // + class FTNOIR_TRACKER_BASE_EXPORT QFunctionConfigurator : public QWidget { Q_OBJECT - Q_PROPERTY(int maxInputEGU READ maxInputEGU WRITE setmaxInputEGU); - Q_PROPERTY(int maxOutputEGU READ maxOutputEGU WRITE setmaxOutputEGU); - Q_PROPERTY(int pixPerEGU_Input READ pixPerEGU_Input WRITE setpixPerEGU_Input); - Q_PROPERTY(int pixPerEGU_Output READ pixPerEGU_Output WRITE setpixPerEGU_Output); - Q_PROPERTY(int gridDistEGU_Input READ gridDistEGU_Input WRITE setgridDistEGU_Input); - Q_PROPERTY(int gridDistEGU_Output READ gridDistEGU_Output WRITE setgridDistEGU_Output); - - Q_PROPERTY(QColor colorBezier READ colorBezier WRITE setColorBezier); - Q_PROPERTY(QColor colorBackground READ colorBackground WRITE setColorBackground); - Q_PROPERTY(QString stringInputEGU READ stringInputEGU WRITE setInputEGU); - Q_PROPERTY(QString stringOutputEGU READ stringOutputEGU WRITE setOutputEGU); - Q_PROPERTY(QString stringCaption READ stringCaption WRITE setCaption); - - // Return the current value to Designer - int maxInputEGU() const - { - return MaxInput; - } - int maxOutputEGU() const - { - return MaxOutput; - } - int pixPerEGU_Input() const - { - return pPerEGU_Input; - } - int pixPerEGU_Output() const - { - return pPerEGU_Output; - } - int gridDistEGU_Input() const - { - return gDistEGU_Input; - } - int gridDistEGU_Output() const - { - return gDistEGU_Output; - } - - // Return the current color to Designer - QColor colorBezier() const + Q_PROPERTY(QColor colorBezier READ colorBezier WRITE setColorBezier) + QColor colorBezier() const { return colBezier; } - // Return the current color to Designer - QColor colorBackground() const - { - return colBackground; - } - // Return the current string to Designer - QString stringInputEGU() const - { - return strInputEGU; - } - // Return the current string to Designer - QString stringOutputEGU() const - { - return strOutputEGU; - } - // Return the current string to Designer - QString stringCaption() const - { - return strCaption; - } - public: QFunctionConfigurator(QWidget *parent = 0); FunctionConfig* config(); - void setConfig(FunctionConfig* config, QString settingsFile); // Connect the FunctionConfig to the Widget. - void loadSettings(QString settingsFile); // Load the FunctionConfig (points) from the INI-file - void saveSettings(QString settingsFile); // Save the FunctionConfig (points) to the INI-file + void setConfig(FunctionConfig* config); + void saveSettings(QString settingsFile); signals: void CurveChanged(bool); public slots: - void setmaxInputEGU(int); - void setmaxOutputEGU(int); - void setpixPerEGU_Input(int); - void setpixPerEGU_Output(int); - void setgridDistEGU_Input(int); - void setgridDistEGU_Output(int); - void setColorBezier(QColor); - void setColorBackground(QColor); - void setInputEGU(QString); - void setOutputEGU(QString); - void setCaption(QString); - - void resetCurve() { - qDebug() << "QFunctionConfigurator::resetCurve = " << strSettingsFile; - loadSettings( strSettingsFile ); - } - protected slots: void paintEvent(QPaintEvent *e); void mousePressEvent(QMouseEvent *e); @@ -154,50 +49,44 @@ protected slots: void mouseReleaseEvent(QMouseEvent *e); protected: - void drawBackground(const QRectF &rect); - void drawFunction(const QRectF &rect); + void drawBackground(); + void drawFunction(); void drawPoint(QPainter *painter, const QPointF &pt, QColor colBG ); void drawLine(QPainter *painter, const QPointF &start, const QPointF &end, QPen pen); - bool markContains(const QPointF &pt, const QPointF &coord) const; -// bool withinRange( const QPointF &coord ) const; - bool withinRect( const QPointF &coord, const QRectF &rect ) const; + bool point_within_pixel(QPointF pt, QPointF pixel) const; protected: virtual void resizeEvent(QResizeEvent *); private: + void update_range() { + if (!_config) + return; + double w = width(), h = height(); + const double mwl = 40, mhl = 20; + const double mwr = 15, mhr = 35; + range = QRectF(mwl, mhl, (w - mwl - mwr), (h - mhl - mhr)); + c = QPointF(range.width() / _config->maxInput(), range.height() / _config->maxOutput()); + _draw_function = _draw_background = true; + } + QRectF range; // The actual rectangle for the Bezier-curve QPointF lastPoint; // The right-most point of the Function - QPointF normalizePoint (QPointF point) const; // Convert the graphical Point to a real-life Point - QPointF graphicalizePoint (QPointF point, QString source = "") const; // Convert the Point to a graphical Point + QPointF pixel_coord_to_point (QPointF point) const; // Convert the graphical Point to a real-life Point + QPointF point_to_pixel (QPointF point) const; // Convert the Point to a graphical Point int movingPoint; - - int MaxInput; // Maximum input limit - int MaxOutput; // Maximum output limit - int pPerEGU_Input; // Number of pixels, per EGU of Input - int pPerEGU_Output; // Number of pixels, per EGU of Output - int gDistEGU_Input; // Distance of the grid, in EGU of Input - int gDistEGU_Output; // Distance of the grid, in EGU of Output + QElapsedTimer timer; + QPointF c; QColor colBezier; // Color of Bezier curve - QColor colBackground; // Color of widget background - QString strInputEGU; // Engineering Units input (vertical axis) - QString strOutputEGU; // Engineering Units output (horizontal axis) - QString strCaption; // Caption of the graph - QString strSettingsFile; // Name of last read INI-file bool _draw_background; // Flag to determine if the background should be (re-)drawn on the QPixmap QPixmap _background; // Image of the static parts (axis, lines, etc.) bool _draw_function; // Flag to determine if the function should be (re-)drawn on the QPixmap QPixmap _function; // Image of the function (static unless edited by the user) - // - // Properties of the CurveConfigurator Widget - // - QString _title; // Title do display in Widget and to load Settings FunctionConfig* _config; - QList<QPointF> _points; // Function-points }; #endif // QFUNCTIONCONFIGURATOR_H |