mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-28 07:59:37 -06:00
spaces instead of tabs
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files(the "Software"), to deal in the Software without
|
||||
@@ -30,12 +30,12 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// set parameters required by levmarq() to default values
|
||||
void levmarq_init(LMstat *lmstat) {
|
||||
lmstat->verbose = false;
|
||||
lmstat->max_it = 3000;
|
||||
lmstat->init_lambda = 1e-6;
|
||||
lmstat->up_factor = 10;
|
||||
lmstat->down_factor = 10;
|
||||
lmstat->target_derr = 1e-12;
|
||||
lmstat->verbose = false;
|
||||
lmstat->max_it = 3000;
|
||||
lmstat->init_lambda = 1e-6;
|
||||
lmstat->up_factor = 10;
|
||||
lmstat->down_factor = 10;
|
||||
lmstat->target_derr = 1e-12;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,222 +58,222 @@ Before calling levmarq, several of the parameters in lmstat must be set.
|
||||
For default values, call levmarq_init(lmstat).
|
||||
*/
|
||||
bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
double (*func)(double *, int, void *, LMstat*),
|
||||
void (*grad)(double *, double *, int, void *, LMstat*),
|
||||
void *fdata, LMstat *lmstat) {
|
||||
double (*func)(double *, int, void *, LMstat*),
|
||||
void (*grad)(double *, double *, int, void *, LMstat*),
|
||||
void *fdata, LMstat *lmstat) {
|
||||
|
||||
int x, i, j, it, nit, ill;
|
||||
bool verbose;
|
||||
std::string data = "";
|
||||
double lambda, up, down, mult, weight, err, newerr, derr, target_derr;
|
||||
int x, i, j, it, nit, ill;
|
||||
bool verbose;
|
||||
std::string data = "";
|
||||
double lambda, up, down, mult, weight, err, newerr, derr, target_derr;
|
||||
|
||||
// allocate the arrays
|
||||
double** h = new double*[npar];
|
||||
double** ch = new double*[npar];
|
||||
for (int i = 0; i < npar; i++) {
|
||||
h[i] = new double[npar];
|
||||
ch[i] = new double[npar];
|
||||
}
|
||||
double* g = new double[npar];
|
||||
double* d = new double[npar];
|
||||
double* delta = new double[npar];
|
||||
double* newpar = new double[npar];
|
||||
// allocate the arrays
|
||||
double** h = new double*[npar];
|
||||
double** ch = new double*[npar];
|
||||
for (int i = 0; i < npar; i++) {
|
||||
h[i] = new double[npar];
|
||||
ch[i] = new double[npar];
|
||||
}
|
||||
double* g = new double[npar];
|
||||
double* d = new double[npar];
|
||||
double* delta = new double[npar];
|
||||
double* newpar = new double[npar];
|
||||
|
||||
verbose = lmstat->verbose;
|
||||
nit = lmstat->max_it;
|
||||
lambda = lmstat->init_lambda;
|
||||
up = lmstat->up_factor;
|
||||
down = 1/lmstat->down_factor;
|
||||
target_derr = lmstat->target_derr;
|
||||
weight = 1;
|
||||
derr = newerr = 0; // to avoid compiler warnings
|
||||
verbose = lmstat->verbose;
|
||||
nit = lmstat->max_it;
|
||||
lambda = lmstat->init_lambda;
|
||||
up = lmstat->up_factor;
|
||||
down = 1/lmstat->down_factor;
|
||||
target_derr = lmstat->target_derr;
|
||||
weight = 1;
|
||||
derr = newerr = 0; // to avoid compiler warnings
|
||||
|
||||
if (verbose) {
|
||||
std::ostringstream qs, gs, ds, ps, oss;
|
||||
for (i = 0; i < npar; ++i) {
|
||||
qs << "q" << i;
|
||||
gs << "g" << i;
|
||||
ds << "d" << i;
|
||||
if (i + 1 < npar) {
|
||||
qs << ",";
|
||||
gs << ",";
|
||||
ds << ",";
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ny; ++i) {
|
||||
for (j = 0; j < 2; ++j) {
|
||||
std::string s = (j == 0) ? "x" : "y";
|
||||
ps << "p" << i << s;
|
||||
if (j + 1 < ny) {
|
||||
ps << ",";
|
||||
}
|
||||
}
|
||||
if (i + 1 < ny) {
|
||||
ps << ",";
|
||||
}
|
||||
}
|
||||
oss << "it,err,derr," << qs.str() << "," << gs.str() << "," << ds.str() << "," << ps.str() << "\n";
|
||||
data = oss.str();
|
||||
}
|
||||
if (verbose) {
|
||||
std::ostringstream qs, gs, ds, ps, oss;
|
||||
for (i = 0; i < npar; ++i) {
|
||||
qs << "q" << i;
|
||||
gs << "g" << i;
|
||||
ds << "d" << i;
|
||||
if (i + 1 < npar) {
|
||||
qs << ",";
|
||||
gs << ",";
|
||||
ds << ",";
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ny; ++i) {
|
||||
for (j = 0; j < 2; ++j) {
|
||||
std::string s = (j == 0) ? "x" : "y";
|
||||
ps << "p" << i << s;
|
||||
if (j + 1 < ny) {
|
||||
ps << ",";
|
||||
}
|
||||
}
|
||||
if (i + 1 < ny) {
|
||||
ps << ",";
|
||||
}
|
||||
}
|
||||
oss << "it,err,derr," << qs.str() << "," << gs.str() << "," << ds.str() << "," << ps.str() << "\n";
|
||||
data = oss.str();
|
||||
}
|
||||
|
||||
// calculate the initial error ("chi-squared")
|
||||
lmstat->pos.clear();
|
||||
err = error_func(par, ny, dysq, func, fdata, lmstat);
|
||||
// calculate the initial error ("chi-squared")
|
||||
lmstat->pos.clear();
|
||||
err = error_func(par, ny, dysq, func, fdata, lmstat);
|
||||
|
||||
// main iteration
|
||||
for (it = 0; it < nit; it++) {
|
||||
// calculate the approximation to the Hessian and the "derivative" d
|
||||
for (i = 0; i < npar; i++) {
|
||||
d[i] = 0;
|
||||
for (j = 0; j <= i; j++)
|
||||
h[i][j] = 0;
|
||||
}
|
||||
for (x = 0; x < ny; x++) {
|
||||
if (dysq)
|
||||
weight = 1/dysq[x]; // for weighted least-squares
|
||||
grad(g, par, x, fdata, lmstat);
|
||||
for (i = 0; i < npar; i++) {
|
||||
d[i] += (0.0 - func(par, x, fdata, lmstat)) * g[i] * weight; //(y[x] - func(par, x, fdata)) * g[i] * weight;
|
||||
for (j = 0; j <= i; j++)
|
||||
h[i][j] += g[i] * g[j] * weight;
|
||||
}
|
||||
}
|
||||
// make a step "delta." If the step is rejected, increase lambda and try again
|
||||
mult = 1 + lambda;
|
||||
ill = 1; // ill-conditioned?
|
||||
while (ill && (it < nit)) {
|
||||
for (i = 0; i < npar; i++)
|
||||
h[i][i] = h[i][i]*mult;
|
||||
ill = cholesky_decomp(npar, ch, h);
|
||||
if (!ill) {
|
||||
solve_axb_cholesky(npar, ch, delta, d);
|
||||
for (i = 0; i < npar; i++)
|
||||
newpar[i] = par[i] + delta[i];
|
||||
lmstat->pos.clear();
|
||||
newerr = error_func(newpar, ny, dysq, func, fdata, lmstat);
|
||||
derr = newerr - err;
|
||||
ill = (derr > 0);
|
||||
}
|
||||
if (verbose) { // store iteration, error, gradient, step
|
||||
/*printf("it = %4d, lambda = %10g, err = %10g, derr = %10g (%d)\n", it, lambda, err, derr, !(newerr > err));
|
||||
for (int i = 0; i < npar; ++i) {
|
||||
printf("g[%d] = %g, ", i, g[i]);
|
||||
}
|
||||
printf("\n");*/
|
||||
// main iteration
|
||||
for (it = 0; it < nit; it++) {
|
||||
// calculate the approximation to the Hessian and the "derivative" d
|
||||
for (i = 0; i < npar; i++) {
|
||||
d[i] = 0;
|
||||
for (j = 0; j <= i; j++)
|
||||
h[i][j] = 0;
|
||||
}
|
||||
for (x = 0; x < ny; x++) {
|
||||
if (dysq)
|
||||
weight = 1/dysq[x]; // for weighted least-squares
|
||||
grad(g, par, x, fdata, lmstat);
|
||||
for (i = 0; i < npar; i++) {
|
||||
d[i] += (0.0 - func(par, x, fdata, lmstat)) * g[i] * weight; //(y[x] - func(par, x, fdata)) * g[i] * weight;
|
||||
for (j = 0; j <= i; j++)
|
||||
h[i][j] += g[i] * g[j] * weight;
|
||||
}
|
||||
}
|
||||
// make a step "delta." If the step is rejected, increase lambda and try again
|
||||
mult = 1 + lambda;
|
||||
ill = 1; // ill-conditioned?
|
||||
while (ill && (it < nit)) {
|
||||
for (i = 0; i < npar; i++)
|
||||
h[i][i] = h[i][i]*mult;
|
||||
ill = cholesky_decomp(npar, ch, h);
|
||||
if (!ill) {
|
||||
solve_axb_cholesky(npar, ch, delta, d);
|
||||
for (i = 0; i < npar; i++)
|
||||
newpar[i] = par[i] + delta[i];
|
||||
lmstat->pos.clear();
|
||||
newerr = error_func(newpar, ny, dysq, func, fdata, lmstat);
|
||||
derr = newerr - err;
|
||||
ill = (derr > 0);
|
||||
}
|
||||
if (verbose) { // store iteration, error, gradient, step
|
||||
/*printf("it = %4d, lambda = %10g, err = %10g, derr = %10g (%d)\n", it, lambda, err, derr, !(newerr > err));
|
||||
for (int i = 0; i < npar; ++i) {
|
||||
printf("g[%d] = %g, ", i, g[i]);
|
||||
}
|
||||
printf("\n");*/
|
||||
|
||||
std::ostringstream gString, qString, dString, pString, os;
|
||||
for (i = 0; i < npar; ++i) {
|
||||
gString << g[i];
|
||||
qString << par[i];
|
||||
dString << d[i];
|
||||
if (i + 1 < npar) {
|
||||
gString << ",";
|
||||
qString << ",";
|
||||
dString << ",";
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ny; ++i) {
|
||||
pString << lmstat->pos.at(i).x << "," << lmstat->pos.at(i).y;
|
||||
if (i + 1 < ny) {
|
||||
pString << ",";
|
||||
}
|
||||
}
|
||||
os << it << "," << err << "," << derr << "," << qString.str() << "," << gString.str() << "," << dString.str() << "," << pString.str() << "\n";
|
||||
data.append(os.str());
|
||||
}
|
||||
if (ill) {
|
||||
mult = (1 + lambda * up) / (1 + lambda);
|
||||
lambda *= up;
|
||||
it++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < npar; i++)
|
||||
par[i] = newpar[i];
|
||||
err = newerr;
|
||||
lambda *= down;
|
||||
std::ostringstream gString, qString, dString, pString, os;
|
||||
for (i = 0; i < npar; ++i) {
|
||||
gString << g[i];
|
||||
qString << par[i];
|
||||
dString << d[i];
|
||||
if (i + 1 < npar) {
|
||||
gString << ",";
|
||||
qString << ",";
|
||||
dString << ",";
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ny; ++i) {
|
||||
pString << lmstat->pos.at(i).x << "," << lmstat->pos.at(i).y;
|
||||
if (i + 1 < ny) {
|
||||
pString << ",";
|
||||
}
|
||||
}
|
||||
os << it << "," << err << "," << derr << "," << qString.str() << "," << gString.str() << "," << dString.str() << "," << pString.str() << "\n";
|
||||
data.append(os.str());
|
||||
}
|
||||
if (ill) {
|
||||
mult = (1 + lambda * up) / (1 + lambda);
|
||||
lambda *= up;
|
||||
it++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < npar; i++)
|
||||
par[i] = newpar[i];
|
||||
err = newerr;
|
||||
lambda *= down;
|
||||
|
||||
if ((!ill) && (-derr < target_derr))
|
||||
break;
|
||||
}
|
||||
if ((!ill) && (-derr < target_derr))
|
||||
break;
|
||||
}
|
||||
|
||||
lmstat->final_it = it;
|
||||
lmstat->final_err = err;
|
||||
lmstat->final_derr = derr;
|
||||
lmstat->data = data;
|
||||
lmstat->final_it = it;
|
||||
lmstat->final_err = err;
|
||||
lmstat->final_derr = derr;
|
||||
lmstat->data = data;
|
||||
|
||||
// deallocate the arrays
|
||||
for (i = 0; i < npar; i++) {
|
||||
delete[] h[i];
|
||||
delete[] ch[i];
|
||||
}
|
||||
delete[] h;
|
||||
delete[] ch;
|
||||
delete[] g;
|
||||
delete[] d;
|
||||
delete[] delta;
|
||||
delete[] newpar;
|
||||
// deallocate the arrays
|
||||
for (i = 0; i < npar; i++) {
|
||||
delete[] h[i];
|
||||
delete[] ch[i];
|
||||
}
|
||||
delete[] h;
|
||||
delete[] ch;
|
||||
delete[] g;
|
||||
delete[] d;
|
||||
delete[] delta;
|
||||
delete[] newpar;
|
||||
|
||||
return (it != lmstat->max_it);
|
||||
return (it != lmstat->max_it);
|
||||
}
|
||||
|
||||
|
||||
// calculate the error function (chi-squared)
|
||||
double error_func(double *par, int ny, double *dysq,
|
||||
double (*func)(double *, int, void *, LMstat*), void *fdata, LMstat *lmstat) {
|
||||
int x;
|
||||
double res, e = 0;
|
||||
double (*func)(double *, int, void *, LMstat*), void *fdata, LMstat *lmstat) {
|
||||
int x;
|
||||
double res, e = 0;
|
||||
|
||||
for (x = 0; x < ny; x++) {
|
||||
res = func(par, x, fdata, lmstat);
|
||||
if (dysq) // weighted least-squares
|
||||
e += res*res/dysq[x];
|
||||
else
|
||||
e += res*res;
|
||||
}
|
||||
return e;
|
||||
for (x = 0; x < ny; x++) {
|
||||
res = func(par, x, fdata, lmstat);
|
||||
if (dysq) // weighted least-squares
|
||||
e += res*res/dysq[x];
|
||||
else
|
||||
e += res*res;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
// solve Ax=b for a symmetric positive-definite matrix A using the Cholesky decomposition A=LL^T, L is passed in "l", elements above the diagonal are ignored.
|
||||
void solve_axb_cholesky(int n, double** l, double* x, double* b) { // n = npar, l = ch, x = delta (solution), b = d (func(par, x, fdata) * g[i]);
|
||||
int i, j;
|
||||
double sum;
|
||||
// solve L*y = b for y (where x[] is used to store y)
|
||||
for (i = 0; i < n; i++) {
|
||||
sum = 0;
|
||||
for (j = 0; j < i; j++)
|
||||
sum += l[i][j] * x[j];
|
||||
x[i] = (b[i] - sum) / l[i][i];
|
||||
}
|
||||
// solve L^T*x = y for x (where x[] is used to store both y and x)
|
||||
for (i = n-1; i >= 0; i--) {
|
||||
sum = 0;
|
||||
for (j = i+1; j < n; j++)
|
||||
sum += l[j][i] * x[j];
|
||||
x[i] = (x[i] - sum) / l[i][i];
|
||||
}
|
||||
int i, j;
|
||||
double sum;
|
||||
// solve L*y = b for y (where x[] is used to store y)
|
||||
for (i = 0; i < n; i++) {
|
||||
sum = 0;
|
||||
for (j = 0; j < i; j++)
|
||||
sum += l[i][j] * x[j];
|
||||
x[i] = (b[i] - sum) / l[i][i];
|
||||
}
|
||||
// solve L^T*x = y for x (where x[] is used to store both y and x)
|
||||
for (i = n-1; i >= 0; i--) {
|
||||
sum = 0;
|
||||
for (j = i+1; j < n; j++)
|
||||
sum += l[j][i] * x[j];
|
||||
x[i] = (x[i] - sum) / l[i][i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// symmetric, positive-definite matrix "a" and returns its (lower-triangular) Cholesky factor in "l", if l=a the decomposition is performed in place, elements above the diagonal are ignored.
|
||||
int cholesky_decomp(int n, double** l, double** a) {
|
||||
int i, j, k;
|
||||
double sum;
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < i; j++) {
|
||||
sum = 0;
|
||||
for (k = 0; k < j; k++)
|
||||
sum += l[i][k] * l[j][k];
|
||||
l[i][j] = (a[i][j] - sum) / l[j][j];
|
||||
}
|
||||
sum = 0;
|
||||
for (k = 0; k < i; k++)
|
||||
sum += l[i][k] * l[i][k];
|
||||
sum = a[i][i] - sum;
|
||||
if (sum < TOL)
|
||||
return 1; // not positive-definite
|
||||
l[i][i] = sqrt(sum);
|
||||
}
|
||||
return 0;
|
||||
int i, j, k;
|
||||
double sum;
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < i; j++) {
|
||||
sum = 0;
|
||||
for (k = 0; k < j; k++)
|
||||
sum += l[i][k] * l[j][k];
|
||||
l[i][j] = (a[i][j] - sum) / l[j][j];
|
||||
}
|
||||
sum = 0;
|
||||
for (k = 0; k < i; k++)
|
||||
sum += l[i][k] * l[i][k];
|
||||
sum = a[i][i] - sum;
|
||||
if (sum < TOL)
|
||||
return 1; // not positive-definite
|
||||
l[i][i] = sqrt(sum);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
levmarq.c and levmarq.h are provided under the MIT license.
|
||||
Copyright(c) 2008 - 2016 Ron Babich
|
||||
|
||||
@@ -29,17 +29,17 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
typedef struct {
|
||||
bool verbose;
|
||||
std::string data;
|
||||
std::vector<glm::dvec2> pos;
|
||||
int max_it;
|
||||
double init_lambda;
|
||||
double up_factor;
|
||||
double down_factor;
|
||||
double target_derr;
|
||||
int final_it;
|
||||
double final_err;
|
||||
double final_derr;
|
||||
bool verbose;
|
||||
std::string data;
|
||||
std::vector<glm::dvec2> pos;
|
||||
int max_it;
|
||||
double init_lambda;
|
||||
double up_factor;
|
||||
double down_factor;
|
||||
double target_derr;
|
||||
int final_it;
|
||||
double final_err;
|
||||
double final_derr;
|
||||
} LMstat;
|
||||
|
||||
/**
|
||||
@@ -51,15 +51,15 @@ void levmarq_init(LMstat *lmstat);
|
||||
* Main function call, finds appropriate values for par[nDOF] that manipulates the camera correctly to direct-manipulation
|
||||
*/
|
||||
bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
double (*func)(double *, int, void *, LMstat*),
|
||||
void (*grad)(double *, double *, int, void *, LMstat*),
|
||||
void *fdata, LMstat *lmstat);
|
||||
double (*func)(double *, int, void *, LMstat*),
|
||||
void (*grad)(double *, double *, int, void *, LMstat*),
|
||||
void *fdata, LMstat *lmstat);
|
||||
|
||||
/**
|
||||
* Returns the total L2 error (to be minimized) with each contact point's distance from the projected coordinates depending on par[nDOF].
|
||||
*/
|
||||
double error_func(double *par, int ny, double *dysq,
|
||||
double (*func)(double *, int, void *, LMstat*), void *fdata, LMstat* lmstat);
|
||||
double (*func)(double *, int, void *, LMstat*), void *fdata, LMstat* lmstat);
|
||||
|
||||
void solve_axb_cholesky(int n, double** l, double* x, double* b);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*****************************************************************************************
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
@@ -48,151 +48,151 @@ namespace openspace {
|
||||
|
||||
class TouchInteraction : public properties::PropertyOwner
|
||||
{
|
||||
using Point = std::pair<int, TUIO::TuioPoint>;
|
||||
using Point = std::pair<int, TUIO::TuioPoint>;
|
||||
|
||||
public:
|
||||
TouchInteraction();
|
||||
public:
|
||||
TouchInteraction();
|
||||
|
||||
// for interpretInteraction()
|
||||
enum Type { ROT = 0, PINCH, PAN, ROLL, PICK };
|
||||
// for interpretInteraction()
|
||||
enum Type { ROT = 0, PINCH, PAN, ROLL, PICK };
|
||||
|
||||
// Stores the velocity in all 6DOF
|
||||
struct VelocityStates {
|
||||
glm::dvec2 orbit;
|
||||
double zoom;
|
||||
double roll;
|
||||
glm::dvec2 pan;
|
||||
};
|
||||
// Stores the selected node, the cursor ID as well as the surface coordinates the cursor touched
|
||||
struct SelectedBody {
|
||||
int id;
|
||||
SceneGraphNode* node;
|
||||
glm::dvec3 coordinates;
|
||||
};
|
||||
// Used in the LM algorithm
|
||||
struct FunctionData {
|
||||
std::vector<glm::dvec3> selectedPoints;
|
||||
std::vector<glm::dvec2> screenPoints;
|
||||
int nDOF;
|
||||
glm::dvec2(*castToNDC)(glm::dvec3, Camera&, SceneGraphNode*);
|
||||
double(*distToMinimize)(double* par, int x, void* fdata, LMstat* lmstat);
|
||||
Camera* camera;
|
||||
SceneGraphNode* node;
|
||||
LMstat stats;
|
||||
double objectScreenRadius;
|
||||
};
|
||||
// Stores the velocity in all 6DOF
|
||||
struct VelocityStates {
|
||||
glm::dvec2 orbit;
|
||||
double zoom;
|
||||
double roll;
|
||||
glm::dvec2 pan;
|
||||
};
|
||||
// Stores the selected node, the cursor ID as well as the surface coordinates the cursor touched
|
||||
struct SelectedBody {
|
||||
int id;
|
||||
SceneGraphNode* node;
|
||||
glm::dvec3 coordinates;
|
||||
};
|
||||
// Used in the LM algorithm
|
||||
struct FunctionData {
|
||||
std::vector<glm::dvec3> selectedPoints;
|
||||
std::vector<glm::dvec2> screenPoints;
|
||||
int nDOF;
|
||||
glm::dvec2(*castToNDC)(glm::dvec3, Camera&, SceneGraphNode*);
|
||||
double(*distToMinimize)(double* par, int x, void* fdata, LMstat* lmstat);
|
||||
Camera* camera;
|
||||
SceneGraphNode* node;
|
||||
LMstat stats;
|
||||
double objectScreenRadius;
|
||||
};
|
||||
|
||||
/* Main function call
|
||||
* 1, Checks if doubleTap occured
|
||||
* 2, Goes through the guiMode() function
|
||||
* 3, Continues if GUI isn't on
|
||||
* 4, If the node in focus is large enough and all contact points have selected it,
|
||||
* calls directControl() function for direct-manipulation
|
||||
* 5, Updates std::vector<SelectedBody> _selected (only if LMA successfully
|
||||
* converged, avoids interaction to snap on LMA fails)
|
||||
* 6, If directControl() wasn't called this frame, interpret the incoming
|
||||
* list and decide what type of interaction this frame should do
|
||||
* 7, Compute the new total velocities after interaction
|
||||
* 8, Evaluate if directControl should be called next frame - true if all contact points
|
||||
* select the same node and said node is larger than _nodeRadiusThreshold
|
||||
*/
|
||||
void updateStateFromInput(const std::vector<TUIO::TuioCursor>& list, std::vector<Point>& lastProcessed);
|
||||
/* Main function call
|
||||
* 1, Checks if doubleTap occured
|
||||
* 2, Goes through the guiMode() function
|
||||
* 3, Continues if GUI isn't on
|
||||
* 4, If the node in focus is large enough and all contact points have selected it,
|
||||
* calls directControl() function for direct-manipulation
|
||||
* 5, Updates std::vector<SelectedBody> _selected (only if LMA successfully
|
||||
* converged, avoids interaction to snap on LMA fails)
|
||||
* 6, If directControl() wasn't called this frame, interpret the incoming
|
||||
* list and decide what type of interaction this frame should do
|
||||
* 7, Compute the new total velocities after interaction
|
||||
* 8, Evaluate if directControl should be called next frame - true if all contact points
|
||||
* select the same node and said node is larger than _nodeRadiusThreshold
|
||||
*/
|
||||
void updateStateFromInput(const std::vector<TUIO::TuioCursor>& list, std::vector<Point>& lastProcessed);
|
||||
|
||||
/* Calculates the new camera state with velocities and time since last frame */
|
||||
void step(double dt);
|
||||
/* Calculates the new camera state with velocities and time since last frame */
|
||||
void step(double dt);
|
||||
|
||||
/* Used to save LMA data for one frame if the user chose to */
|
||||
void unitTest();
|
||||
/* Used to save LMA data for one frame if the user chose to */
|
||||
void unitTest();
|
||||
|
||||
/* Called each frame we have no new input, used to reset data */
|
||||
void resetAfterInput();
|
||||
/* Called each frame we have no new input, used to reset data */
|
||||
void resetAfterInput();
|
||||
|
||||
/* Sets _tap to true, called if tap occured current frame (called from touchmodule) */
|
||||
void tap();
|
||||
/* Set touchactive as true from the touchmodule if incoming list isn't empty, used to void mouse input */
|
||||
void touchActive(bool active);
|
||||
/* Sets _tap to true, called if tap occured current frame (called from touchmodule) */
|
||||
void tap();
|
||||
/* Set touchactive as true from the touchmodule if incoming list isn't empty, used to void mouse input */
|
||||
void touchActive(bool active);
|
||||
|
||||
// Get & Setters
|
||||
Camera* getCamera();
|
||||
SceneGraphNode* getFocusNode();
|
||||
void setFocusNode(SceneGraphNode* focusNode);
|
||||
void setCamera(Camera* cam);
|
||||
// Get & Setters
|
||||
Camera* getCamera();
|
||||
SceneGraphNode* getFocusNode();
|
||||
void setFocusNode(SceneGraphNode* focusNode);
|
||||
void setCamera(Camera* cam);
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
/* Returns true if we have the GUI window open
|
||||
If so, emulates the incoming touch input to a mouse such that we can interact with the GUI
|
||||
*/
|
||||
bool guiMode(const std::vector<TUIO::TuioCursor>& list);
|
||||
/* Returns true if we have the GUI window open
|
||||
If so, emulates the incoming touch input to a mouse such that we can interact with the GUI
|
||||
*/
|
||||
bool guiMode(const std::vector<TUIO::TuioCursor>& list);
|
||||
|
||||
/* Function that calculates the new camera state such that it minimizes the L2 error in screenspace
|
||||
* between contact points and surface coordinates projected to clip space using LMA
|
||||
*/
|
||||
void directControl(const std::vector<TUIO::TuioCursor>& list);
|
||||
/* Function that calculates the new camera state such that it minimizes the L2 error in screenspace
|
||||
* between contact points and surface coordinates projected to clip space using LMA
|
||||
*/
|
||||
void directControl(const std::vector<TUIO::TuioCursor>& list);
|
||||
|
||||
/* Traces each contact point into the scene as a ray
|
||||
* if the ray hits a node, save the id, node and surface coordinates the cursor hit in the list _selected
|
||||
*/
|
||||
void findSelectedNode(const std::vector<TUIO::TuioCursor>& list);
|
||||
/* Traces each contact point into the scene as a ray
|
||||
* if the ray hits a node, save the id, node and surface coordinates the cursor hit in the list _selected
|
||||
*/
|
||||
void findSelectedNode(const std::vector<TUIO::TuioCursor>& list);
|
||||
|
||||
/* Returns an int (ROT = 0, PINCH, PAN, ROLL, PICK) for what interaction to be used,
|
||||
depending on what input was gotten */
|
||||
int interpretInteraction(const std::vector<TUIO::TuioCursor>& list, const std::vector<Point>& lastProcessed);
|
||||
/* Returns an int (ROT = 0, PINCH, PAN, ROLL, PICK) for what interaction to be used,
|
||||
depending on what input was gotten */
|
||||
int interpretInteraction(const std::vector<TUIO::TuioCursor>& list, const std::vector<Point>& lastProcessed);
|
||||
|
||||
/* Compute new velocity according to the interpreted action */
|
||||
void computeVelocities(const std::vector<TUIO::TuioCursor>& list, const std::vector<Point>& lastProcessed);
|
||||
/* Compute new velocity according to the interpreted action */
|
||||
void computeVelocities(const std::vector<TUIO::TuioCursor>& list, const std::vector<Point>& lastProcessed);
|
||||
|
||||
/* Decelerate the velocities,
|
||||
* function is called in step() but is dereferenced from frame time to assure same behaviour on all systems
|
||||
*/
|
||||
void decelerate(double dt);
|
||||
/* Decelerate the velocities,
|
||||
* function is called in step() but is dereferenced from frame time to assure same behaviour on all systems
|
||||
*/
|
||||
void decelerate(double dt);
|
||||
|
||||
/* Resets all properties that can be changed in the GUI to default */
|
||||
void resetToDefault();
|
||||
/* Resets all properties that can be changed in the GUI to default */
|
||||
void resetToDefault();
|
||||
|
||||
Camera* _camera;
|
||||
SceneGraphNode* _focusNode = nullptr;
|
||||
Camera* _camera;
|
||||
SceneGraphNode* _focusNode = nullptr;
|
||||
|
||||
// Property variables
|
||||
properties::StringProperty _origin;
|
||||
properties::BoolProperty _unitTest;
|
||||
properties::BoolProperty _touchActive;
|
||||
properties::BoolProperty _reset;
|
||||
properties::IntProperty _maxTapTime;
|
||||
properties::IntProperty _deceleratesPerSecond;
|
||||
properties::FloatProperty _touchScreenSize;
|
||||
properties::FloatProperty _tapZoomFactor;
|
||||
properties::FloatProperty _nodeRadiusThreshold;
|
||||
properties::FloatProperty _rollAngleThreshold;
|
||||
properties::FloatProperty _orbitSpeedThreshold;
|
||||
properties::FloatProperty _spinSensitivity;
|
||||
properties::FloatProperty _inputStillThreshold;
|
||||
properties::FloatProperty _centroidStillThreshold;
|
||||
properties::FloatProperty _interpretPan;
|
||||
properties::FloatProperty _slerpTime;
|
||||
properties::IVec2Property _guiButton;
|
||||
properties::Vec4Property _friction;
|
||||
// Property variables
|
||||
properties::StringProperty _origin;
|
||||
properties::BoolProperty _unitTest;
|
||||
properties::BoolProperty _touchActive;
|
||||
properties::BoolProperty _reset;
|
||||
properties::IntProperty _maxTapTime;
|
||||
properties::IntProperty _deceleratesPerSecond;
|
||||
properties::FloatProperty _touchScreenSize;
|
||||
properties::FloatProperty _tapZoomFactor;
|
||||
properties::FloatProperty _nodeRadiusThreshold;
|
||||
properties::FloatProperty _rollAngleThreshold;
|
||||
properties::FloatProperty _orbitSpeedThreshold;
|
||||
properties::FloatProperty _spinSensitivity;
|
||||
properties::FloatProperty _inputStillThreshold;
|
||||
properties::FloatProperty _centroidStillThreshold;
|
||||
properties::FloatProperty _interpretPan;
|
||||
properties::FloatProperty _slerpTime;
|
||||
properties::IVec2Property _guiButton;
|
||||
properties::Vec4Property _friction;
|
||||
|
||||
// Class variables
|
||||
VelocityStates _vel;
|
||||
VelocityStates _lastVel;
|
||||
VelocityStates _sensitivity;
|
||||
// Class variables
|
||||
VelocityStates _vel;
|
||||
VelocityStates _lastVel;
|
||||
VelocityStates _sensitivity;
|
||||
|
||||
double _projectionScaleFactor;
|
||||
double _currentRadius;
|
||||
double _slerpdT;
|
||||
double _timeSlack;
|
||||
int _numOfTests;
|
||||
TUIO::TuioTime _time;
|
||||
bool _directTouchMode;
|
||||
bool _tap;
|
||||
bool _doubleTap;
|
||||
bool _lmSuccess;
|
||||
bool _guiON;
|
||||
std::vector<SelectedBody> _selected;
|
||||
LMstat _lmstat;
|
||||
glm::dquat _toSlerp;
|
||||
glm::dvec3 _centroid;
|
||||
double _projectionScaleFactor;
|
||||
double _currentRadius;
|
||||
double _slerpdT;
|
||||
double _timeSlack;
|
||||
int _numOfTests;
|
||||
TUIO::TuioTime _time;
|
||||
bool _directTouchMode;
|
||||
bool _tap;
|
||||
bool _doubleTap;
|
||||
bool _lmSuccess;
|
||||
bool _guiON;
|
||||
std::vector<SelectedBody> _selected;
|
||||
LMstat _lmstat;
|
||||
glm::dquat _toSlerp;
|
||||
glm::dvec3 _centroid;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*****************************************************************************************
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
namespace ghoul {
|
||||
namespace opengl {
|
||||
class ProgramObject;
|
||||
class ProgramObject;
|
||||
} // namespace opengl
|
||||
} // namespace ghoul
|
||||
|
||||
@@ -52,29 +52,29 @@ namespace openspace {
|
||||
|
||||
class TouchMarker : public properties::PropertyOwner
|
||||
{
|
||||
public:
|
||||
TouchMarker();
|
||||
public:
|
||||
TouchMarker();
|
||||
|
||||
bool initialize();
|
||||
bool deinitialize();
|
||||
bool initialize();
|
||||
bool deinitialize();
|
||||
|
||||
void render(const std::vector<TUIO::TuioCursor> list);
|
||||
void render(const std::vector<TUIO::TuioCursor> list);
|
||||
|
||||
|
||||
private:
|
||||
void createVertexList(const std::vector<TUIO::TuioCursor> list);
|
||||
private:
|
||||
void createVertexList(const std::vector<TUIO::TuioCursor> list);
|
||||
|
||||
properties::BoolProperty _visible;
|
||||
properties::FloatProperty _radiusSize;
|
||||
properties::FloatProperty _transparency;
|
||||
properties::FloatProperty _thickness;
|
||||
properties::Vec3Property _color;
|
||||
properties::BoolProperty _visible;
|
||||
properties::FloatProperty _radiusSize;
|
||||
properties::FloatProperty _transparency;
|
||||
properties::FloatProperty _thickness;
|
||||
properties::Vec3Property _color;
|
||||
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _shader;
|
||||
|
||||
GLuint _quad;
|
||||
GLuint _vertexPositionBuffer;
|
||||
int _numFingers;
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _shader;
|
||||
|
||||
GLuint _quad;
|
||||
GLuint _vertexPositionBuffer;
|
||||
int _numFingers;
|
||||
};
|
||||
|
||||
} // openspace namespace
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*****************************************************************************************
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
@@ -40,68 +40,68 @@
|
||||
|
||||
|
||||
class TuioEar : public TUIO::TuioListener {
|
||||
|
||||
public:
|
||||
TuioEar();
|
||||
~TuioEar() {
|
||||
_tuioClient->disconnect();
|
||||
delete _tuioClient;
|
||||
delete _oscReceiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback functions, listens to the TUIO server
|
||||
*/
|
||||
void addTuioObject(TUIO::TuioObject *tobj);
|
||||
void updateTuioObject(TUIO::TuioObject *tobj);
|
||||
void removeTuioObject(TUIO::TuioObject *tobj);
|
||||
|
||||
public:
|
||||
TuioEar();
|
||||
~TuioEar() {
|
||||
_tuioClient->disconnect();
|
||||
delete _tuioClient;
|
||||
delete _oscReceiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback functions, listens to the TUIO server
|
||||
*/
|
||||
void addTuioObject(TUIO::TuioObject *tobj);
|
||||
void updateTuioObject(TUIO::TuioObject *tobj);
|
||||
void removeTuioObject(TUIO::TuioObject *tobj);
|
||||
|
||||
void addTuioCursor(TUIO::TuioCursor *tcur);
|
||||
void updateTuioCursor(TUIO::TuioCursor *tcur);
|
||||
void removeTuioCursor(TUIO::TuioCursor *tcur);
|
||||
void addTuioCursor(TUIO::TuioCursor *tcur);
|
||||
void updateTuioCursor(TUIO::TuioCursor *tcur);
|
||||
void removeTuioCursor(TUIO::TuioCursor *tcur);
|
||||
|
||||
void addTuioBlob(TUIO::TuioBlob *tblb);
|
||||
void updateTuioBlob(TUIO::TuioBlob *tblb);
|
||||
void removeTuioBlob(TUIO::TuioBlob *tblb);
|
||||
void addTuioBlob(TUIO::TuioBlob *tblb);
|
||||
void updateTuioBlob(TUIO::TuioBlob *tblb);
|
||||
void removeTuioBlob(TUIO::TuioBlob *tblb);
|
||||
|
||||
void refresh(TUIO::TuioTime frameTime);
|
||||
void refresh(TUIO::TuioTime frameTime);
|
||||
|
||||
/**
|
||||
* Returns a list of all touch history that happened since the last frame
|
||||
*/
|
||||
std::vector<TUIO::TuioCursor> getInput();
|
||||
/**
|
||||
* Returns a list of all touch history that happened since the last frame
|
||||
*/
|
||||
std::vector<TUIO::TuioCursor> getInput();
|
||||
|
||||
/**
|
||||
* Returns true if a tap occured since the last frame
|
||||
*/
|
||||
bool tap();
|
||||
/**
|
||||
* Returns true if a tap occured since the last frame
|
||||
*/
|
||||
bool tap();
|
||||
|
||||
/**
|
||||
* Returns tap's cursor coordinates and time information
|
||||
*/
|
||||
TUIO::TuioCursor getTap();
|
||||
/**
|
||||
* Returns tap's cursor coordinates and time information
|
||||
*/
|
||||
TUIO::TuioCursor getTap();
|
||||
|
||||
/**
|
||||
* Clears the input list, function called after getInput() each frame
|
||||
*/
|
||||
void clearInput();
|
||||
|
||||
private:
|
||||
bool _tap;
|
||||
TUIO::TuioCursor _tapCo = TUIO::TuioCursor(-1, -1, -1.0f, -1.0f);
|
||||
std::mutex _mx;
|
||||
/**
|
||||
* Clears the input list, function called after getInput() each frame
|
||||
*/
|
||||
void clearInput();
|
||||
|
||||
private:
|
||||
bool _tap;
|
||||
TUIO::TuioCursor _tapCo = TUIO::TuioCursor(-1, -1, -1.0f, -1.0f);
|
||||
std::mutex _mx;
|
||||
|
||||
TUIO::TuioClient *_tuioClient;
|
||||
TUIO::OscReceiver *_oscReceiver;
|
||||
TUIO::TuioClient *_tuioClient;
|
||||
TUIO::OscReceiver *_oscReceiver;
|
||||
|
||||
|
||||
std::vector<TUIO::TuioCursor> _list;
|
||||
|
||||
std::vector<TUIO::TuioCursor> _list;
|
||||
|
||||
/**
|
||||
* A list that tracks all of the cursor ID's that got removed since last frame
|
||||
*/
|
||||
std::vector<int> _removeList;
|
||||
|
||||
/**
|
||||
* A list that tracks all of the cursor ID's that got removed since last frame
|
||||
*/
|
||||
std::vector<int> _removeList;
|
||||
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_MODULE_TOUCH___TOUCHWRAPPER___H__
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/*****************************************************************************************
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
@@ -32,111 +32,111 @@
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TouchMarker";
|
||||
const int MAX_FINGERS = 20;
|
||||
const std::string _loggerCat = "TouchMarker";
|
||||
const int MAX_FINGERS = 20;
|
||||
}
|
||||
namespace openspace {
|
||||
|
||||
TouchMarker::TouchMarker()
|
||||
: properties::PropertyOwner("TouchMarker")
|
||||
, _visible("TouchMarkers visible", "Toggle visibility of markers", true)
|
||||
, _radiusSize("Marker size", "Marker radius", 30, 0, 100)
|
||||
, _transparency("Transparency of marker", "Marker transparency", 0.8, 0, 1.0)
|
||||
, _thickness("Thickness of marker", "Marker thickness", 2.0, 0, 4.0)
|
||||
, _color(
|
||||
"MarkerColor",
|
||||
"Marker color",
|
||||
glm::vec3(204.f / 255.f, 51.f / 255.f, 51.f / 255.f),
|
||||
glm::vec3(0.f),
|
||||
glm::vec3(1.f)
|
||||
)
|
||||
, _shader(nullptr)
|
||||
, _numFingers(0)
|
||||
: properties::PropertyOwner("TouchMarker")
|
||||
, _visible("TouchMarkers visible", "Toggle visibility of markers", true)
|
||||
, _radiusSize("Marker size", "Marker radius", 30, 0, 100)
|
||||
, _transparency("Transparency of marker", "Marker transparency", 0.8, 0, 1.0)
|
||||
, _thickness("Thickness of marker", "Marker thickness", 2.0, 0, 4.0)
|
||||
, _color(
|
||||
"MarkerColor",
|
||||
"Marker color",
|
||||
glm::vec3(204.f / 255.f, 51.f / 255.f, 51.f / 255.f),
|
||||
glm::vec3(0.f),
|
||||
glm::vec3(1.f)
|
||||
)
|
||||
, _shader(nullptr)
|
||||
, _numFingers(0)
|
||||
{
|
||||
addProperty(_visible);
|
||||
addProperty(_radiusSize);
|
||||
addProperty(_transparency);
|
||||
addProperty(_thickness);
|
||||
_color.setViewOption(properties::Property::ViewOptions::Color);
|
||||
addProperty(_color);
|
||||
|
||||
addProperty(_visible);
|
||||
addProperty(_radiusSize);
|
||||
addProperty(_transparency);
|
||||
addProperty(_thickness);
|
||||
_color.setViewOption(properties::Property::ViewOptions::Color);
|
||||
addProperty(_color);
|
||||
|
||||
}
|
||||
|
||||
bool TouchMarker::initialize() {
|
||||
glGenVertexArrays(1, &_quad); // generate array
|
||||
glGenBuffers(1, &_vertexPositionBuffer); // generate buffer
|
||||
glGenVertexArrays(1, &_quad); // generate array
|
||||
glGenBuffers(1, &_vertexPositionBuffer); // generate buffer
|
||||
|
||||
try {
|
||||
_shader = OsEng.renderEngine().buildRenderProgram("MarkerProgram",
|
||||
"${MODULE_TOUCH}/shaders/marker_vs.glsl",
|
||||
"${MODULE_TOUCH}/shaders/marker_fs.glsl"
|
||||
);
|
||||
}
|
||||
catch (const ghoul::opengl::ShaderObject::ShaderCompileError& e) {
|
||||
LERRORC(e.component, e.what());
|
||||
}
|
||||
return (_shader != nullptr);
|
||||
try {
|
||||
_shader = OsEng.renderEngine().buildRenderProgram("MarkerProgram",
|
||||
"${MODULE_TOUCH}/shaders/marker_vs.glsl",
|
||||
"${MODULE_TOUCH}/shaders/marker_fs.glsl"
|
||||
);
|
||||
}
|
||||
catch (const ghoul::opengl::ShaderObject::ShaderCompileError& e) {
|
||||
LERRORC(e.component, e.what());
|
||||
}
|
||||
return (_shader != nullptr);
|
||||
}
|
||||
|
||||
bool TouchMarker::deinitialize() {
|
||||
glDeleteVertexArrays(1, &_quad);
|
||||
_quad = 0;
|
||||
glDeleteVertexArrays(1, &_quad);
|
||||
_quad = 0;
|
||||
|
||||
glDeleteBuffers(1, &_vertexPositionBuffer);
|
||||
_vertexPositionBuffer = 0;
|
||||
glDeleteBuffers(1, &_vertexPositionBuffer);
|
||||
_vertexPositionBuffer = 0;
|
||||
|
||||
RenderEngine& renderEngine = OsEng.renderEngine();
|
||||
if (_shader) {
|
||||
renderEngine.removeRenderProgram(_shader);
|
||||
_shader = nullptr;
|
||||
}
|
||||
return true;
|
||||
RenderEngine& renderEngine = OsEng.renderEngine();
|
||||
if (_shader) {
|
||||
renderEngine.removeRenderProgram(_shader);
|
||||
_shader = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TouchMarker::render(const std::vector<TUIO::TuioCursor> list) {
|
||||
if (_visible && !list.empty()) {
|
||||
createVertexList(list);
|
||||
_shader->activate();
|
||||
if (_visible && !list.empty()) {
|
||||
createVertexList(list);
|
||||
_shader->activate();
|
||||
|
||||
_shader->setUniform("radius", _radiusSize);
|
||||
_shader->setUniform("transparency", _transparency);
|
||||
_shader->setUniform("thickness", _thickness);
|
||||
_shader->setUniform("color", _color.value());
|
||||
_shader->setUniform("radius", _radiusSize);
|
||||
_shader->setUniform("transparency", _transparency);
|
||||
_shader->setUniform("thickness", _thickness);
|
||||
_shader->setUniform("color", _color.value());
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_PROGRAM_POINT_SIZE); // Enable gl_PointSize in vertex shader
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
|
||||
glBindVertexArray(_quad);
|
||||
glDrawArrays(GL_POINTS, 0, _numFingers);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_PROGRAM_POINT_SIZE); // Enable gl_PointSize in vertex shader
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
|
||||
glBindVertexArray(_quad);
|
||||
glDrawArrays(GL_POINTS, 0, _numFingers);
|
||||
|
||||
_shader->deactivate();
|
||||
}
|
||||
_shader->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void TouchMarker::createVertexList(const std::vector<TUIO::TuioCursor> list) {
|
||||
_numFingers = list.size();
|
||||
GLfloat vertexData[MAX_FINGERS];
|
||||
int i = 0;
|
||||
for (const TUIO::TuioCursor& c : list) {
|
||||
vertexData[i] = 2 * (c.getX() - 0.5);
|
||||
vertexData[i + 1] = -2 * (c.getY() - 0.5);
|
||||
i += 2;
|
||||
}
|
||||
_numFingers = list.size();
|
||||
GLfloat vertexData[MAX_FINGERS];
|
||||
int i = 0;
|
||||
for (const TUIO::TuioCursor& c : list) {
|
||||
vertexData[i] = 2 * (c.getX() - 0.5);
|
||||
vertexData[i + 1] = -2 * (c.getY() - 0.5);
|
||||
i += 2;
|
||||
}
|
||||
|
||||
glBindVertexArray(_quad);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(
|
||||
0,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
0,
|
||||
0
|
||||
);
|
||||
glBindVertexArray(_quad);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(
|
||||
0,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
} // openspace namespace
|
||||
@@ -1,4 +1,4 @@
|
||||
/*****************************************************************************************
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
using namespace TUIO;
|
||||
namespace {
|
||||
const std::string _loggerCat = "TuioEar";
|
||||
const std::string _loggerCat = "TuioEar";
|
||||
}
|
||||
|
||||
void TuioEar::addTuioObject(TuioObject *tobj) { }
|
||||
@@ -45,61 +45,61 @@ void TuioEar::updateTuioObject(TuioObject *tobj) { }
|
||||
void TuioEar::removeTuioObject(TuioObject *tobj) { }
|
||||
|
||||
void TuioEar::addTuioCursor(TuioCursor *tcur) {
|
||||
_mx.lock();
|
||||
_tap = false;
|
||||
// find same id in _list if it exists in _removeList (new input with same ID as a previously stored)
|
||||
int i = tcur->getSessionID();
|
||||
std::vector<int>::iterator foundID = std::find_if(
|
||||
_removeList.begin(),
|
||||
_removeList.end(),
|
||||
[&i](int id) { return id == i; });
|
||||
_mx.lock();
|
||||
_tap = false;
|
||||
// find same id in _list if it exists in _removeList (new input with same ID as a previously stored)
|
||||
int i = tcur->getSessionID();
|
||||
std::vector<int>::iterator foundID = std::find_if(
|
||||
_removeList.begin(),
|
||||
_removeList.end(),
|
||||
[&i](int id) { return id == i; });
|
||||
|
||||
// if found, remove id from _removeList and update, otherwise add new id to list
|
||||
if (foundID != _removeList.end()) {
|
||||
std::find_if(
|
||||
_list.begin(),
|
||||
_list.end(),
|
||||
[&i](const TuioCursor& cursor) {
|
||||
return cursor.getSessionID() == i;
|
||||
})->update(tcur);
|
||||
_removeList.erase(foundID);
|
||||
}
|
||||
else {
|
||||
_list.push_back(TuioCursor(*tcur));
|
||||
}
|
||||
_mx.unlock();
|
||||
// if found, remove id from _removeList and update, otherwise add new id to list
|
||||
if (foundID != _removeList.end()) {
|
||||
std::find_if(
|
||||
_list.begin(),
|
||||
_list.end(),
|
||||
[&i](const TuioCursor& cursor) {
|
||||
return cursor.getSessionID() == i;
|
||||
})->update(tcur);
|
||||
_removeList.erase(foundID);
|
||||
}
|
||||
else {
|
||||
_list.push_back(TuioCursor(*tcur));
|
||||
}
|
||||
_mx.unlock();
|
||||
}
|
||||
|
||||
void TuioEar::updateTuioCursor(TuioCursor *tcur) {
|
||||
_mx.lock();
|
||||
_tap = false;
|
||||
int i = tcur->getSessionID();
|
||||
std::find_if(
|
||||
_list.begin(),
|
||||
_list.end(),
|
||||
[&i](const TuioCursor& cursor) {
|
||||
return cursor.getSessionID() == i;
|
||||
})->update(tcur);
|
||||
_mx.unlock();
|
||||
_mx.lock();
|
||||
_tap = false;
|
||||
int i = tcur->getSessionID();
|
||||
std::find_if(
|
||||
_list.begin(),
|
||||
_list.end(),
|
||||
[&i](const TuioCursor& cursor) {
|
||||
return cursor.getSessionID() == i;
|
||||
})->update(tcur);
|
||||
_mx.unlock();
|
||||
}
|
||||
|
||||
// save id to be removed and remove it in clearInput
|
||||
void TuioEar::removeTuioCursor(TuioCursor *tcur) {
|
||||
_mx.lock();
|
||||
_removeList.push_back(tcur->getSessionID());
|
||||
_mx.lock();
|
||||
_removeList.push_back(tcur->getSessionID());
|
||||
|
||||
// Check if the cursor ID could be considered a tap
|
||||
double dist = 0;
|
||||
for (const TuioPoint& p : tcur->getPath()) {
|
||||
dist += glm::length(glm::dvec2(p.getX(), p.getY()) - glm::dvec2(tcur->getX(), tcur->getY()));
|
||||
}
|
||||
dist /= tcur->getPath().size();
|
||||
double heldTime = tcur->getPath().back().getTuioTime().getTotalMilliseconds() - tcur->getPath().front().getTuioTime().getTotalMilliseconds();
|
||||
if (heldTime < 180 && dist < 0.0004 && _list.size() == 1 && _removeList.size() == 1) {
|
||||
_tapCo = TuioCursor(*tcur);
|
||||
_tap = true;
|
||||
}
|
||||
_mx.unlock();
|
||||
// Check if the cursor ID could be considered a tap
|
||||
double dist = 0;
|
||||
for (const TuioPoint& p : tcur->getPath()) {
|
||||
dist += glm::length(glm::dvec2(p.getX(), p.getY()) - glm::dvec2(tcur->getX(), tcur->getY()));
|
||||
}
|
||||
dist /= tcur->getPath().size();
|
||||
double heldTime = tcur->getPath().back().getTuioTime().getTotalMilliseconds() - tcur->getPath().front().getTuioTime().getTotalMilliseconds();
|
||||
if (heldTime < 180 && dist < 0.0004 && _list.size() == 1 && _removeList.size() == 1) {
|
||||
_tapCo = TuioCursor(*tcur);
|
||||
_tap = true;
|
||||
}
|
||||
_mx.unlock();
|
||||
}
|
||||
|
||||
void TuioEar::addTuioBlob(TuioBlob *tblb) { }
|
||||
@@ -111,52 +111,52 @@ void TuioEar::removeTuioBlob(TuioBlob *tblb) { }
|
||||
void TuioEar::refresh(TuioTime frameTime) { } // about every 15ms
|
||||
|
||||
std::vector<TuioCursor> TuioEar::getInput() {
|
||||
std::lock_guard<std::mutex> lock(_mx);
|
||||
return _list;
|
||||
std::lock_guard<std::mutex> lock(_mx);
|
||||
return _list;
|
||||
}
|
||||
|
||||
bool TuioEar::tap() {
|
||||
std::lock_guard<std::mutex> lock(_mx);
|
||||
if (_tap) {
|
||||
_tap = false;
|
||||
return !_tap;
|
||||
}
|
||||
else {
|
||||
return _tap;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(_mx);
|
||||
if (_tap) {
|
||||
_tap = false;
|
||||
return !_tap;
|
||||
}
|
||||
else {
|
||||
return _tap;
|
||||
}
|
||||
}
|
||||
|
||||
TuioCursor TuioEar::getTap() {
|
||||
std::lock_guard<std::mutex> lock(_mx);
|
||||
return _tapCo;
|
||||
std::lock_guard<std::mutex> lock(_mx);
|
||||
return _tapCo;
|
||||
}
|
||||
|
||||
// Removes all cursor ID from list that exists in _removeList
|
||||
void TuioEar::clearInput() {
|
||||
_mx.lock();
|
||||
_list.erase(
|
||||
std::remove_if(
|
||||
_list.begin(),
|
||||
_list.end(),
|
||||
[this](const TuioCursor& cursor) {
|
||||
return std::find_if(
|
||||
_removeList.begin(),
|
||||
_removeList.end(),
|
||||
[&cursor](int id) {
|
||||
return cursor.getSessionID() == id;
|
||||
}
|
||||
) != _removeList.end();
|
||||
}),
|
||||
_list.end()
|
||||
);
|
||||
_removeList.clear();
|
||||
_mx.unlock();
|
||||
_mx.lock();
|
||||
_list.erase(
|
||||
std::remove_if(
|
||||
_list.begin(),
|
||||
_list.end(),
|
||||
[this](const TuioCursor& cursor) {
|
||||
return std::find_if(
|
||||
_removeList.begin(),
|
||||
_removeList.end(),
|
||||
[&cursor](int id) {
|
||||
return cursor.getSessionID() == id;
|
||||
}
|
||||
) != _removeList.end();
|
||||
}),
|
||||
_list.end()
|
||||
);
|
||||
_removeList.clear();
|
||||
_mx.unlock();
|
||||
}
|
||||
|
||||
// Standard UDP IP connection to port 3333
|
||||
TuioEar::TuioEar() {
|
||||
_oscReceiver = new UdpReceiver(3333);
|
||||
_tuioClient = new TuioClient(_oscReceiver);
|
||||
_tuioClient->addTuioListener(this);
|
||||
_tuioClient->connect();
|
||||
_oscReceiver = new UdpReceiver(3333);
|
||||
_tuioClient = new TuioClient(_oscReceiver);
|
||||
_tuioClient->addTuioListener(this);
|
||||
_tuioClient->connect();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/*****************************************************************************************
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
@@ -41,114 +41,114 @@
|
||||
using namespace TUIO;
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TouchModule";
|
||||
const std::string _loggerCat = "TouchModule";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
|
||||
bool TouchModule::hasNewInput() {
|
||||
// Get new input from listener
|
||||
listOfContactPoints = ear.getInput();
|
||||
ear.clearInput();
|
||||
touch.touchActive(!listOfContactPoints.empty()); // Set touch property to active (to void mouse input, mainly for mtdev bridges)
|
||||
// Get new input from listener
|
||||
listOfContactPoints = ear.getInput();
|
||||
ear.clearInput();
|
||||
touch.touchActive(!listOfContactPoints.empty()); // Set touch property to active (to void mouse input, mainly for mtdev bridges)
|
||||
|
||||
// Erase old input id's that no longer exists
|
||||
lastProcessed.erase(
|
||||
std::remove_if(
|
||||
lastProcessed.begin(),
|
||||
lastProcessed.end(),
|
||||
[this](const Point& point) {
|
||||
return std::find_if(
|
||||
listOfContactPoints.begin(),
|
||||
listOfContactPoints.end(),
|
||||
[&point](const TuioCursor& c) {
|
||||
return point.first == c.getSessionID();
|
||||
}
|
||||
) == listOfContactPoints.end(); }),
|
||||
lastProcessed.end());
|
||||
// Erase old input id's that no longer exists
|
||||
lastProcessed.erase(
|
||||
std::remove_if(
|
||||
lastProcessed.begin(),
|
||||
lastProcessed.end(),
|
||||
[this](const Point& point) {
|
||||
return std::find_if(
|
||||
listOfContactPoints.begin(),
|
||||
listOfContactPoints.end(),
|
||||
[&point](const TuioCursor& c) {
|
||||
return point.first == c.getSessionID();
|
||||
}
|
||||
) == listOfContactPoints.end(); }),
|
||||
lastProcessed.end());
|
||||
|
||||
// if tap occured, we have new input
|
||||
if (listOfContactPoints.empty() && lastProcessed.empty() && ear.tap()) {
|
||||
TuioCursor c = ear.getTap();
|
||||
listOfContactPoints.push_back(c);
|
||||
// if tap occured, we have new input
|
||||
if (listOfContactPoints.empty() && lastProcessed.empty() && ear.tap()) {
|
||||
TuioCursor c = ear.getTap();
|
||||
listOfContactPoints.push_back(c);
|
||||
lastProcessed.emplace_back(c.getSessionID(), c.getPath().back());
|
||||
touch.tap();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return true if we got new input
|
||||
if (listOfContactPoints.size() == lastProcessed.size() && !listOfContactPoints.empty()) {
|
||||
bool newInput = true;
|
||||
// go through list and check if the last registrered time is newer than the one in lastProcessed (last frame)
|
||||
std::for_each(lastProcessed.begin(), lastProcessed.end(), [this, &newInput](Point& p) {
|
||||
std::vector<TuioCursor>::iterator cursor = std::find_if(listOfContactPoints.begin(), listOfContactPoints.end(),
|
||||
[&p](const TuioCursor& c) { return c.getSessionID() == p.first; });
|
||||
double now = cursor->getPath().back().getTuioTime().getTotalMilliseconds();
|
||||
if (!cursor->isMoving()) { // if current cursor isn't moving, we want to interpret that as new input for interaction purposes
|
||||
newInput = true;
|
||||
}
|
||||
else if (p.second.getTuioTime().getTotalMilliseconds() == now) {
|
||||
newInput = false;
|
||||
}
|
||||
});
|
||||
return newInput;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
touch.tap();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return true if we got new input
|
||||
if (listOfContactPoints.size() == lastProcessed.size() && !listOfContactPoints.empty()) {
|
||||
bool newInput = true;
|
||||
// go through list and check if the last registrered time is newer than the one in lastProcessed (last frame)
|
||||
std::for_each(lastProcessed.begin(), lastProcessed.end(), [this, &newInput](Point& p) {
|
||||
std::vector<TuioCursor>::iterator cursor = std::find_if(listOfContactPoints.begin(), listOfContactPoints.end(),
|
||||
[&p](const TuioCursor& c) { return c.getSessionID() == p.first; });
|
||||
double now = cursor->getPath().back().getTuioTime().getTotalMilliseconds();
|
||||
if (!cursor->isMoving()) { // if current cursor isn't moving, we want to interpret that as new input for interaction purposes
|
||||
newInput = true;
|
||||
}
|
||||
else if (p.second.getTuioTime().getTotalMilliseconds() == now) {
|
||||
newInput = false;
|
||||
}
|
||||
});
|
||||
return newInput;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TouchModule::TouchModule()
|
||||
: OpenSpaceModule("Touch")
|
||||
: OpenSpaceModule("Touch")
|
||||
{
|
||||
addPropertySubOwner(touch);
|
||||
addPropertySubOwner(markers);
|
||||
addPropertySubOwner(touch);
|
||||
addPropertySubOwner(markers);
|
||||
|
||||
OsEng.registerModuleCallback(
|
||||
OpenSpaceEngine::CallbackOption::InitializeGL,
|
||||
[&]() {
|
||||
LDEBUGC("TouchModule", "Initializing TouchMarker OpenGL");
|
||||
markers.initialize();
|
||||
}
|
||||
);
|
||||
OsEng.registerModuleCallback(
|
||||
OpenSpaceEngine::CallbackOption::InitializeGL,
|
||||
[&]() {
|
||||
LDEBUGC("TouchModule", "Initializing TouchMarker OpenGL");
|
||||
markers.initialize();
|
||||
}
|
||||
);
|
||||
|
||||
OsEng.registerModuleCallback(
|
||||
OpenSpaceEngine::CallbackOption::DeinitializeGL,
|
||||
[&]() {
|
||||
LDEBUGC("TouchMarker", "Deinitialize TouchMarker OpenGL");
|
||||
markers.deinitialize();
|
||||
}
|
||||
);
|
||||
OsEng.registerModuleCallback(
|
||||
OpenSpaceEngine::CallbackOption::DeinitializeGL,
|
||||
[&]() {
|
||||
LDEBUGC("TouchMarker", "Deinitialize TouchMarker OpenGL");
|
||||
markers.deinitialize();
|
||||
}
|
||||
);
|
||||
|
||||
OsEng.registerModuleCallback(
|
||||
OpenSpaceEngine::CallbackOption::PreSync,
|
||||
[&]() {
|
||||
touch.setCamera(OsEng.interactionHandler().camera());
|
||||
touch.setFocusNode(OsEng.interactionHandler().focusNode());
|
||||
OsEng.registerModuleCallback(
|
||||
OpenSpaceEngine::CallbackOption::PreSync,
|
||||
[&]() {
|
||||
touch.setCamera(OsEng.interactionHandler().camera());
|
||||
touch.setFocusNode(OsEng.interactionHandler().focusNode());
|
||||
|
||||
if (hasNewInput() && OsEng.windowWrapper().isMaster()) {
|
||||
touch.updateStateFromInput(listOfContactPoints, lastProcessed);
|
||||
}
|
||||
else if (listOfContactPoints.empty()) {
|
||||
touch.resetAfterInput();
|
||||
}
|
||||
if (hasNewInput() && OsEng.windowWrapper().isMaster()) {
|
||||
touch.updateStateFromInput(listOfContactPoints, lastProcessed);
|
||||
}
|
||||
else if (listOfContactPoints.empty()) {
|
||||
touch.resetAfterInput();
|
||||
}
|
||||
|
||||
// update lastProcessed
|
||||
lastProcessed.clear();
|
||||
for (const TuioCursor& c : listOfContactPoints) {
|
||||
// update lastProcessed
|
||||
lastProcessed.clear();
|
||||
for (const TuioCursor& c : listOfContactPoints) {
|
||||
lastProcessed.emplace_back(c.getSessionID(), c.getPath().back());
|
||||
}
|
||||
touch.unitTest(); // used to save data from solver, only calculated for one frame when user chooses in GUI
|
||||
touch.step(OsEng.windowWrapper().deltaTime()); // calculate the new camera state for this frame
|
||||
}
|
||||
);
|
||||
}
|
||||
touch.unitTest(); // used to save data from solver, only calculated for one frame when user chooses in GUI
|
||||
touch.step(OsEng.windowWrapper().deltaTime()); // calculate the new camera state for this frame
|
||||
}
|
||||
);
|
||||
|
||||
OsEng.registerModuleCallback(
|
||||
OpenSpaceEngine::CallbackOption::Render,
|
||||
[&]() {
|
||||
markers.render(listOfContactPoints); // render markers, customizable through the GUI
|
||||
}
|
||||
);
|
||||
OsEng.registerModuleCallback(
|
||||
OpenSpaceEngine::CallbackOption::Render,
|
||||
[&]() {
|
||||
markers.render(listOfContactPoints); // render markers, customizable through the GUI
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*****************************************************************************************
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
@@ -32,23 +32,23 @@
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class TouchModule : public OpenSpaceModule {
|
||||
using Point = std::pair<int, TUIO::TuioPoint>;
|
||||
public:
|
||||
TouchModule();
|
||||
class TouchModule : public OpenSpaceModule {
|
||||
using Point = std::pair<int, TUIO::TuioPoint>;
|
||||
public:
|
||||
TouchModule();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Returns true if new touch input occured since the last frame
|
||||
*/
|
||||
bool hasNewInput();
|
||||
private:
|
||||
/**
|
||||
* Returns true if new touch input occured since the last frame
|
||||
*/
|
||||
bool hasNewInput();
|
||||
|
||||
TuioEar ear;
|
||||
TouchInteraction touch;
|
||||
TouchMarker markers;
|
||||
std::vector<TUIO::TuioCursor> listOfContactPoints;
|
||||
std::vector<Point> lastProcessed; // contains an id and the TuioPoint that was processed last frame
|
||||
};
|
||||
TuioEar ear;
|
||||
TouchInteraction touch;
|
||||
TouchMarker markers;
|
||||
std::vector<TUIO::TuioCursor> listOfContactPoints;
|
||||
std::vector<Point> lastProcessed; // contains an id and the TuioPoint that was processed last frame
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user