MeshLab中Filters菜单下插件的编写

在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)                                  


发布了32 篇原创文章 · 获赞 8 · 访问量 19万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章