#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 MLXMLPluginInfo& xmlInfo ) const { QString names; //the order is important !!! MLXMLPluginInfo::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 MLXMLPluginInfo& xmlInfo ) const { QString code; QString names = parNames(filterName,xmlInfo); QString ariet = xmlInfo.filterAttribute(filterName,MLXMLElNames::filterArity); bool isSingle = (ariet == MLXMLElNames::singleMeshArity); QString mid("meshID"); if ((names.isEmpty()) && isSingle) names = mid; else if (isSingle) names = mid + ", " + names; code += "function (" + names + ")\n"; code += "{\n"; MLXMLPluginInfo::XMLMapList mplist = xmlInfo.filterParametersExtendedInfo(filterName); if (names.indexOf(optName()) != -1) { QString defValues; for(int ii = 0;ii < mplist.size();++ii) { MLXMLPluginInfo::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) { MLXMLPluginInfo::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); MLXMLPluginInfo::XMLMap valuesMap = MLXMLPluginInfo::mapFromString(values,QRegExp("\\|"),QRegExp("\\:")); code += "\tfunction enumfun_" + num + "()\n\t{\t\n"; for(MLXMLPluginInfo::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(param); QMap::iterator it = pm->stringFilterMap.find(filterName); if (it == pm->stringFilterMap.end()) { return false; } MeshDocumentScriptInterface* md = qscriptvalue_cast(engine->globalObject().property(ScriptAdapterGenerator::meshDocVarName())); RichParameterSet* rps = qscriptvalue_cast(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(param); QMap::iterator it = pm->stringFilterMap.find(filterName); if (it == pm->stringFilterMap.end()) { return false; } MeshDocumentScriptInterface* md = qscriptvalue_cast(engine->globalObject().property(ScriptAdapterGenerator::meshDocVarName())); RichParameterSet* rps = qscriptvalue_cast(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(param); QMap::iterator it = pm->stringXMLFilterMap.find(filterName); if (it == pm->stringXMLFilterMap.end()) return false; MeshDocumentScriptInterface* md = qscriptvalue_cast(engine->globalObject().property(ScriptAdapterGenerator::meshDocVarName())); EnvWrap* envWrap = qscriptvalue_cast(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(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(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(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(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 MeshModelScriptInterface::bboxMin() const { return ScriptInterfaceUtilities::vcgPointToVector(mm.cm.bbox.min); } Q_INVOKABLE QVector 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 int MeshModelScriptInterface::vn() const { return mm.cm.vn; } Q_INVOKABLE int MeshModelScriptInterface::fn() const { return mm.cm.fn; } Q_INVOKABLE QVector 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); } Q_INVOKABLE QVector VCGVertexScriptInterface::getN() { return ScriptInterfaceUtilities::vcgPointToVector(vv.N()); } Q_INVOKABLE void VCGVertexScriptInterface::setN( const float x,const float y,const float z ) { vv.N() = 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(val.toQObject()); } QScriptValue MeshDocumentScriptInterfaceToScriptValue( QScriptEngine* eng,MeshDocumentScriptInterface* const& in ) { return eng->newQObject(in); } void MeshDocumentScriptInterfaceFromScriptValue( const QScriptValue& val,MeshDocumentScriptInterface*& out ) { out = qobject_cast(val.toQObject()); } QScriptValue VCGVertexScriptInterfaceToScriptValue( QScriptEngine* eng,VCGVertexScriptInterface* const& in ) { return eng->newQObject(in); } void VCGVertexScriptInterfaceFromScriptValue( const QScriptValue& val,VCGVertexScriptInterface*& out ) { out = qobject_cast(val.toQObject()); } QScriptValue ShotScriptInterfaceToScriptValue( QScriptEngine* eng,ShotScriptInterface* const& in ) { return eng->newQObject(in); } void ShotScriptInterfaceFromScriptValue( const QScriptValue& val,ShotScriptInterface*& out ) { out = qobject_cast(val.toQObject()); } QScriptValue EnvWrap_ctor( QScriptContext* c,QScriptEngine* e ) { Env* env = qscriptvalue_cast(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(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 >(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_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 ScriptInterfaceUtilities::vcgPointToVector( const vcg::Point3f& p ) { QVector vfl(3); for (int ii = 0;ii < 3;++ii) vfl[ii] = p[ii]; return vfl; }