MeshLab中Filters菜单下插件的编写

来源:互联网 发布:批量修改文件名软件 编辑:程序博客网 时间:2024/05/21 17:37

在MeshLab中对其功能的扩展是通过插件来实现的,通过实现不同的接口,可以将插件放在不同的菜单下或工具栏上,在这里只介绍Filter菜单下的插件实现,其他的类似。

 

    1. 首先在meshlab/src目录下创建myplugins文件夹,然后用QCreator打开meshlab_mini.pro。创建一个新的子工程叫helloplugin,选择空Qt项目即可,并保存在myplugins文件下,如图1所示。


图1 创建的helloplugin空项目

2.MeshLab提供了一个公用的shared.pri,里面包含了通用的插件编译配置,只需在helloplugin.pro包含该文件即完成了插件编译的基本配置。在helloplugin.pro中包含该文件:include (../../shared.pri)然后在该工程下创建一个HelloPlugin类,继承自QObject,如图2所示。


图2 创建HelloPlugin类

3.MeshLab提供了MeshFilterInterface接口,用于实现Filter菜单下的插件,因此需要实现该接口。

//helloplugin.h#ifndef HELLOPLUGIN_H#define HELLOPLUGIN_H#include <QObject>#include <common/interfaces.h>class HelloPlugin : public QObject, public MeshFilterInterface{    Q_OBJECT    Q_INTERFACES(MeshFilterInterface) //指名MeshFilterInterface为接口public:    explicit HelloPlugin(QObject *parent = 0);    //……};#endif // HELLOPLUGIN_H//helloplugin.cpp#include "helloplugin.h"HelloPlugin::HelloPlugin(QObject *parent) :    QObject(parent){}Q_EXPORT_PLUGIN(HelloPlugin) //导出插件

4.接下来逐步完成Filter菜单下的插件,是通过实现MeshFilterInterface接口中的功能来完成。下面介绍下几个核心函数和成员变量:

