meshlab/src/common/scriptinterface.cpp
Guido Ranzuglia granzuglia 6e3b659765 - fixed small bug in MeshModelInterface
- introduced ShotScriptInterface
2011-09-23 07:01:12 +00:00

673 lines
20 KiB
C++

#include "scriptinterface.h"
#include "pluginmanager.h"
#include "interfaces.h"
#include "filterparameter.h"
#include "meshmodel.h"
#include "mlexception.h"
QString ScriptAdapterGenerator::parNames(const RichParameterSet& set) const
{
QString names;
int ii;
for(ii = 0;ii < (set.paramList.size() - 1);++ii)
names += set.paramList[ii]->name + ", ";
if (set.paramList.size() != 0)
names += set.paramList[ii]->name;
return names;
}
QString ScriptAdapterGenerator::parNames( const QString& filterName,const XMLFilterInfo& xmlInfo ) const
{
QString names;
//the order is important !!!
XMLFilterInfo::XMLMapList params = xmlInfo.filterParametersExtendedInfo(filterName);
int ii;
bool optional = false;
for(ii = 0;ii < params.size();++ii)
{
bool isImp = (params[ii][MLXMLElNames::paramIsImportant] == "true");
if (names.isEmpty() && isImp)
names += /*params[ii][MLXMLElNames::paramType] + "_" +*/ params[ii][MLXMLElNames::paramName];
else
if (isImp)
names += ", " + /*params[ii][MLXMLElNames::paramType] + "_" + */params[ii][MLXMLElNames::paramName];
else
optional = true;
}
if (optional && !(names.isEmpty()))
names += ", " + optName();
if (optional && names.isEmpty())
names += optName();
return names;
}
QString ScriptAdapterGenerator::funCodeGenerator(const QString& filtername,const RichParameterSet& set) const
{
QString code;
code += "function (" + parNames(set) + ")\n";
code += "{\n";
code += "\tvar tmpRichPar = new IRichParameterSet();\n";
code += "\tif (!_initParameterSet(\""+ filtername + "\",tmpRichPar)) return false;\n";
for(int ii = 0; ii < set.paramList.size();++ii)
code += "\ttmpRichPar.set" + set.paramList[ii]->val->typeName() + "(\"" + set.paramList[ii]->name + "\",arguments[" + QString::number(ii) + "]);\n";
code += "\treturn _applyFilter(\"" + filtername + "\",tmpRichPar);\n";
code += "};\n";
return code;
}
QString ScriptAdapterGenerator::funCodeGenerator( const QString& filterName,const XMLFilterInfo& xmlInfo ) const
{
QString code;
QString names = parNames(filterName,xmlInfo);
QString ariet = xmlInfo.filterAttribute(filterName,MLXMLElNames::filterAriety);
bool isSingle = (ariet == MLXMLElNames::singleMeshAriety);
QString mid("meshID");
if ((names.isEmpty()) && isSingle)
names = mid;
else
if (isSingle)
names = mid + ", " + names;
code += "function (" + names + ")\n";
code += "{\n";
XMLFilterInfo::XMLMapList mplist = xmlInfo.filterParametersExtendedInfo(filterName);
if (names.indexOf(optName()) != -1)
{
QString defValues;
for(int ii = 0;ii < mplist.size();++ii)
{
XMLFilterInfo::XMLMap mp = mplist[ii];
if (mp[MLXMLElNames::paramIsImportant] == "false")
defValues += mp[MLXMLElNames::paramName] + " : " + mp[MLXMLElNames::paramDefExpr] + ", ";
}
code += "\t" + optName() + " = __mergeOptions(" + optName() + ",{" + defValues + "});\n";
}
code += "\tvar environ = new Env;\n";
//if is singleMeshAriety i have to jump the first argument because is the meshID
int arg = (int) isSingle;
for(int ii = 0; ii < mplist.size();++ii)
{
XMLFilterInfo::XMLMap mp = mplist[ii];
bool isenum = false;
QString num = QString::number(ii);
QString values = mp[MLXMLElNames::paramType];
if (values.contains(MLXMLElNames::enumType))
{
QRegExp rem(MLXMLElNames::enumType + " \\{");
values.remove(rem);
rem.setPattern("\\}");
values.remove(rem);
XMLFilterInfo::XMLMap valuesMap = XMLFilterInfo::mapFromString(values,QRegExp("\\|"),QRegExp("\\:"));
code += "\tfunction enumfun_" + num + "()\n\t{\t\n";
for(XMLFilterInfo::XMLMap::iterator it = valuesMap.begin();it != valuesMap.end();++it)
{
code += "\t\tthis[\"" + it.key() + "\"] = " + it.value() + ";\n";
code += "\t\tthis[parseInt(" + it.value() + ")] = \"" + it.key() + "\";\n";
}
code += "\t}\n";
code += "\tfunction get_" + num + "(ff,ii)\n\t{\t\n";
code += "\t\tif (typeof(ii) == \"number\") return ff[ff[ii]];\n";
code += "\t\telse if (typeof(ii) == \"string\") return ff[ii];\n";
code += "\t\t\telse return undefined;\n";
code += "\t}\n";
code += "\tvar enumtype_" + num + " = new enumfun_" + num + "();\n";
isenum = true;
}
if (mp[MLXMLElNames::paramIsImportant] == "true")
{
QString argument = "arguments[" + QString::number(arg) + "]";
if (isenum)
{
code += "\tvar argenum_" + num + " = get_" + num + "(enumtype_" + num + "," + argument + ");\n";
code += "\tenviron.insertExpressionBinding(\"" + mp[MLXMLElNames::paramName] + "\",argenum_" + num + ");\n";
}
else
//code += "\tprint(" + argument + ");\n";
code += "\tenviron.insertExpressionBinding(\"" + mp[MLXMLElNames::paramName] + "\"," + argument + ");\n";
++arg;
}
else
{
if (isenum)
{
//code += "\tvar argenum_" + num + " = enumtype_" + num + "[" + argument + "];\n";
code += "\tvar " + mp[MLXMLElNames::paramName] + " = get_" + num + "(enumtype_" + num + "," + optName() + "." + /*mp[MLXMLElNames::paramType] + "_" +*/ mp[MLXMLElNames::paramName] + ");\n";
code += "\tenviron.insertExpressionBinding(\"" + mp[MLXMLElNames::paramName] + "\", " + mp[MLXMLElNames::paramName] + ");\n";
}
else
{
code += "\tvar " + mp[MLXMLElNames::paramName] + " = " + optName() + "." + /*mp[MLXMLElNames::paramType] + "_" +*/ mp[MLXMLElNames::paramName] + ";\n";
code += "\tenviron.insertExpressionBinding(\"" + mp[MLXMLElNames::paramName] + "\", " + mp[MLXMLElNames::paramName] + ");\n";
}
}
}
code += "\tvar environWrap = new EnvWrap(environ);\n";
if (isSingle)
{
code += "\tvar oldInd=" + meshDocVarName() + ".setCurrent(" + mid + ");\n";
code += "\tif (oldInd == -1) return false;\n";
}
code += "\tvar result = _applyFilter(\"" + filterName + "\",environWrap);\n";
if (isSingle)
code += "\t" +meshDocVarName() + ".setCurrent(oldInd);\n";
code += "\treturn result;\n";
code += "};\n";
return code;
}
const QStringList ScriptAdapterGenerator::javaScriptLibraryFiles()
{
QStringList res;
res.push_back(":/script_system/space_math.js");
return res;
}
QString ScriptAdapterGenerator::mergeOptParamsCodeGenerator() const
{
QString code;
code += "function __mergeOptions(argOptions, defaultOptions)\n{";
code += "\tvar ret = { };\n";
code += "\targOptions = argOptions || { };\n";
code += "\tfor (var p in defaultOptions)\n";
code += "\t\tret[p] = argOptions.hasOwnProperty(p) ? argOptions[p] : defaultOptions[p];\n";
code += "\treturn ret;\n}";
return code;
}
Q_DECLARE_METATYPE(MeshDocument*)
static bool TestCallback(const int , const char* )
{
return true;
}
QScriptValue PluginInterfaceInit(QScriptContext *context, QScriptEngine *engine, void * param)
{
QString filterName = context->argument(0).toString();
PluginManager * pm = reinterpret_cast<PluginManager *>(param);
QMap<QString, MeshFilterInterface*>::iterator it = pm->stringFilterMap.find(filterName);
if (it == pm->stringFilterMap.end())
{
return false;
}
MeshDocumentScriptInterface* md = qscriptvalue_cast<MeshDocumentScriptInterface*>(engine->globalObject().property(ScriptAdapterGenerator::meshDocVarName()));
RichParameterSet* rps = qscriptvalue_cast<RichParameterSet*>(context->argument(1));
MeshFilterInterface * mi = it.value();
QAction act(filterName, NULL);
mi->initParameterSet(&act, (md->current()->mm), *rps);
return true;
}
QScriptValue PluginInterfaceApply(QScriptContext *context, QScriptEngine *engine, void * param)
{
QString filterName = context->argument(0).toString();
PluginManager * pm = reinterpret_cast<PluginManager *>(param);
QMap<QString, MeshFilterInterface*>::iterator it = pm->stringFilterMap.find(filterName);
if (it == pm->stringFilterMap.end())
{
return false;
}
MeshDocumentScriptInterface* md = qscriptvalue_cast<MeshDocumentScriptInterface*>(engine->globalObject().property(ScriptAdapterGenerator::meshDocVarName()));
RichParameterSet* rps = qscriptvalue_cast<RichParameterSet*>(context->argument(1));
MeshFilterInterface * mi = it.value();
QAction act(filterName, NULL);
const bool res = mi->applyFilter(&act, *(md->md), *rps, TestCallback);
return res;
}
QScriptValue PluginInterfaceApplyXML(QScriptContext *context, QScriptEngine *engine, void * param)
{
QString filterName = context->argument(0).toString();
PluginManager * pm = reinterpret_cast<PluginManager *>(param);
QMap<QString, MeshLabXMLFilterContainer>::iterator it = pm->stringXMLFilterMap.find(filterName);
if (it == pm->stringXMLFilterMap.end())
return false;
MeshDocumentScriptInterface* md = qscriptvalue_cast<MeshDocumentScriptInterface*>(engine->globalObject().property(ScriptAdapterGenerator::meshDocVarName()));
EnvWrap* envWrap = qscriptvalue_cast<EnvWrap*>(context->argument(1));
MeshLabFilterInterface * mi = it->filterInterface;
const bool res = mi->applyFilter(filterName, *(md->md), *envWrap, TestCallback);
return res;
}
Q_DECLARE_METATYPE(RichParameterSet)
Q_DECLARE_METATYPE(RichParameterSet*)
QScriptValue IRichParameterSet_prototype_setBool(QScriptContext* c,QScriptEngine* e)
{
RichParameterSet* rset = qscriptvalue_cast<RichParameterSet*>(c->thisObject());
QString varname = c->argument(0).toString();
bool val = c->argument(1).toBool();
rset->setValue(varname,BoolValue(val));
return e->undefinedValue();
}
QScriptValue IRichParameterSet_prototype_setInt(QScriptContext* c,QScriptEngine* e)
{
RichParameterSet* rset = qscriptvalue_cast<RichParameterSet*>(c->thisObject());
QString varname = c->argument(0).toString();
int val = c->argument(1).toInt32();
rset->setValue(varname,IntValue(val));
return e->undefinedValue();
}
QScriptValue IRichParameterSet_prototype_setAbsPerc(QScriptContext* c,QScriptEngine* e)
{
RichParameterSet* rset = qscriptvalue_cast<RichParameterSet*>(c->thisObject());
QString varname = c->argument(0).toString();
float val = (float) c->argument(1).toNumber();
rset->setValue(varname,AbsPercValue(val));
return e->undefinedValue();
}
QScriptValue IRichParameterSet_prototype_setFloat( QScriptContext* c,QScriptEngine* e )
{
RichParameterSet* rset = qscriptvalue_cast<RichParameterSet*>(c->thisObject());
QString varname = c->argument(0).toString();
float val = (float) c->argument(1).toNumber();
rset->setValue(varname,FloatValue(val));
return e->undefinedValue();
}
QScriptValue IRichParameterSet_ctor(QScriptContext* /*c*/,QScriptEngine* e)
{
RichParameterSet* p = new RichParameterSet();
QScriptValue res = e->toScriptValue(*p);
//res.setProperty("setBool",e->newFunction(IRichParameterSet_prototype_setBool,2));
//res.setProperty("setInt",e->newFunction(IRichParameterSet_prototype_setInt,2));
return res;
}
QScriptValue myprint (QScriptContext* sc, QScriptEngine* se)
{
// do what you want
qDebug("%s",qPrintable(sc->argument(0).toString()));
return QScriptValue(se, 0);
}
MeshDocumentScriptInterface::MeshDocumentScriptInterface( MeshDocument* doc )
:QObject(doc),md(doc)
{
}
Q_INVOKABLE MeshModelScriptInterface* MeshDocumentScriptInterface::getMesh( int meshId )
{
MeshModel* model = md->getMesh(meshId);
if (model != NULL)
return new MeshModelScriptInterface(*model,this);
else
return NULL;
}
Q_INVOKABLE MeshModelScriptInterface* MeshDocumentScriptInterface::current()
{
MeshModel* model = md->mm();
if (model != NULL)
return new MeshModelScriptInterface(*model,this);
else
return NULL;
}
Q_INVOKABLE int MeshDocumentScriptInterface::currentId()
{
MeshModel* model = md->mm();
if (model != NULL)
return model->id();
else
return -1;
}
Q_INVOKABLE int MeshDocumentScriptInterface::setCurrent(const int meshId)
{
int id = md->mm()->id();
if (md->getMesh(meshId) != NULL)
{
md->setCurrentMesh(meshId);
return id;
}
else
return -1;
}
Q_INVOKABLE MeshModelScriptInterface* MeshDocumentScriptInterface::operator[]( const QString& name )
{
MeshModel* mym = md->getMesh(name);
if (mym != NULL)
return new MeshModelScriptInterface(*mym,this);
else
return NULL;
}
Q_INVOKABLE MeshModelScriptInterface* MeshDocumentScriptInterface::getMeshByName( const QString& name )
{
return (*this)[name];
}
MeshModelScriptInterface::MeshModelScriptInterface(MeshModel& meshModel,MeshDocumentScriptInterface* parent)
:QObject(parent),mm(meshModel)
{
}
Q_INVOKABLE float MeshModelScriptInterface::bboxDiag() const
{
return mm.cm.bbox.Diag();
}
Q_INVOKABLE QVector<float> MeshModelScriptInterface::bboxMin() const
{
return ScriptInterfaceUtilities::vcgPointToVector(mm.cm.bbox.min);
}
Q_INVOKABLE QVector<float> MeshModelScriptInterface::bboxMax() const
{
return ScriptInterfaceUtilities::vcgPointToVector(mm.cm.bbox.max);
}
Q_INVOKABLE int MeshModelScriptInterface::id() const
{
return mm.id();
}
VCGVertexScriptInterface::VCGVertexScriptInterface( CMeshO::VertexType& v )
:QObject(),vv(v)
{
}
Q_INVOKABLE VCGVertexScriptInterface* MeshModelScriptInterface::v( const int ind )
{
unsigned int ii(ind);
if (ii < mm.cm.vert.size())
return new VCGVertexScriptInterface(mm.cm.vert[ii]);
else
return NULL;
}
Q_INVOKABLE ShotScriptInterface* MeshModelScriptInterface::shot()
{
return new ShotScriptInterface(mm.cm.shot);
}
Q_INVOKABLE QVector<float> VCGVertexScriptInterface::getP()
{
return ScriptInterfaceUtilities::vcgPointToVector(vv.P());
}
Q_INVOKABLE void VCGVertexScriptInterface::setP( const float x,const float y,const float z )
{
vv.P() = vcg::Point3f(x,y,z);
}
QScriptValue MeshModelScriptInterfaceToScriptValue(QScriptEngine* eng,MeshModelScriptInterface* const& in)
{
return eng->newQObject(in);
}
void MeshModelScriptInterfaceFromScriptValue(const QScriptValue& val,MeshModelScriptInterface*& out)
{
out = qobject_cast<MeshModelScriptInterface*>(val.toQObject());
}
QScriptValue MeshDocumentScriptInterfaceToScriptValue( QScriptEngine* eng,MeshDocumentScriptInterface* const& in )
{
return eng->newQObject(in);
}
void MeshDocumentScriptInterfaceFromScriptValue( const QScriptValue& val,MeshDocumentScriptInterface*& out )
{
out = qobject_cast<MeshDocumentScriptInterface*>(val.toQObject());
}
QScriptValue VCGVertexScriptInterfaceToScriptValue( QScriptEngine* eng,VCGVertexScriptInterface* const& in )
{
return eng->newQObject(in);
}
void VCGVertexScriptInterfaceFromScriptValue( const QScriptValue& val,VCGVertexScriptInterface*& out )
{
out = qobject_cast<VCGVertexScriptInterface*>(val.toQObject());
}
QScriptValue ShotScriptInterfaceToScriptValue( QScriptEngine* eng,ShotScriptInterface* const& in )
{
return eng->newQObject(in);
}
void ShotScriptInterfaceFromScriptValue( const QScriptValue& val,ShotScriptInterface*& out )
{
out = qobject_cast<ShotScriptInterface*>(val.toQObject());
}
QScriptValue EnvWrap_ctor( QScriptContext* c,QScriptEngine* e )
{
Env* env = qscriptvalue_cast<Env*>(c->argument(0));
EnvWrap* p = new EnvWrap(*env);
QScriptValue res = e->toScriptValue(*p);
return res;
}
EnvWrap::EnvWrap(Env& envir)
:env(&envir)
{
}
QScriptValue EnvWrap::evalExp( const QString& nm )
{
if (!constStatement(nm))
throw NotConstException(nm);
QScriptValue result = env->evaluate(nm);
if (result.isError())
throw ValueNotFoundException(nm);
return result;
}
bool EnvWrap::evalBool( const QString& nm )
{
QScriptValue result = evalExp(nm);
if (result.isBool())
return result.toBool();
else
throw ExpressionHasNotThisTypeException("Bool",nm);
return false;
}
double EnvWrap::evalDouble( const QString& nm )
{
QScriptValue result = evalExp(nm);
if (result.isNumber())
return result.toNumber();
else
throw ExpressionHasNotThisTypeException("Double",nm);
return double();
}
float EnvWrap::evalFloat( const QString& nm )
{
try
{
double result = evalDouble(nm);
return (float) result;
}
catch(ExpressionHasNotThisTypeException& exc)
{
throw ExpressionHasNotThisTypeException("Float",nm);
}
return float();
}
int EnvWrap::evalInt( const QString& nm )
{
try
{
double result = evalDouble(nm);
return (int) result;
}
catch(ExpressionHasNotThisTypeException& exc)
{
throw ExpressionHasNotThisTypeException("Int",nm);
}
return int();
}
vcg::Point3f EnvWrap::evalVec3( const QString& nm )
{
QScriptValue result = evalExp(nm);
QVariant resVar = result.toVariant();
QVariantList resList = resVar.toList();
if (resList.size() == 3)
return vcg::Point3f(resList[0].toReal(),resList[1].toReal(),resList[2].toReal());
else
throw ExpressionHasNotThisTypeException("Vec3",nm);
return vcg::Point3f();
}
int EnvWrap::evalEnum( const QString& nm )
{
return evalInt(nm);
}
MeshModel* EnvWrap::evalMesh(const QString& nm)
{
int ii = evalInt(nm);
QScriptValue mdsv = env->globalObject().property(ScriptAdapterGenerator::meshDocVarName());
MeshDocumentScriptInterface* mdsi = dynamic_cast<MeshDocumentScriptInterface*>(mdsv.toQObject());
if (mdsi != NULL)
return mdsi->md->getMesh(ii);
return NULL;
}
QColor EnvWrap::evalColor( const QString& nm )
{
QScriptValue result = evalExp(nm);
QVariant resVar = result.toVariant();
QVariantList resList = resVar.toList();
int colorComp = resList.size();
if ((colorComp >= 3) && (colorComp <= 4))
{
bool isReal01 = true;
bool isInt0255 = true;
for(int ii = 0;ii < colorComp;++ii)
{
bool isScalarReal = false;
bool isScalarInt = false;
float resFloat = (float) resList[ii].toReal(&isScalarReal);
int resInt = resList[ii].toInt(&isScalarInt);
if ((!isScalarReal) && (!isScalarInt))
throw ExpressionHasNotThisTypeException("Color",nm);
if ((resFloat >= 0.0f) && (resFloat <= 1.0f))
{
isReal01 = isReal01 && true;
isInt0255 = false;
}
else
if ((resInt >= 0) && (resInt <= 255))
{
isInt0255 = isInt0255 && true;
isReal01 = false;
}
}
if (isReal01)
{
if (colorComp == 3)
return QColor::fromRgbF(resList[0].toReal(),resList[1].toReal(),resList[2].toReal());
if (colorComp == 4)
return QColor::fromRgbF(resList[0].toReal(),resList[1].toReal(),resList[2].toReal(),resList[3].toReal());
}
else if (isInt0255)
{
//if the
if (colorComp == 3)
return QColor(resList[0].toInt(),resList[1].toInt(),resList[2].toInt());
if (colorComp == 4)
return QColor(resList[0].toInt(),resList[1].toInt(),resList[2].toInt(),resList[3].toInt());
}
else
throw ExpressionHasNotThisTypeException("Color",nm);
}
else
throw ExpressionHasNotThisTypeException("Color",nm);
return QColor();
}
bool EnvWrap::constStatement( const QString& statement ) const
{
/*QRegExp exp("\\S+\\s*=\\s*S++;");*/
QRegExp exp("\\S+\\s*=\\s*\\S+;");
int ii = statement.indexOf(exp);
return (ii == -1);
}
QString EnvWrap::evalString( const QString& nm )
{
QScriptValue result = evalExp(nm);
return result.toString();
}
Q_DECLARE_METATYPE(EnvWrap)
Q_DECLARE_METATYPE(EnvWrap*)
QScriptValue Env_ctor( QScriptContext */*context*/,QScriptEngine *engine )
{
Env * env = new Env();
return engine->newQObject(env, QScriptEngine::ScriptOwnership);
}
Env::Env()
{
qScriptRegisterSequenceMetaType<QVector<float> >(this);
qScriptRegisterMetaType(this,MeshModelScriptInterfaceToScriptValue,MeshModelScriptInterfaceFromScriptValue);
qScriptRegisterMetaType(this,VCGVertexScriptInterfaceToScriptValue,VCGVertexScriptInterfaceFromScriptValue);
//qScriptRegisterMetaType(this,VCGPoint3fScriptInterfaceToScriptValue,VCGPoint3fScriptInterfaceFromScriptValue);
globalObject().setProperty("print", newFunction(myprint, 1));
QScriptValue envwrap_ctor = newFunction(EnvWrap_ctor);
//eng->setDefaultPrototype(qMetaTypeId<EnvWrap>(), envwrap_ctor.property("prototype"));
globalObject().setProperty("EnvWrap",envwrap_ctor);
QScriptValue env_ctor = newFunction(Env_ctor);
QScriptValue metaObject = newQMetaObject(&Env::staticMetaObject, env_ctor);
globalObject().setProperty("Env", metaObject);
/*qScriptRegisterMetaType(this,Point3fToScriptValue,Point3fFromScriptValue);*/
}
void Env::insertExpressionBinding( const QString& nm,const QString& exp )
{
QString decl("var " + nm + " = " + exp + ";");
QScriptValue res = evaluate(decl);
if (res.isError())
throw JavaScriptException(res.toString());
}
ShotScriptInterface::ShotScriptInterface( vcg::Shotf& st )
:shot(st)
{
}
QVector<float> ScriptInterfaceUtilities::vcgPointToVector( const vcg::Point3f& p )
{
QVector<float> vfl(3);
for (int ii = 0;ii < 3;++ii)
vfl[ii] = p[ii];
return vfl;
}