PDA

View Full Version : How to use c++ complex numbers in QtScript



FFox
3rd July 2010, 21:04
Hi,

I have a class relying totally on the use of complex numbers. I'm using the c++ standard complex class for this.
Making this class scriptable, following the examples given in http://doc.qt.nokia.com/4.6/scripting.html wasn't a big deal.
Now I'm able to call all routines using real (double) arguments. However I have absolutely no clue how to call routines using complex arguments. Doe anyone out there know how to do it?

Best,
FFox

JohannesMunk
6th July 2010, 15:40
Hi there!

I never used c++ complex numbers before. But you will need to register the datatype to the scripting engine. One way to do that is to use qScriptRegisterMetaType. But that doesn't work for types that are not supported by QScriptValue ..



QScriptValue TypeToScriptValue(QScriptEngine *engine, Type* const &in)
{
return engine->newQObject(in,QScriptEngine::QtOwnership,QScriptEn gine::AutoCreateDynamicProperties);
}
void TypeFromScriptValue(const QScriptValue &object, Type* &out)
{
out = qobject_cast<Type*>(object.toQObject());
}

qScriptRegisterMetaType<Type*>(scriptengine, TypeToScriptValue, TypeFromScriptValue);
For a simple struct, that I think the c++ complex number will be similar too, you could create a prototype as follows:



template <typename T>
struct CVec4
{
T vec[4];
T x() const {return vec[0];}
T y() const {return vec[1];}
T z() const {return vec[2];}
T a() const {return vec[3];}
void setX(const T c) {vec[0] = c;}
void setY(const T c) {vec[1] = c;}
void setZ(const T c) {vec[2] = c;}
void setA(const T c) {vec[3] = c;}

CVec4(T _x = 0,T _y = 0,T _z = 0,T _a = 1) {vec[0] = _x;vec[1] = _y;vec[2] = _z;vec[3] = _a;}
CVec4(const CVec3<f32>& b) {vec[0] = b.x();vec[1] = b.y();vec[2] = b.z();vec[3] = 1;}
CVec4(const CVec3<f64>& b) {vec[0] = b.x();vec[1] = b.y();vec[2] = b.z();vec[3] = 1;}

const CVec4 operator+(const CVec4& b) const {return CVec4(x()+b.x(),y()+b.y(),z()+b.z(),a()+b.a());}
const CVec4 operator-(const CVec4& b) const {return CVec4(x()-b.x(),y()-b.y(),z()-b.z(),a()-b.a());}

CVec4& operator=(const CVec4& b) {vec[0] = b.x();vec[1] = b.y();vec[2] = b.z();vec[3] = b.a();return *this;}
CVec4& operator*=(const T s) {vec[0] *= s;vec[1] *= s;vec[2] *= s;return *this;}

CVec4& operator+=(const CVec4& b) {*this = *this + b;return *this;}

const CVec4 operator*(const T s) const {CVec4 a = *this;a *= s;return a;}

CVec4 MultMatrix(const f32* mat) const
{
return CVec4(vec[0] * mat[0]+vec[1] * mat[4]+vec[2] * mat[8]+vec[3] * mat[12],
vec[0] * mat[1]+vec[1] * mat[5]+vec[2] * mat[9]+vec[3] * mat[13],
vec[0] * mat[2]+vec[1] * mat[6]+vec[2] * mat[10]+vec[3] * mat[14],
vec[0] * mat[3]+vec[1] * mat[7]+vec[2] * mat[11]+vec[3] * mat[15]);
}

CVec4<f64> Getf64(const f64 s) const {CVec4<f64> a(ex4(*this));a *= s;return a;}

QString toString() const {return "("+QString::number(x())+";"+QString::number(y())+";"+QString::number(z())+";"+QString::number(a())+")";}
};

typedef CVec4<f32> CVec4f;

typedef CVec4f CGL4f;

Q_DECLARE_METATYPE(CGL4f)
Q_DECLARE_METATYPE(CGL4f*)
Q_DECLARE_METATYPE(QList<CGL4f>)

class CGL4fPrototype : public QObject, public QScriptable
{
Q_OBJECT
Q_PROPERTY(qreal x READ X WRITE setX)
Q_PROPERTY(qreal y READ Y WRITE setY)
Q_PROPERTY(qreal z READ Z WRITE setZ)
Q_PROPERTY(qreal a READ A WRITE setA)
protected:
CGL4f* thisCGL4() const {return qscriptvalue_cast<CGL4f*>(thisObject());}

public:
CGL4fPrototype(QObject *parent = 0) : QObject(parent) {}

qreal X() const {return thisCGL4()->x();}
void setX(const qreal &x) {thisCGL4()->setX(x);}

qreal Y() const {return thisCGL4()->y();}
void setY(const qreal &y) {thisCGL4()->setY(y);}

qreal Z() const {return thisCGL4()->z();}
void setZ(const qreal &z) {thisCGL4()->setZ(z);}

qreal A() const {return thisCGL4()->a();}
void setA(const qreal &a) {thisCGL4()->setA(a);}

public slots:
QString toString() const {return thisCGL4()->toString();}
};

QScriptValue CGL4f_ctor(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() >= 3)
{
qreal x = context->argument(0).toNumber();
qreal y = context->argument(1).toNumber();
qreal z = context->argument(2).toNumber();
qreal a = 1.0;
if (context->argumentCount() > 3)
context->argument(3).toNumber();
return engine->toScriptValue(CGL4f(x, y, z, a));
}
else {
return context->throwError(QScriptContext::SyntaxError, "CGL4f constructor requires 3/4 parameters (x,y,z,a/1)!");
}
}

CGL4fPrototype* cgl4fProto = new CGL4fPrototype();
scripting->setDefaultPrototype(qMetaTypeId<CGL4f>(),scripting->newQObject(cgl4fProto));
scripting->setDefaultPrototype(qMetaTypeId<CGL4f*>(),scripting->newQObject(cgl4fProto));
scripting->globalObject().setProperty("CGL4f", scripting->newFunction(CGL4f_ctor));
qScriptRegisterSequenceMetaType<QList<CGL4f> >(scripting);


Afterwards you can call something like this in script:


object.setColor(new CGL4f(1,1,0.5));

where setColor takes a CGL4f argument..

Hope the amount of code doesn't frighten you. It's a complete example of a 4dimensional vector struct made available to scripting by hand :->

HIH

Johannes