/**  \brief The MeshFilterInterface class provide the interface of the filter plugins.*/class MeshFilterInterface : public MeshCommonInterface{public:  /** The FilterClass enum represents the set of keywords that must be used to categorize a filter.   Each filter can belong to one or more filtering class, or-ed togheter.  */enum FilterClass {         Generic          =0x00000, /*!< Should be avoided if possible. */  //        Selection        =0x00001, /*!<  select or de-select something, basic operation on selections (like deleting)*/        Cleaning         =0x00002, /*!<  Filters that can be used to clean meshes (duplicated vertices etc)*/        Remeshing        =0x00004, /*!<  Simplification, Refinement, Reconstruction and mesh optimization*/        FaceColoring     =0x00008,        VertexColoring   =0x00010,        MeshCreation     =0x00020,        Smoothing        =0x00040, /*!<  Stuff that does not change the topology, but just the vertex positions*/        Quality          =0x00080,        Layer            =0x00100, /*!<  Layers, attributes */        RasterLayer      =0x20000, /*!<  Raster Layers, attributes */        Normal           =0x00200, /*!<  Normal, Curvature, orientation (rotations and transformations fall here)*/        Sampling         =0x00400,        Texture          =0x00800,        RangeMap         =0x01000, /*!<  filters specific for range map processing*/        PointSet         =0x02000,        Measure          =0x04000,  /*!<  Filters that compute measures and information on meshes.*/        Polygonal        =0x08000,  /*!<  Filters that works on polygonal and quad meshes.*/        Camera           =0x10000  /*!<  Filters that works on shot of mesh and raster.*/    };MeshFilterInterface() : MeshCommonInterface() {}virtual ~MeshFilterInterface() {}  /** The very short string (a few words) describing each filtering action  // This string is used also to define the menu entry  */  virtual QString filterName(FilterIDType ) const =0;  /** The long, formatted string describing each filtering action.// This string is printed in the top of the parameter window   // so it should be at least one or two paragraphs long. The more the better.  // you can use simple html formatting tags (like "<br>" "<b>" and "<i>") to improve readability.  // This string is used in the 'About plugin' dialog and by meshlabserver to create the filter list wiki page and the doxygen documentation of the filters.  // Here is the place where you should put you bibliographic references in a form like this:  <br>  See: <br />  <i>Luiz Velho, Denis Zorin </i><br/>  <b>"4-8 Subdivision"</b><br/>  CAGD, volume 18, Issue 5, Pages 397-427.<br/>  <br>  e.g. italic for authors, bold for title (quoted) and plain for bib ref.  */virtual QString filterInfo(FilterIDType filter) const =0;  /** The FilterClass describes in which generic class of filters it fits.// This choice affect the submenu in which each filter will be placed // For example filters that perform an action only on the selection will be placed in the Selection Class  */virtual FilterClass getClass(QAction *) { return MeshFilterInterface::Generic; }  /**   The filters can have some additional requirements on the mesh capabiliteis.// For example if a filters requires Face-Face Adjacency you shoud re-implement // this function making it returns MeshModel::MM_FACEFACETOPO. // The framework will ensure that the mesh has the requirements satisfied before invoking the applyFilter function  //  // Furthermore, requirements are checked just before the invocation of a filter. If your filter  // outputs a never used before mesh property (e.g. face colors), it will be allocated by a call  // to MeshModel::updateDataMask(...)  */  virtual int getRequirements(QAction *){return MeshModel::MM_NONE;}  /** The FilterPrecondition mask is used to explicitate what kind of data a filter really needs to be applied.// For example algorithms that compute per face quality have as precondition the existence of faces // (but quality per face is not a precondition, because quality per face is created by these algorithms)// on the other hand an algorithm that deletes faces according to the stored quality has both FaceQuality// and Face as precondition.  // These conditions do NOT include computed properties like borderFlags, manifoldness or watertightness.  // They are also used to grayout menus un-appliable entries.  */  virtual int getPreConditions(QAction *) const {return MeshModel::MM_NONE;}  /** Function used by the framework to get info about the mesh properties changed by the filter.// It is widely used by the meshlab's preview system.//TO BE REPLACED WITH = 0  */  virtual int postCondition( QAction* ) const {return MeshModel::MM_UNKNOWN;}  /** \brief applies the selected filter with the already stabilished parameters  * This function is called by the framework after getting values for the parameters specified in the \ref InitParameterSet  * NO GUI interaction should be done here. No dialog asking, no messagebox errors.  * Think that his function will also be called by the commandline framework.  * If you want report errors, use the \ref errorMsg() string. It will displayed in case of filters returning false.  * When implementing your applyFilter, you should use the cb function to report to the framework the current state of the processing.  * During your (long) processing you should call from time to time cb(perc,descriptiveString), where perc is an int (0..100)  * saying what you are doing and at what point of the computation you currently are.  * \sa errorMsg  * \sa initParameterSet  */    virtual bool applyFilter(QAction *   filter, MeshDocument &md,   RichParameterSet & par,       vcg::CallBackPos *cb) =0;  /** \brief tests if a filter is applicable to a mesh.  This function is a handy wrapper used by the framework for the \a getPreConditions callback;  For istance a colorize by quality filter cannot be applied to a mesh without per-vertex-quality.  On failure (returning false) the function fills the MissingItems list with strings describing the missing items.  */  bool isFilterApplicable(QAction *act, const MeshModel& m, QStringList &MissingItems) const;// This function is called to initialized the list of parameters.   // it is always called. If a filter does not need parameter it leave it empty and the framework  // will not create a dialog (unless for previewing)virtual void initParameterSet(QAction *,MeshModel &/*m*/, RichParameterSet & /*par*/) {}virtual void initParameterSet(QAction *filter,MeshDocument &md, RichParameterSet &par) {initParameterSet(filter,*(md.mm()),par);}  /** \brief is invoked by the framework when the applyFilter fails to give some info to the user about the fiter failure    * Filters \b must never use QMessageBox for reporting errors.    * Failing filters should put some meaningful information inside the errorMessage string and return false with the \ref applyFilter    */const QString &errorMsg() {return this->errorMessage;}  virtual QString filterInfo(QAction *a) const {return this->filterInfo(ID(a));}  virtual QString filterName(QAction *a) const {return this->filterName(ID(a));}  virtual QString filterScriptFunctionName(FilterIDType /*filterID*/) {return "";}//………………………..略protected:    // Each plugins exposes a set of filtering possibilities. // Each filtering procedure corresponds to a single QAction with a corresponding FilterIDType id. //     // The list of actions exported by the plugin. Each actions strictly corresponds to QList <QAction *> actionList;    QList <FilterIDType> typeList;    // this string is used to pass back to the framework error messages in case of failure of a filter apply.QString errorMessage;};

 

5.添加到Filter菜单下的插件有好几个分类,已是预定义好的,在FilterClass所定义的枚举类型,前面的代码中有定义。插件中可以有许多的功能,每个功能可以列入FilterClass中的一个分类,这些功能都存在成员变量typeList中,其相应的动作响应由actionList来承接,参见上面代码。

 

在HelloPlugin.h中定义该插件所具有的功能,加入代码:

enum{//定义HelloPlugin插件所具有的功能        FP_FUNC_ONE,        FP_FUNC_TWO,        FP_FUNC_THREE    };//重写MeshFilterInterface中的虚函数,实现自己的功能//给所定义的功能起个名字,该名字是要显示在filter菜单中的子菜单中的,比如:给FP_FUNC_ONE起名为“Function one”virtual QString filterName(FilterIDType filter) const;    //给所定义的功能进行描述virtual QString filterInfo(FilterIDType filter) const;//给所定义的功能进行分类,即加入filter菜单中的哪个子菜单virtual FilterClass getClass(QAction* a);//定义参数输入的GUI界面,进行交互virtual void initParameterSet(QAction* a,MeshModel& mm,RichParameterSet& parlst);//判定该所执行的功能在具体运行前,是不是已满足运行条件virtual int getPreConditions(QAction * a) const;//应用该插件所执行的功能    virtual bool applyFilter(QAction *filter, MeshDocument &md, RichParameterSet &par, vcg::CallBackPos *cb);

然后在HelloPlugin.cpp中实现这些功能,代码如下:

//HelloPlugin.cpp#include "helloplugin.h"HelloPlugin::HelloPlugin(QObject *parent) :    QObject(parent),MeshFilterInterface(){    typeList << FP_FUNC_ONE                <<FP_FUNC_TWO                  <<FP_FUNC_THREE;    foreach(FilterIDType tt,typeList)//为各功能添加响应        actionList<< new QAction(filterName(tt),this);}QString HelloPlugin::filterName(FilterIDType filter) const{//给各功能所起在名称,即菜单名    switch(filter){    case FP_FUNC_ONE:        return tr("Function One");    case FP_FUNC_TWO:        return tr("Function Two");    case FP_FUNC_THREE:        return tr("Function Three");    default:assert(0);    }    return tr("");}QString HelloPlugin::filterInfo(FilterIDType filter) const{//对各功能进行的解释,描述    switch(filter){    case FP_FUNC_ONE:        return tr("the description for function one");    case FP_FUNC_TWO:        return tr("the description for function two");    case FP_FUNC_THREE:        return tr("the description for function three");    default: assert(0);    }    return tr("");}MeshFilterInterface::FilterClass HelloPlugin::getClass(QAction* a){//定义每个功能所属的子菜单    switch(ID(a)){    case FP_FUNC_ONE:        return MeshFilterInterface::Generic;//直接在filter菜单下    case FP_FUNC_TWO:    case FP_FUNC_THREE:        return MeshFilterInterface::Camera;//在filter->camera子菜单下    default:assert(0);    }    return MeshFilterInterface::Generic;}void HelloPlugin::initParameterSet(QAction* a,MeshModel& mm,RichParameterSet& parlst){//定义每个功能接收参数的GUI,至于存在几种控件类型,请查相关资料    switch(ID(a)){    case FP_FUNC_ONE:    {        parlst.addParam(new RichBool("Original",true,"remove original","if remove the original mesh."));        return;    }    case FP_FUNC_TWO:    {        parlst.addParam(new RichInt("Resolution",90,"resolution"," resolution when do voxelization"));        parlst.addParam(new RichFloat("Ratio",0.96,"Shreshold","the ratio over this threshold would be thought as the same."));        parlst.addParam(new RichBool("WriteFile",false,"write file","write the lightweighted model to file."));        parlst.addParam(new RichInt("OverNum",16,"over vertex num","if the vertex number of one mesh over this threshold, it will be write to an individual file"));        parlst.addParam(new RichBool("QuickSlow",false,"Quick","voxelize Quickly but high memory, else slowly with low memory."));        return;    }    case FP_FUNC_THREE:    {//不需要GUI接收参数        return;    }    default:assert(0);    }    return;}int HelloPlugin::getPreConditions(QAction * a) const{//各个功能执行的先决条件    switch(ID(a)){    case FP_FUNC_ONE:    case FP_FUNC_TWO:    case FP_FUNC_THREE:        return MeshModel::MM_FACENUMBER;//必须存在三维模型    default:assert(0);    }    return MeshModel::MM_NONE;//不需任何条件}bool HelloPlugin::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet &par, vcg::CallBackPos *cb){    //your work is here    return true;}Q_EXPORT_PLUGIN(HelloPlugin)

如此,一个简单的、不执行任何功能的插件编写完成,上个截图:

 

 

 

辉辉                                                  

(FightingBull Studio)