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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章