/****************************************************************************
* MeshLab                                                           o o     *
* A versatile mesh processing toolbox                             o     o   *
*                                                                _   O  _   *
* Copyright(C) 2005                                                \/)\/    *
* Visual Computing Lab                                            /\/|      *
* ISTI - Italian National Research Council                           |      *
*                                                                    \      *
* All rights reserved.                                                      *
*                                                                           *
* This program is free software; you can redistribute it and/or modify      *
* it under the terms of the GNU General Public License as published by      *
* the Free Software Foundation; either version 2 of the License, or         *
* (at your option) any later version.                                       *
*                                                                           *
* This program is distributed in the hope that it will be useful,           *
* but WITHOUT ANY WARRANTY; without even the implied warranty of            *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
* for more details.                                                         *
*                                                                           *
****************************************************************************/

#include "filter_func.h"
#include <vcg/complex/algorithms/create/platonic.h>

#include <vcg/complex/algorithms/create/marching_cubes.h>
#include <vcg/complex/algorithms/create/mc_trivial_walker.h>

#include "muParser.h"
#include "string_conversion.h"

using namespace mu;
using namespace vcg;

// Constructor
FilterFunctionPlugin::FilterFunctionPlugin()
{
	typeList
			<< FF_VERT_SELECTION
			<< FF_FACE_SELECTION
			<< FF_GEOM_FUNC
			<< FF_WEDGE_TEXTURE_FUNC
			<< FF_VERT_TEXTURE_FUNC
			<< FF_FACE_COLOR
			<< FF_VERT_COLOR
			<< FF_VERT_QUALITY
			<< FF_VERT_NORMAL
			<< FF_FACE_QUALITY
			<< FF_DEF_VERT_ATTRIB
			<< FF_DEF_FACE_ATTRIB
			<< FF_GRID
			<< FF_ISOSURFACE
			<< FF_REFINE;
	
	foreach(FilterIDType tt , types())
		actionList << new QAction(filterName(tt), this);
}

FilterFunctionPlugin::~FilterFunctionPlugin()
{
	for (int i = 0; i < actionList.count() ; i++ )
		delete actionList.at(i);
}

QString FilterFunctionPlugin::pluginName() const
{
	return "FilterFunc";
}

// short string describing each filtering action
QString FilterFunctionPlugin::filterName(FilterIDType filterId) const
{
	switch(filterId) {
	case FF_VERT_SELECTION:     return QString("Conditional Vertex Selection");
	case FF_FACE_SELECTION:     return QString("Conditional Face Selection");
	case FF_GEOM_FUNC:          return QString("Per Vertex Geometric Function");
	case FF_FACE_COLOR:         return QString("Per Face Color Function");
	case FF_FACE_QUALITY:       return QString("Per Face Quality Function");
	case FF_VERT_COLOR:         return QString("Per Vertex Color Function");
	case FF_VERT_QUALITY:       return QString("Per Vertex Quality Function");
	case FF_VERT_TEXTURE_FUNC:  return QString("Per Vertex Texture Function");
	case FF_WEDGE_TEXTURE_FUNC: return QString("Per Wedge Texture Function");
	case FF_VERT_NORMAL:        return QString("Per Vertex Normal Function");
	case FF_DEF_VERT_ATTRIB:    return QString("Define New Per Vertex Attribute");
	case FF_DEF_FACE_ATTRIB:    return QString("Define New Per Face Attribute");
	case FF_GRID:               return QString("Grid Generator");
	case FF_REFINE:             return QString("Refine User-Defined");
	case FF_ISOSURFACE:         return QString("Implicit Surface");
		
	default: assert(0);
	}
	return QString("error!");
}

const QString PossibleOperators("<br>It's possible to use parenthesis <b>()</b>, and predefined operators:<br>"
								"<b>&&</b> (logic and), <b>||</b> (logic or), <b>&lt;</b>, <b>&lt;=</b>, <b>></b>, <b>>=</b>, <b>!=</b> (not equal), <b>==</b> (equal), <b>_?_:_</b> (c/c++ ternary operator)<br><br>");

const QString PerVertexAttributeString(	"It's possible to use the following per-vertex variables in the expression:<br>"
										"<b>x,y,z</b> (position), <b>nx,ny,nz</b> (normal), <b>r,g,b,a</b> (color), <b>q</b> (quality), "
										"<b>rad</b> (radius), <b>vi</b> (vertex index), <b>vtu,vtv,ti</b> (texture coords and texture index), <b>vsel</b> (is the vertex selected? 1 yes, 0 no) "
										"and all custom <i>vertex attributes</i> already defined by user.<br>");

const QString PerFaceAttributeString("It's possible to use the following per-face variables, or variables associated to the three vertex of every face:<br>"
									 "<b>x0,y0,z0</b> for the first vertex position, <b>x1,y1,z1</b> for the second vertex position, <b>x2,y2,z2</b> for the third vertex position, "
									 "<b>nx0,ny0,nz0 nx1,ny1,nz1 nx2,ny2,nz2</b> for vertex normals, <b>r0,g0,b0,a0 r1,g1,b1,a1 r2,g2,b2,a2</b> for vertex colors, "
									 "<b>q0,q1,q2</b> for vertex quality, <b>wtu0,wtv0 wtu1,wtv1 wtu2,wtv2</b> for per-wedge texture coords, <b>ti</b> for face texture index, <b>vsel0,vsel1,vsel2</b> for vertex selection (1 yes, 0 no) "
									 "<b>fr,fg,fb,fa</b> for face color, <b>fq</b> for face quality, <b>fnx,fny,fnz</b> for face normal, <b>fsel</b> face selection (1 yes, 0 no).<br>");

// long string describing each filtering action
QString FilterFunctionPlugin::filterInfo(FilterIDType filterId) const
{
	switch(filterId) {
	case FF_VERT_SELECTION : return tr(	"Boolean function using muparser lib to perform vertex selection over current mesh.<br>")
				+ PossibleOperators + PerVertexAttributeString;
		
	case FF_FACE_SELECTION : return tr(	"Boolean function using muparser lib to perform faces selection over current mesh.<br>") 
				+ PossibleOperators + PerFaceAttributeString;
		
	case FF_GEOM_FUNC :  return tr(	"Geometric function using muparser lib to generate new Coord<br>"
									"You can change x,y,z for every vertex according to the function specified.<br>") + PerVertexAttributeString;
		
	case FF_FACE_COLOR : return tr(	"Color function using muparser lib to generate new RGBA color for every face<br>"
									"Red, Green, Blue and Alpha channels may be defined specifying a function in their respective fields.<br>") + PerFaceAttributeString;
		
	case FF_VERT_COLOR : return tr(	"Color function using muparser lib to generate new RGBA color for every vertex<br>"
									"Red, Green, Blue and Alpha channels may be defined specifying a function in their respective fields.<br>") + PerVertexAttributeString;
		
	case FF_VERT_QUALITY: return tr("Quality function using muparser to generate new Quality for every vertex<br>") + PerVertexAttributeString;
		
	case FF_VERT_TEXTURE_FUNC: return tr("Texture function using muparser to generate new texture coords for every vertex<br>") + PerVertexAttributeString;
		
	case FF_VERT_NORMAL: return tr("Normal function using muparser to generate new Normal for every vertex<br>") + PerVertexAttributeString;
		
	case FF_FACE_QUALITY : return tr("Quality function using muparser to generate new Quality for every face<br>"
									 "Insert three function each one for quality of the three vertex of a face<br>") +PerFaceAttributeString;
		
	case FF_WEDGE_TEXTURE_FUNC : return tr("Texture function using muparser to generate new per wedge tex coords for every face<br>"
										   "Insert six functions each u v for each one of the three vertex of a face<br>") +PerFaceAttributeString;
		
	case FF_DEF_VERT_ATTRIB : return tr("Add a new Per-Vertex scalar attribute to current mesh and fill it with the defined function.<br>"
										"The name specified below can be used in other filter function") +PerVertexAttributeString;
		
	case FF_DEF_FACE_ATTRIB : return tr("Add a new Per-Face attribute to current mesh.<br>"
										"You can specify custom name and a function to generate attribute's value<br>"
										"It's possible to use per-face variables in the expression:<br>") +PerFaceAttributeString+
				tr("<font color=\"#FF0000\">The attribute name specified below can be used in other filter function</font>");
		
	case FF_GRID : return tr("Generate a new 2D Grid mesh with number of vertices on X and Y axis specified by user with absolute length/height.<br>"
							 "It's possible to center Grid on origin.");
		
	case FF_ISOSURFACE : return tr("Generate a new mesh that corresponds to the 0 valued isosurface defined by the scalar field generated by the given expression");
		
	case FF_REFINE : return tr("Refine current mesh with user defined parameters.<br>"
							   "Specify a Boolean Function needed to select which edges will be cut for refinement purpose.<br>"
							   "Each edge is identified with first and second vertex.<br>"
							   "Arguments accepted are first and second vertex attributes:<br>") + PossibleOperators + PerFaceAttributeString;
		
	default : assert(0);
	}
	return QString("filter not found!");
}

FilterFunctionPlugin::FilterClass FilterFunctionPlugin::getClass(const QAction *a) const
{
	switch(ID(a))
	{
	case FF_FACE_SELECTION:
	case FF_VERT_SELECTION: return FilterPluginInterface::Selection;
	case FF_FACE_QUALITY: return FilterClass(Quality + FaceColoring);
	case FF_VERT_QUALITY: return FilterClass(Quality + VertexColoring);
	case FF_VERT_TEXTURE_FUNC: return FilterPluginInterface::Texture;
	case FF_VERT_COLOR:	return FilterPluginInterface::VertexColoring;
	case FF_VERT_NORMAL:	return FilterPluginInterface::Normal;
	case FF_FACE_COLOR: return FilterPluginInterface::FaceColoring;
	case FF_WEDGE_TEXTURE_FUNC: return FilterPluginInterface::Texture;
	case FF_ISOSURFACE: return FilterPluginInterface::MeshCreation;
	case FF_GRID: return FilterPluginInterface::MeshCreation;
	case FF_REFINE: return FilterPluginInterface::Remeshing;
	case FF_GEOM_FUNC: return FilterPluginInterface::Smoothing;
	case FF_DEF_VERT_ATTRIB: return FilterPluginInterface::Layer;
	case FF_DEF_FACE_ATTRIB: return FilterPluginInterface::Layer;
		
	default: return FilterPluginInterface::Generic;
	}
}

int FilterFunctionPlugin::postCondition(const QAction *action) const
{
	switch(ID(action))
	{
	case FF_VERT_SELECTION:
	case FF_FACE_SELECTION:
		return MeshModel::MM_VERTFLAGSELECT | MeshModel::MM_FACEFLAGSELECT;
	case FF_FACE_COLOR:
		return MeshModel::MM_FACECOLOR;
	case FF_GEOM_FUNC:
		return MeshModel::MM_VERTCOORD + MeshModel::MM_VERTNORMAL + MeshModel::MM_FACENORMAL;
	case FF_VERT_COLOR:
		return MeshModel::MM_VERTCOLOR;
	case FF_VERT_NORMAL:
		return MeshModel::MM_VERTNORMAL;
	case FF_VERT_TEXTURE_FUNC:
		return MeshModel::MM_VERTTEXCOORD;
	case FF_WEDGE_TEXTURE_FUNC:
		return MeshModel::MM_WEDGTEXCOORD;
	case FF_VERT_QUALITY:
		return MeshModel::MM_VERTQUALITY + MeshModel::MM_VERTCOLOR;
	case FF_FACE_QUALITY:
		return MeshModel::MM_FACECOLOR + MeshModel::MM_FACEQUALITY;
		
	case FF_DEF_VERT_ATTRIB:
	case FF_DEF_FACE_ATTRIB:
		return MeshModel::MM_NONE;  // none, because they do not change any existing data
		
	case FF_REFINE:
		return MeshModel::MM_ALL;
		
	case FF_GRID:
	case FF_ISOSURFACE:
		return MeshModel::MM_NONE;  // none, because they create a new layer, without affecting old one
	}
	
	return MeshModel::MM_NONE;
}

int FilterFunctionPlugin::getRequirements(const QAction *action)
{
	switch(ID(action))
	{
	case FF_VERT_SELECTION    :
	case FF_GEOM_FUNC         :
	case FF_VERT_COLOR        :
	case FF_VERT_NORMAL       :
	case FF_VERT_QUALITY      :
	case FF_VERT_TEXTURE_FUNC :
	case FF_DEF_VERT_ATTRIB   :
	case FF_GRID              :
	case FF_ISOSURFACE        :
	case FF_DEF_FACE_ATTRIB   :
	case FF_FACE_SELECTION    : return 0;
	case FF_WEDGE_TEXTURE_FUNC: return MeshModel::MM_WEDGTEXCOORD;
	case FF_FACE_QUALITY      : return MeshModel::MM_FACECOLOR | MeshModel::MM_FACEQUALITY;
	case FF_FACE_COLOR        : return MeshModel::MM_FACECOLOR;
	case FF_REFINE            : return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK;
	default: assert(0);
	}
	return 0;
}

// This function define the needed parameters for each filter. Return true if the filter has some parameters
// it is called every time, so you can set the default value of parameters according to the mesh
// For each parameter you need to define,
// - the name of the parameter,
// - the string shown in the dialog
// - the default value
// - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog)
void FilterFunctionPlugin::initParameterList(const QAction *action,MeshModel &m, RichParameterList & parlst)
{
	Q_UNUSED(m);
	switch(ID(action))	 {
	
	case FF_VERT_SELECTION :
		parlst.addParam(RichString("condSelect","(q < 0)", "boolean function",
								   "type a boolean function that will be evaluated in order to select a subset of vertices<br>"
								   "example: (y > 0) and (ny > 0)"));
		break;
		
	case FF_FACE_SELECTION :
		parlst.addParam(RichString("condSelect","(fi == 0)", "boolean function",
								   "type a boolean function that will be evaluated in order to select a subset of faces<br>"));
		break;
		
	case FF_GEOM_FUNC:
		parlst.addParam(RichString("x", "x", "func x = ", "insert function to generate new coord for x"));
		parlst.addParam(RichString("y", "y", "func y = ", "insert function to generate new coord for y"));
		parlst.addParam(RichString("z", "sin(x+y)", "func z = ", "insert function to generate new coord for z"));
		parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected vertices"));
		break;
		
	case FF_VERT_NORMAL:
		parlst.addParam(RichString("x", "-nx", "func nx = ", "insert function to generate new x for the normal"));
		parlst.addParam(RichString("y", "-ny", "func ny = ", "insert function to generate new y for the normal"));
		parlst.addParam(RichString("z", "-nz", "func nz = ", "insert function to generate new z for the normal"));
		parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected vertices"));
		break;
		
	case FF_VERT_COLOR:
		parlst.addParam(RichString("x", "255", "func r = ", "function to generate Red component. Expected Range 0-255"));
		parlst.addParam(RichString("y", "255", "func g = ", "function to generate Green component. Expected Range 0-255"));
		parlst.addParam(RichString("z", "0", "func b = ", "function to generate Blue component. Expected Range 0-255"));
		parlst.addParam(RichString("a", "255", "func alpha = ", "function to generate Alpha component. Expected Range 0-255"));
		parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected vertices"));
		break;
		
	case FF_VERT_TEXTURE_FUNC:
		parlst.addParam(RichString("u", "x", "func u = ", "function to generate u texture coord. Expected Range 0-1"));
		parlst.addParam(RichString("v", "y", "func v = ", "function to generate v texture coord. Expected Range 0-1"));
		parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected vertices"));
		break;
		
	case FF_VERT_QUALITY:
		parlst.addParam(RichString("q", "vi", "func q = ", "function to generate new Quality for every vertex"));
		parlst.addParam(RichBool("normalize", false, "normalize", "if checked normalize all quality values in range [0..1]"));
		parlst.addParam(RichBool("map", false, "map into color", "if checked map quality generated values into per-vertex color"));
		parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected vertices"));
		break;
		
	case FF_FACE_COLOR:
		parlst.addParam(RichString("r", "255", "func r = ", "function to generate Red component. Expected Range 0-255"));
		parlst.addParam(RichString("g", "0", "func g = ", "function to generate Green component. Expected Range 0-255"));
		parlst.addParam(RichString("b", "255", "func b = ", "function to generate Blue component. Expected Range 0-255"));
		parlst.addParam(RichString("a", "255", "func alpha = ", "function to generate Alpha component. Expected Range 0-255"));
		parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected faces"));
		break;
		
	case FF_FACE_QUALITY:
		parlst.addParam(RichString("q", "x0+y0+z0", "func q0 = ", "function to generate new Quality foreach face"));
		parlst.addParam(RichBool("normalize", false, "normalize", "if checked normalize all quality values in range [0..1]"));
		parlst.addParam(RichBool("map", false, "map into color", "if checked map quality generated values into per-vertex color"));
		parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected faces"));
		break;
		
	case FF_WEDGE_TEXTURE_FUNC:
		parlst.addParam(RichString("u0","x0", "func u0 = ", "function to generate u texture coord. of wedge 0. Expected Range 0-1"));
		parlst.addParam(RichString("v0","y0", "func v0 = ", "function to generate v texture coord. of wedge 0. Expected Range 0-1"));
		parlst.addParam(RichString("u1","x1", "func u1 = ", "function to generate u texture coord. of wedge 1. Expected Range 0-1"));
		parlst.addParam(RichString("v1","y1", "func v1 = ", "function to generate v texture coord. of wedge 1. Expected Range 0-1"));
		parlst.addParam(RichString("u2","x2", "func u2 = ", "function to generate u texture coord. of wedge 2. Expected Range 0-1"));
		parlst.addParam(RichString("v2","y2", "func v2 = ", "function to generate v texture coord. of wedge 2. Expected Range 0-1"));
		parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected faces"));
		break;
		
	case FF_DEF_VERT_ATTRIB:
		parlst.addParam(RichString("name","Radiosity","Name", "the name of new attribute. you can access attribute in other filters through this name"));
		parlst.addParam(RichString("expr","x","Function =", "function to calculate custom attribute value for each vertex"));
		break;
		
	case FF_DEF_FACE_ATTRIB:
		parlst.addParam(RichString("name","Radiosity","Name", "the name of new attribute. you can access attribute in other filters through this name"));
		parlst.addParam(RichString("expr","fi","Function =", "function to calculate custom attribute value for each face"));
		break;
		
	case FF_GRID :
		parlst.addParam(RichInt("numVertX", 10, "num vertices on x", "number of vertices on x. it must be positive"));
		parlst.addParam(RichInt("numVertY", 10, "num vertices on y", "number of vertices on y. it must be positive"));
		parlst.addParam(RichFloat("absScaleX", 0.3f, "x scale", "absolute scale on x (float)"));
		parlst.addParam(RichFloat("absScaleY", 0.3f, "y scale", "absolute scale on y (float)"));
		parlst.addParam(RichBool("center",false,"centered on origin", "center grid generated by filter on origin.<br>"
																	  "Grid is first generated and than moved into origin (using muparser lib to perform fast calc on every vertex)"));
		break;
	case FF_ISOSURFACE :
		parlst.addParam(RichFloat("voxelSize", 0.05f, "Size of Voxel", "Size of the voxel that is used by for the grid where the field is sampled. Smaller this value, higher precision, but higher processing times."));
		parlst.addParam(RichFloat("minX", -1.0f, "Min X", "Range where the field is sampled"));
		parlst.addParam(RichFloat("minY", -1.0f, "Min Y", "Range where the field is sampled"));
		parlst.addParam(RichFloat("minZ", -1.0f, "Min Z", "Range where the field is sampled"));
		parlst.addParam(RichFloat("maxX", 1.0f, "Max X", "Range where the field is sampled"));
		parlst.addParam(RichFloat("maxY", 1.0f, "Max Y", "Range where the field is sampled"));
		parlst.addParam(RichFloat("maxZ", 1.0f, "Max Z", "Range where the field is sampled"));
		parlst.addParam(RichString("expr","x*x+y*y+z*z-0.5","Function =", "This expression is evaluated for each voxel of the grid. The surface passing through the zero valued points of this field is then extracted using marching cube."));
		
		break;
		
	case FF_REFINE :
		parlst.addParam(RichString("condSelect","(q0 >= 0 && q1 >= 0)","boolean function","type a boolean function that will be evaluated on every edge"));
		parlst.addParam(RichString("x","(x0+x1)/2","x =","function to generate x coord of new vertex in [x0,x1].<br>For example (x0+x1)/2"));
		parlst.addParam(RichString("y","(y0+y1)/2","y =","function to generate x coord of new vertex in [y0,y1].<br>For example (y0+y1)/2"));
		parlst.addParam(RichString("z","(z0+z1)/2","z =","function to generate x coord of new vertex in [z0,z1].<br>For example (z0+z1)/2"));
		break;
		
	default: break; // do not add any parameter for the other filters
	}
}

// The Real Core Function doing the actual mesh processing.
bool FilterFunctionPlugin::applyFilter(const QAction *filter, MeshDocument &md, std::map<std::string, QVariant>&, unsigned int& /*postConditionMask*/, const RichParameterList & par, vcg::CallBackPos *cb)
{
	if(this->getClass(filter) == FilterPluginInterface::MeshCreation)
		md.addNewMesh("",this->filterName(ID(filter)));
	MeshModel &m=*(md.mm());
	Q_UNUSED(cb);
	switch(ID(filter)) {
	case FF_VERT_SELECTION :
	{
		std::string expr = par.getString("condSelect").toStdString();
		auto wexpr = conversion::fromStringToWString(expr);
		
		// muparser initialization and explicitly define parser variables
		Parser p;
		setPerVertexVariables(p,m.cm);
		
		// set expression inserted by user as string (required by muparser)
		p.SetExpr(wexpr);
		
		int numvert = 0;
		time_t start = clock();
		
		// every parser variables is related to vertex coord and attributes.
		CMeshO::VertexIterator vi;
		for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)if(!(*vi).IsD())
		{
			setAttributes(vi,m.cm);
			
			bool selected = false;
			
			// use parser to evaluate boolean function specified above
			// in case of fail, error dialog contains details of parser's error
			try {
				selected = p.Eval();
			} catch(Parser::exception_type &e) {
				errorMessage = conversion::fromWStringToString(e.GetMsg()).c_str();
				return false;
			}
			
			// set vertex as selected or clear selection
			if(selected) {
				(*vi).SetS();
				numvert++;
			} else (*vi).ClearS();
		}
		
		// if succeeded log stream contains number of vertices and time elapsed
		log( "selected %d vertices in %.2f sec.", numvert, (clock() - start) / (float) CLOCKS_PER_SEC);
		
		return true;
	}
		break;
		
	case FF_FACE_SELECTION :
	{
		QString select = par.getString("condSelect");
		
		// muparser initialization and explicitly define parser variables
		Parser p;
		setPerFaceVariables(p,m.cm);
		
		// set expression inserted by user as string (required by muparser)
		p.SetExpr(conversion::fromStringToWString(select.toStdString()));
		
		int numface = 0;
		time_t start = clock();
		
		// every parser variables is related to face attributes.
		CMeshO::FaceIterator fi;
		for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)if(!(*fi).IsD())
		{
			setAttributes(fi,m.cm);
			
			bool selected = false;
			
			// use parser to evaluate boolean function specified above
			// in case of fail, error dialog contains details of parser's error
			try {
				selected = p.Eval();
			} catch(Parser::exception_type &e) {
				errorMessage = conversion::fromWStringToString(e.GetMsg()).c_str();
				return false;
			}
			
			// set face as selected or clear selection
			if(selected) {
				(*fi).SetS();
				numface++;
			} else (*fi).ClearS();
		}
		
		// if succeeded log stream contains number of vertices and time elapsed
		log( "selected %d faces in %.2f sec.", numface, (clock() - start) / (float) CLOCKS_PER_SEC);
		
		return true;
	}
		break;
		
	case FF_GEOM_FUNC :
	case FF_VERT_COLOR:
	case FF_VERT_NORMAL:
	{
		std::string func_x,func_y,func_z,func_a;
		// FF_VERT_COLOR : x = r, y = g, z = b
		// FF_VERT_NORMAL : x = r, y = g, z = b
		func_x = par.getString("x").toStdString();
		func_y = par.getString("y").toStdString();
		func_z = par.getString("z").toStdString();
		if(ID(filter) == FF_VERT_COLOR) func_a = par.getString("a").toStdString();
		
		bool onSelected = par.getBool("onselected");
		
		if (onSelected && m.cm.svn == 0 && m.cm.sfn == 0) // if no selection at all, fail
		{
			log("Cannot apply only on selection: there is no selection");
			errorMessage = "Cannot apply only on selection: there is no selection";
			return false;
		}
		if (onSelected && (m.cm.svn == 0 && m.cm.sfn > 0)) // if no vert selected, but some faces selected, use their vertices
		{
			tri::UpdateSelection<CMeshO>::VertexClear(m.cm);
			tri::UpdateSelection<CMeshO>::VertexFromFaceLoose(m.cm);
		}
		
		// muparser initialization and explicitly define parser variables
		// function for x,y and z must use different parser and variables
		Parser p1,p2,p3,p4;
		
		setPerVertexVariables(p1,m.cm);
		setPerVertexVariables(p2,m.cm);
		setPerVertexVariables(p3,m.cm);
		setPerVertexVariables(p4,m.cm);
		
		p1.SetExpr(conversion::fromStringToWString(func_x));
		p2.SetExpr(conversion::fromStringToWString(func_y));
		p3.SetExpr(conversion::fromStringToWString(func_z));
		p4.SetExpr(conversion::fromStringToWString(func_a));
		
		double newx=0,newy=0,newz=0,newa=255;
		errorMessage = "";
		
		time_t start = clock();
		
		// every parser variables is related to vertex coord and attributes.
		CMeshO::VertexIterator vi;
		for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)
			if(!(*vi).IsD())
				if ((!onSelected) || ((*vi).IsS()))
				{
					setAttributes(vi,m.cm);
					
					// every function is evaluated by different parser.
					// errorMessage dialog contains errors for func x, func y and func z
					try { newx = p1.Eval(); }  catch(Parser::exception_type &e) { showParserError("1st func : ",e); }
					try { newy = p2.Eval(); }  catch(Parser::exception_type &e) { showParserError("2nd func : ",e); }
					try { newz = p3.Eval(); }  catch(Parser::exception_type &e) { showParserError("3rd func : ",e); }
					if(ID(filter) == FF_VERT_COLOR)
					{
						try { newa = p4.Eval(); } catch(Parser::exception_type &e) { showParserError("4th func : ",e); }
					}
					if(errorMessage != "") return false;
					
					if (ID(filter) == FF_GEOM_FUNC)  // set new vertex coord for this iteration
						(*vi).P() = Point3m(newx, newy, newz);
					if (ID(filter) == FF_VERT_NORMAL) // set new color for this iteration
						(*vi).N() = Point3m(newx, newy, newz);
					if (ID(filter) == FF_VERT_COLOR) // set new color for this iteration
					{
						(*vi).C() = Color4b(newx, newy, newz, newa);
						m.updateDataMask(MeshModel::MM_VERTCOLOR);
					}
					
				}
		
		if(ID(filter) == FF_GEOM_FUNC) {
			// update bounding box, normalize normals
			tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFace(m.cm);
			tri::UpdateNormal<CMeshO>::NormalizePerFace(m.cm);
			tri::UpdateBounding<CMeshO>::Box(m.cm);
		}
		
		// if succeeded log stream contains number of vertices processed and time elapsed
		log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC);
		
		return true;
	}
		break;
		
	case FF_VERT_QUALITY:
	{
		std::string func_q = par.getString("q").toStdString();
		bool onSelected = par.getBool("onselected");
		
		if (onSelected && m.cm.svn == 0 && m.cm.sfn == 0) // if no selection at all, fail
		{
			log("Cannot apply only on selection: there is no selection");
			errorMessage = "Cannot apply only on selection: there is no selection";
			return false;
		}
		if (onSelected && (m.cm.svn == 0 && m.cm.sfn > 0)) // if no vert selected, but some faces selected, use their vertices
		{
			tri::UpdateSelection<CMeshO>::VertexClear(m.cm);
			tri::UpdateSelection<CMeshO>::VertexFromFaceLoose(m.cm);
		}
		
		m.updateDataMask(MeshModel::MM_VERTQUALITY);
		
		// muparser initialization and define custom variables
		Parser p;
		setPerVertexVariables(p,m.cm);
		
		// set expression to calc with parser
		p.SetExpr(conversion::fromStringToWString(func_q));
		
		// every parser variables is related to vertex coord and attributes.
		time_t start = clock();
		CMeshO::VertexIterator vi;
		for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)
			if(!(*vi).IsD())
				if ((!onSelected) || ((*vi).IsS()))
				{
					setAttributes(vi,m.cm);
					
					// use parser to evaluate function specified above
					// in case of fail, errorMessage dialog contains details of parser's error
					try {
						(*vi).Q() = p.Eval();
					} catch(Parser::exception_type &e) {
						errorMessage = conversion::fromWStringToString(e.GetMsg()).c_str();
						return false;
					}
				}
		
		// normalize quality with values in [0..1]
		if(par.getBool("normalize")) tri::UpdateQuality<CMeshO>::VertexNormalize(m.cm);
		
		// map quality into per-vertex color
		if(par.getBool("map"))
		{
			tri::UpdateColor<CMeshO>::PerVertexQualityRamp(m.cm);
			m.updateDataMask(MeshModel::MM_VERTCOLOR);
		}
		// if succeeded log stream contains number of vertices and time elapsed
		log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC);
		
		return true;
	}
		break;
	case FF_VERT_TEXTURE_FUNC:
	{
		std::string func_u = par.getString("u").toStdString();
		std::string func_v = par.getString("v").toStdString();
		bool onSelected = par.getBool("onselected");
		
		if (onSelected && m.cm.svn == 0 && m.cm.sfn == 0) // if no selection at all, fail
		{
			log("Cannot apply only on selection: there is no selection");
			errorMessage = "Cannot apply only on selection: there is no selection";
			return false;
		}
		if (onSelected && (m.cm.svn == 0 && m.cm.sfn > 0)) // if no vert selected, but some faces selected, use their vertices
		{
			tri::UpdateSelection<CMeshO>::VertexClear(m.cm);
			tri::UpdateSelection<CMeshO>::VertexFromFaceLoose(m.cm);
		}
		
		m.updateDataMask(MeshModel::MM_VERTTEXCOORD);
		
		// muparser initialization and define custom variables
		Parser pu,pv;
		setPerVertexVariables(pu,m.cm);
		setPerVertexVariables(pv,m.cm);
		
		// set expression to calc with parser
#ifdef _UNICODE
		pu.SetExpr(conversion::fromStringToWString(func_u));
		pv.SetExpr(conversion::fromStringToWString(func_v));
#else
		pu.SetExpr(func_u);
		pv.SetExpr(func_v);
#endif
		
		// every parser variables is related to vertex coord and attributes.
		time_t start = clock();
		CMeshO::VertexIterator vi;
		for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)
			if(!(*vi).IsD())
				if ((!onSelected) || ((*vi).IsS()))
				{
					setAttributes(vi,m.cm);
					
					// use parser to evaluate function specified above
					// in case of fail, errorMessage dialog contains details of parser's error
					try {
						(*vi).T().U() = pu.Eval();
						(*vi).T().V() = pv.Eval();
					} catch(Parser::exception_type &e) {
						errorMessage = conversion::fromWStringToString(e.GetMsg()).c_str();
						return false;
					}
				}
		
		log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC);
		return true;
	}
		break;
	case FF_WEDGE_TEXTURE_FUNC:
	{
		std::string func_u0 = par.getString("u0").toStdString();
		std::string func_v0 = par.getString("v0").toStdString();
		std::string func_u1 = par.getString("u1").toStdString();
		std::string func_v1 = par.getString("v1").toStdString();
		std::string func_u2 = par.getString("u2").toStdString();
		std::string func_v2 = par.getString("v2").toStdString();
		bool onSelected = par.getBool("onselected");
		
		if (onSelected && m.cm.sfn == 0) // if no selection, fail
		{
			log("Cannot apply only on selection: there is no selection");
			errorMessage = "Cannot apply only on selection: there is no selection";
			return false;
		}
		
		m.updateDataMask(MeshModel::MM_VERTTEXCOORD);
		
		// muparser initialization and define custom variables
		Parser pu0,pv0,pu1,pv1,pu2,pv2;
		setPerFaceVariables(pu0,m.cm); setPerFaceVariables(pv0,m.cm);
		setPerFaceVariables(pu1,m.cm); setPerFaceVariables(pv1,m.cm);
		setPerFaceVariables(pu2,m.cm); setPerFaceVariables(pv2,m.cm);
		
		// set expression to calc with parser
		pu0.SetExpr(conversion::fromStringToWString(func_u0)); pv0.SetExpr(conversion::fromStringToWString(func_v0));
		pu1.SetExpr(conversion::fromStringToWString(func_u1)); pv1.SetExpr(conversion::fromStringToWString(func_v1));
		pu2.SetExpr(conversion::fromStringToWString(func_u2)); pv2.SetExpr(conversion::fromStringToWString(func_v2));
		
		// every parser variables is related to vertex coord and attributes.
		time_t start = clock();
		for(CMeshO::FaceIterator fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)
			if(!(*fi).IsD())
				if ((!onSelected) || ((*fi).IsS()))
				{
					setAttributes(fi,m.cm);
					
					// use parser to evaluate function specified above
					// in case of fail, errorMessage dialog contains details of parser's error
					try {
						(*fi).WT(0).U() = pu0.Eval(); (*fi).WT(0).V() = pv0.Eval();
						(*fi).WT(1).U() = pu1.Eval(); (*fi).WT(1).V() = pv1.Eval();
						(*fi).WT(2).U() = pu2.Eval(); (*fi).WT(2).V() = pv2.Eval();
					} catch(Parser::exception_type &e) {
						errorMessage = conversion::fromWStringToString(e.GetMsg()).c_str();
						return false;
					}
				}
		
		log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC);
		return true;
	}
		break;
	case FF_FACE_COLOR:
	{
		std::string func_r = par.getString("r").toStdString();
		std::string func_g = par.getString("g").toStdString();
		std::string func_b = par.getString("b").toStdString();
		std::string func_a = par.getString("a").toStdString();
		bool onSelected = par.getBool("onselected");
		
		if (onSelected && m.cm.sfn == 0) // if no selection, fail
		{
			log("Cannot apply only on selection: there is no selection");
			errorMessage = "Cannot apply only on selection: there is no selection";
			return false;
		}
		
		m.updateDataMask(MeshModel::MM_FACECOLOR);
		
		// muparser initialization and explicitly define parser variables
		// every function must uses own parser and variables
		Parser p1,p2,p3,p4;
		
		setPerFaceVariables(p1,m.cm);
		setPerFaceVariables(p2,m.cm);
		setPerFaceVariables(p3,m.cm);
		setPerFaceVariables(p4,m.cm);
		
		p1.SetExpr(conversion::fromStringToWString(func_r));
		p2.SetExpr(conversion::fromStringToWString(func_g));
		p3.SetExpr(conversion::fromStringToWString(func_b));
		p4.SetExpr(conversion::fromStringToWString(func_a));
		
		// RGB is related to every face
		CMeshO::FaceIterator fi;
		double newr=0,newg=0,newb=0,newa=255;
		errorMessage = "";
		
		time_t start = clock();
		
		// every parser variables is related to face attributes.
		for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)
			if(!(*fi).IsD())
				if ((!onSelected) || ((*fi).IsS()))
				{
					setAttributes(fi,m.cm);
					
					// evaluate functions to generate new color
					// in case of fail, error dialog contains details of parser's error
					try { newr = p1.Eval(); } catch(Parser::exception_type &e) { showParserError("func r: ",e); }
					try { newg = p2.Eval(); } catch(Parser::exception_type &e) { showParserError("func g: ",e); }
					try { newb = p3.Eval(); } catch(Parser::exception_type &e) { showParserError("func b: ",e); 	}
					try { newa = p4.Eval(); } catch(Parser::exception_type &e) { showParserError("func a: ",e); 	}
					
					if(errorMessage != "") return false;
					
					// set new color for this iteration
					(*fi).C() = Color4b(newr,newg,newb,newa);
				}
		
		// if succeeded log stream contains number of vertices processed and time elapsed
		log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC);
		
		return true;
		
	}
		break;
		
	case FF_FACE_QUALITY:
	{
		std::string func_q = par.getString("q").toStdString();
		bool onSelected = par.getBool("onselected");
		
		if (onSelected && m.cm.sfn == 0) // if no selection, fail
		{
			log("Cannot apply only on selection: there is no selection");
			errorMessage = "Cannot apply only on selection: there is no selection";
			return false;
		}
		
		m.updateDataMask(MeshModel::MM_FACEQUALITY);
		
		// muparser initialization and define custom variables
		Parser pf;
		setPerFaceVariables(pf,m.cm);
		
		// set expression to calc with parser
		pf.SetExpr(conversion::fromStringToWString(func_q));
		
		time_t start = clock();
		errorMessage = "";
		
		// every parser variables is related to face attributes.
		CMeshO::FaceIterator fi;
		for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)
			if(!(*fi).IsD())
				if ((!onSelected) || ((*fi).IsS()))
				{
					setAttributes(fi,m.cm);
					
					// evaluate functions to generate new quality
					// in case of fail, error dialog contains details of parser's error
					try { (*fi).Q() = pf.Eval(); }
					catch(Parser::exception_type &e) {
						showParserError("func q: ",e);
					}
					if(errorMessage != "") return false;
				}
		
		// normalize quality with values in [0..1]
		if(par.getBool("normalize")) tri::UpdateQuality<CMeshO>::FaceNormalize(m.cm);
		
		// map quality into per-vertex color
		if(par.getBool("map"))
		{
			tri::UpdateColor<CMeshO>::PerFaceQualityRamp(m.cm);
			m.updateDataMask(MeshModel::MM_FACECOLOR);
		}
		
		// if succeeded log stream contains number of faces processed and time elapsed
		log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC);
		
		return true;
	}
		break;
		
	case FF_DEF_VERT_ATTRIB :
	{
		std::string name = par.getString("name").toStdString();
		std::string expr = par.getString("expr").toStdString();
		
		// add per-vertex attribute with type float and name specified by user
		CMeshO::PerVertexAttributeHandle<float> h;
		if(tri::HasPerVertexAttribute(m.cm,name))
		{
			h = tri::Allocator<CMeshO>::FindPerVertexAttribute<float>(m.cm, name);
			if(!tri::Allocator<CMeshO>::IsValidHandle<float>(m.cm,h))
			{
				errorMessage = "attribute already exists with a different type";
				return false;
			}
		}
		else
			h = tri::Allocator<CMeshO>::AddPerVertexAttribute<float> (m.cm,name);
		
		std::vector<std::string> AllVertexAttribName;
		tri::Allocator<CMeshO>::GetAllPerVertexAttribute< float >(m.cm,AllVertexAttribName);
		qDebug("Now mesh has %lu vertex float attribute",AllVertexAttribName.size());
		Parser p;
		setPerVertexVariables(p,m.cm);
		p.SetExpr(conversion::fromStringToWString(expr));
		
		time_t start = clock();
		
		// perform calculation of attribute's value with function specified by user
		CMeshO::VertexIterator vi;
		for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)if(!(*vi).IsD())
		{
			setAttributes(vi,m.cm);
			
			// add new user-defined attribute
			try {
				h[vi] = p.Eval();
			} catch(Parser::exception_type &e) {
				errorMessage = conversion::fromWStringToString(e.GetMsg()).c_str();
				return false;
			}
		}
		
		// add string, double and handler to vector.
		// vectors keep tracks of new attributes and let muparser use explicit variables
		// it's possible to use custom attributes in other filters
		v_attrNames.push_back(name);
		v_attrValue.push_back(0);
		v_handlers.push_back(h);
		
		// if succeeded log stream contains number of vertices processed and time elapsed
		log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC);
		
		return true;
	}
		break;
		
	case FF_DEF_FACE_ATTRIB :
	{
		std::string name = par.getString("name").toStdString();
		std::string expr = par.getString("expr").toStdString();
		
		// add per-face attribute with type float and name specified by user
		// add per-vertex attribute with type float and name specified by user
		CMeshO::PerFaceAttributeHandle<float> h;
		if(tri::HasPerFaceAttribute(m.cm,name))
		{
			h = tri::Allocator<CMeshO>::FindPerFaceAttribute<float>(m.cm, name);
			if(!tri::Allocator<CMeshO>::IsValidHandle<float>(m.cm,h))
			{
				errorMessage = "attribute already exists with a different type";
				return false;
			}
		}
		else
			h = tri::Allocator<CMeshO>::AddPerFaceAttribute<float> (m.cm,name);
		Parser p;
		setPerFaceVariables(p,m.cm);
		p.SetExpr(conversion::fromStringToWString(expr));
		
		time_t start = clock();
		
		// every parser variables is related to face attributes.
		CMeshO::FaceIterator fi;
		for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)if(!(*fi).IsD())
		{
			setAttributes(fi,m.cm);
			
			// add new user-defined attribute
			try {
				h[fi] = p.Eval();
			} catch(Parser::exception_type &e) {
				errorMessage = conversion::fromWStringToString(e.GetMsg()).c_str();
				return false;
			}
		}
		
		//				// add string, double and handler to vector.
		//				// vectors keep tracks of new attributes and let muparser use explicit variables
		//				// it's possible to use custom attributes in other filters
		//				f_attrNames.push_back(name);
		//				f_attrValue.push_back(0);
		//				fhandlers.push_back(h);
		
		// if succeeded log stream contains number of vertices processed and time elapsed
		log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC);
		
		return true;
	}
		break;
		
	case FF_GRID :
	{
		// obtain parameters to generate 2D Grid
		int w = par.getInt("numVertX");
		int h = par.getInt("numVertY");
		float wl = par.getFloat("absScaleX");
		float hl = par.getFloat("absScaleY");
		
		if(w <= 0 || h <= 0) {
			errorMessage = "number of vertices must be positive";
			return false;
		}
		
		// use Grid function to generate Grid
		tri::Grid<CMeshO>(m.cm, w, h, wl, hl);
		
		// if "centered on origin" is checked than move generated Grid in (0,0,0)
		if(par.getBool("center"))
		{
			// move x and y
			Scalarm halfw = Scalarm(w-1)/2;
			Scalarm halfh = Scalarm(h-1)/2;
			Scalarm wld = wl/Scalarm(w);
			Scalarm hld = hl/Scalarm(h);
			
			for(auto vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)
			{
				(*vi).P()[0] = (*vi).P()[0] - (wld * halfw);
				(*vi).P()[1] = (*vi).P()[1] - (hld * halfh);
			}
		}
		// update bounding box, normals
		//    Matrix44m rot; rot.SetRotateDeg(180,Point3m(0,1,0));
		Matrix44m rot; rot.SetScale(-1,1,-1);
		tri::UpdatePosition<CMeshO>::Matrix(m.cm,rot,false);
		m.UpdateBoxAndNormals();
		return true;
	}
		break;
	case FF_ISOSURFACE :
	{
		SimpleVolume<SimpleVoxel <float > > 	volume;
		
		typedef vcg::tri::TrivialWalker<CMeshO, SimpleVolume<SimpleVoxel<float> > >	MyWalker;
		typedef vcg::tri::MarchingCubes<CMeshO, MyWalker>	MyMarchingCubes;
		MyWalker walker;
		
		Box3f RangeBBox;
		RangeBBox.min[0]=par.getFloat("minX");
		RangeBBox.min[1]=par.getFloat("minY");
		RangeBBox.min[2]=par.getFloat("minZ");
		RangeBBox.max[0]=par.getFloat("maxX");
		RangeBBox.max[1]=par.getFloat("maxY");
		RangeBBox.max[2]=par.getFloat("maxZ");
		double step=par.getFloat("voxelSize");
		Point3i siz= Point3i::Construct((RangeBBox.max-RangeBBox.min)*(1.0/step));
		
		Parser p;
		double x,y,z;
		p.DefineVar(conversion::fromStringToWString("x"), &x);
		p.DefineVar(conversion::fromStringToWString("y"), &y);
		p.DefineVar(conversion::fromStringToWString("z"), &z);
		std::string expr = par.getString("expr").toStdString();
		p.SetExpr(conversion::fromStringToWString(expr));
		log("Filling a Volume of %i %i %i",siz[0],siz[1],siz[2]);
		volume.Init(siz,RangeBBox);
		for(double i=0;i<siz[0];i++)
			for(double j=0;j<siz[1];j++)
				for(double k=0;k<siz[2];k++)
				{
					x = RangeBBox.min[0]+step*i;
					y = RangeBBox.min[1]+step*j;
					z = RangeBBox.min[2]+step*k;
					try {
						volume.Val(i,j,k)=p.Eval();
					} catch(Parser::exception_type &e) {
						errorMessage = conversion::fromWStringToString(e.GetMsg()).c_str();
						return false;
					}
				}
		
		// MARCHING CUBES
		log("[MARCHING CUBES] Building mesh...");
		MyMarchingCubes					mc(m.cm, walker);
		walker.BuildMesh<MyMarchingCubes>(m.cm, volume, mc, 0);
		//    Matrix44m tr; tr.SetIdentity(); tr.SetTranslate(rbb.min[0],rbb.min[1],rbb.min[2]);
		//    Matrix44m sc; sc.SetIdentity(); sc.SetScale(step,step,step);
		//    tr=tr*sc;
		
		//    tri::UpdatePosition<CMeshO>::Matrix(m.cm,tr);
		tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFace(m.cm);
		tri::UpdateBounding<CMeshO>::Box(m.cm);					// updates bounding box
		return true;
		
	}
		break;
		
	case FF_REFINE :
	{
		std::string condSelect = par.getString("condSelect").toStdString();
		
		std::string expr1 = par.getString("x").toStdString();
		std::string expr2 = par.getString("y").toStdString();
		std::string expr3 = par.getString("z").toStdString();
		
		bool errorMidPoint = false;
		bool errorEdgePred = false;
		std::string msg = "";
		
		// check parsing errors while creating two func obj
		// display error message
		MidPointCustom<CMeshO> mid = MidPointCustom<CMeshO>(m.cm,expr1,expr2,expr3,errorMidPoint,msg);
		CustomEdge<CMeshO> edge = CustomEdge<CMeshO>(condSelect,errorEdgePred,msg);
		if(errorMidPoint || errorEdgePred)
		{
			errorMessage = msg.c_str();
			return false;
		}
		
		// Refine current mesh.
		// Only edge specified with CustomEdge pred are selected
		//  and the new vertex is chosen with MidPointCustom created above
		vcg::tri::RefineE<CMeshO, MidPointCustom<CMeshO>, CustomEdge<CMeshO> >
				(m.cm, mid, edge, false, cb);
		m.UpdateBoxAndNormals();
		m.clearDataMask( MeshModel::MM_VERTMARK);
		//vcg::tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFace(m.cm);
		
		return true;
	}
		break;
		
	default : assert (0);
	}
	return false;
}

// display parsing error in dialog
void FilterFunctionPlugin::showParserError(const QString &s, Parser::exception_type &e)
{
	errorMessage += s;
	errorMessage += conversion::fromWStringToString(e.GetMsg()).c_str();
	errorMessage += "\n";
}

// set per-vertex attributes associated to parser variables
void FilterFunctionPlugin::setAttributes(CMeshO::VertexIterator &vi, CMeshO &m)
{
	x = (*vi).P()[0]; // coord x
	y = (*vi).P()[1]; // coord y
	z = (*vi).P()[2]; // coord z
	
	nx = (*vi).N()[0]; // normal coord x
	ny = (*vi).N()[1]; // normal coord y
	nz = (*vi).N()[2]; // normal coord z
	
	r = (*vi).C()[0];  // color R
	g = (*vi).C()[1];  // color G
	b = (*vi).C()[2];  // color B
	a = (*vi).C()[3];  // color ALPHA
	
	q = (*vi).Q();     // quality
	
	vsel = ((*vi).IsS()) ? 1.0 : 0.0;    //selection
	
	if(tri::HasPerVertexRadius(m)) rad = (*vi).R();
	else rad=0;
	
	v = vi - m.vert.begin(); // zero based index of current vertex
	
	if(tri::HasPerVertexTexCoord(m))
	{
		vtu=(*vi).T().U();
		vtv=(*vi).T().V();
		ti = (*vi).T().N();
	}
	else { vtu=vtv=ti=0; }
	
	// if user-defined attributes exist (vector is not empty)
	//  set variables to explicit value obtained through attribute's handler
	for(int i = 0; i < (int) v_attrValue.size(); i++)
		v_attrValue[i] = v_handlers[i][vi];
	
	for(int i = 0; i < (int) v3_handlers.size(); i++)
	{
		v3_attrValue[i*3+0] = v3_handlers[i][vi].X();
		v3_attrValue[i*3+1] = v3_handlers[i][vi].Y();
		v3_attrValue[i*3+2] = v3_handlers[i][vi].Z();
	}
}

// set per-face attributes associated to parser variables
void FilterFunctionPlugin::setAttributes(CMeshO::FaceIterator &fi, CMeshO &m)
{
	// set attributes for First vertex
	// coords, normal coords, quality
	x0 = (*fi).V(0)->P()[0];
	y0 = (*fi).V(0)->P()[1];
	z0 = (*fi).V(0)->P()[2];
	
	nx0 = (*fi).V(0)->N()[0];
	ny0 = (*fi).V(0)->N()[1];
	nz0 = (*fi).V(0)->N()[2];
	
	r0 = (*fi).V(0)->C()[0];
	g0 = (*fi).V(0)->C()[1];
	b0 = (*fi).V(0)->C()[2];
	a0 = (*fi).V(0)->C()[3];
	
	q0 = (*fi).V(0)->Q();
	
	// set attributes for Second vertex
	// coords, normal coords, quality
	x1 = (*fi).V(1)->P()[0];
	y1 = (*fi).V(1)->P()[1];
	z1 = (*fi).V(1)->P()[2];
	
	nx1 = (*fi).V(1)->N()[0];
	ny1 = (*fi).V(1)->N()[1];
	nz1 = (*fi).V(1)->N()[2];
	
	r1 = (*fi).V(1)->C()[0];
	g1 = (*fi).V(1)->C()[1];
	b1 = (*fi).V(1)->C()[2];
	a1 = (*fi).V(1)->C()[3];
	
	q1 = (*fi).V(1)->Q();
	
	// set attributes for Third vertex
	// coords, normal coords, quality
	x2 = (*fi).V(2)->P()[0];
	y2 = (*fi).V(2)->P()[1];
	z2 = (*fi).V(2)->P()[2];
	
	nx2 = (*fi).V(2)->N()[0];
	ny2 = (*fi).V(2)->N()[1];
	nz2 = (*fi).V(2)->N()[2];
	
	r2 = (*fi).V(2)->C()[0];
	g2 = (*fi).V(2)->C()[1];
	b2 = (*fi).V(2)->C()[2];
	a2 = (*fi).V(2)->C()[3];
	
	q2 = (*fi).V(2)->Q();
	
	if(HasPerFaceQuality(m))
		fq=(*fi).Q();
	else fq=0;
	
	// set face color attributes
	if(HasPerFaceColor(m)){
		fr = (*fi).C()[0];
		fg = (*fi).C()[1];
		fb = (*fi).C()[2];
		fa = (*fi).C()[3];
	} else {
		fr=fg=fb=fa=255;
	}
	
	//face normal
	fnx = (*fi).N()[0];
	fny = (*fi).N()[1];
	fnz = (*fi).N()[2];
	
	// zero based index of face
	f = fi - m.face.begin();
	
	// zero based index of its vertices
	v0i = ((*fi).V(0) - &m.vert[0]);
	v1i = ((*fi).V(1) - &m.vert[0]);
	v2i = ((*fi).V(2) - &m.vert[0]);
	
	if(tri::HasPerWedgeTexCoord(m))
	{
		wtu0=(*fi).WT(0).U();
		wtv0=(*fi).WT(0).V();
		wtu1=(*fi).WT(1).U();
		wtv1=(*fi).WT(1).V();
		wtu2=(*fi).WT(2).U();
		wtv2=(*fi).WT(2).V();
		ti = (*fi).WT(0).N();
	}
	else { wtu0=wtv0=wtu1=wtv1=wtu2=wtv2=ti=0; }
	
	//selection
	vsel0 = ((*fi).V(0)->IsS()) ? 1.0 : 0.0;
	vsel1 = ((*fi).V(1)->IsS()) ? 1.0 : 0.0;
	vsel2 = ((*fi).V(2)->IsS()) ? 1.0 : 0.0;
	fsel = ((*fi).IsS()) ? 1.0 : 0.0;
	
	// if user-defined attributes exist (vector is not empty)
	//  set variables to explicit value obtained through attribute's handler
	for(int i = 0; i < (int) f_attrValue.size(); i++)
		f_attrValue[i] = f_handlers[i][fi];
}

// Function explicitly define parser variables to perform per-vertex filter action
// x, y, z for vertex coord, nx, ny, nz for normal coord, r, g ,b for color
// and q for quality
void FilterFunctionPlugin::setPerVertexVariables(Parser &p, CMeshO &m)
{
	p.DefineVar(conversion::fromStringToWString("x"), &x);
	p.DefineVar(conversion::fromStringToWString("y"), &y);
	p.DefineVar(conversion::fromStringToWString("z"), &z);
	p.DefineVar(conversion::fromStringToWString("nx"), &nx);
	p.DefineVar(conversion::fromStringToWString("ny"), &ny);
	p.DefineVar(conversion::fromStringToWString("nz"), &nz);
	p.DefineVar(conversion::fromStringToWString("r"), &r);
	p.DefineVar(conversion::fromStringToWString("g"), &g);
	p.DefineVar(conversion::fromStringToWString("b"), &b);
	p.DefineVar(conversion::fromStringToWString("a"), &a);
	p.DefineVar(conversion::fromStringToWString("q"), &q);
	p.DefineVar(conversion::fromStringToWString("vi"),&v);
	p.DefineVar(conversion::fromStringToWString("rad"),&rad);
	p.DefineVar(conversion::fromStringToWString("vtu"),&vtu);
	p.DefineVar(conversion::fromStringToWString("vtv"),&vtv);
	p.DefineVar(conversion::fromStringToWString("ti"), &ti);
	p.DefineVar(conversion::fromStringToWString("vsel"), &vsel);
	
	// define var for user-defined attributes (if any exists)
	// if vector is empty, code won't be executed
	v_handlers.clear();
	v_attrNames.clear();
	v_attrValue.clear();
	v3_handlers.clear();
	v3_attrNames.clear();
	v3_attrValue.clear();
	std::vector<std::string> AllVertexAttribName;
	tri::Allocator<CMeshO>::GetAllPerVertexAttribute< float >(m,AllVertexAttribName);
	for(int i = 0; i < (int) AllVertexAttribName.size(); i++)
	{
		CMeshO::PerVertexAttributeHandle<float> hh = tri::Allocator<CMeshO>::GetPerVertexAttribute<float>(m, AllVertexAttribName[i]);
		v_handlers.push_back(hh);
		v_attrNames.push_back(AllVertexAttribName[i]);
		v_attrValue.push_back(0);
		p.DefineVar(conversion::fromStringToWString(v_attrNames.back()), &v_attrValue.back());
		qDebug("Adding custom per vertex float variable %s",v_attrNames.back().c_str());
	}
	AllVertexAttribName.clear();
	tri::Allocator<CMeshO>::GetAllPerVertexAttribute< Point3f >(m,AllVertexAttribName);
	for(int i = 0; i < (int) AllVertexAttribName.size(); i++)
	{
		CMeshO::PerVertexAttributeHandle<Point3f> hh3 = tri::Allocator<CMeshO>::GetPerVertexAttribute<Point3f>(m, AllVertexAttribName[i]);
		
		v3_handlers.push_back(hh3);
		
		v3_attrValue.push_back(0);
		v3_attrNames.push_back(AllVertexAttribName[i]+"_x");
		p.DefineVar(conversion::fromStringToWString(v3_attrNames.back()), &v3_attrValue.back());
		
		v3_attrValue.push_back(0);
		v3_attrNames.push_back(AllVertexAttribName[i]+"_y");
		p.DefineVar(conversion::fromStringToWString(v3_attrNames.back()), &v3_attrValue.back());
		
		v3_attrValue.push_back(0);
		v3_attrNames.push_back(AllVertexAttribName[i]+"_z");
		p.DefineVar(conversion::fromStringToWString(v3_attrNames.back()), &v3_attrValue.back());
		qDebug("Adding custom per vertex Point3f variable %s",v3_attrNames.back().c_str());
	}
}


// Function explicitly define parser variables to perform Per-Face filter action
void FilterFunctionPlugin::setPerFaceVariables(Parser &p, CMeshO &m)
{
	// coord of the three vertices within a face
	p.DefineVar(conversion::fromStringToWString("x0"), &x0);
	p.DefineVar(conversion::fromStringToWString("y0"), &y0);
	p.DefineVar(conversion::fromStringToWString("z0"), &z0);
	p.DefineVar(conversion::fromStringToWString("x1"), &x1);
	p.DefineVar(conversion::fromStringToWString("y1"), &y1);
	p.DefineVar(conversion::fromStringToWString("z1"), &z1);
	p.DefineVar(conversion::fromStringToWString("x2"), &x2);
	p.DefineVar(conversion::fromStringToWString("y2"), &y2);
	p.DefineVar(conversion::fromStringToWString("z2"), &z2);
	
	// attributes of the vertices
	// normals:
	p.DefineVar(conversion::fromStringToWString("nx0"), &nx0);
	p.DefineVar(conversion::fromStringToWString("ny0"), &ny0);
	p.DefineVar(conversion::fromStringToWString("nz0"), &nz0);
	
	p.DefineVar(conversion::fromStringToWString("nx1"), &nx1);
	p.DefineVar(conversion::fromStringToWString("ny1"), &ny1);
	p.DefineVar(conversion::fromStringToWString("nz1"), &nz1);
	
	p.DefineVar(conversion::fromStringToWString("nx2"), &nx2);
	p.DefineVar(conversion::fromStringToWString("ny2"), &ny2);
	p.DefineVar(conversion::fromStringToWString("nz2"), &nz2);
	
	// colors:
	p.DefineVar(conversion::fromStringToWString("r0"), &r0);
	p.DefineVar(conversion::fromStringToWString("g0"), &g0);
	p.DefineVar(conversion::fromStringToWString("b0"), &b0);
	p.DefineVar(conversion::fromStringToWString("a0"), &a0);
	
	p.DefineVar(conversion::fromStringToWString("r1"), &r1);
	p.DefineVar(conversion::fromStringToWString("g1"), &g1);
	p.DefineVar(conversion::fromStringToWString("b1"), &b1);
	p.DefineVar(conversion::fromStringToWString("a1"), &a1);
	
	p.DefineVar(conversion::fromStringToWString("r2"), &r2);
	p.DefineVar(conversion::fromStringToWString("g2"), &g2);
	p.DefineVar(conversion::fromStringToWString("b2"), &b2);
	p.DefineVar(conversion::fromStringToWString("a2"), &a2);
	
	// quality
	p.DefineVar(conversion::fromStringToWString("q0"), &q0);
	p.DefineVar(conversion::fromStringToWString("q1"), &q1);
	p.DefineVar(conversion::fromStringToWString("q2"), &q2);
	
	// face color
	p.DefineVar(conversion::fromStringToWString("fr"), &fr);
	p.DefineVar(conversion::fromStringToWString("fg"), &fg);
	p.DefineVar(conversion::fromStringToWString("fb"), &fb);
	p.DefineVar(conversion::fromStringToWString("fa"), &fa);
	
	// face normal
	p.DefineVar(conversion::fromStringToWString("fnx"), &fnx);
	p.DefineVar(conversion::fromStringToWString("fny"), &fny);
	p.DefineVar(conversion::fromStringToWString("fnz"), &fnz);
	
	// face quality
	p.DefineVar(conversion::fromStringToWString("fq"), &fq);
	
	// index
	p.DefineVar(conversion::fromStringToWString("fi"),&f);
	p.DefineVar(conversion::fromStringToWString("vi0"),&v0i);
	p.DefineVar(conversion::fromStringToWString("vi1"),&v1i);
	p.DefineVar(conversion::fromStringToWString("vi2"),&v2i);
	
	// texture
	p.DefineVar(conversion::fromStringToWString("wtu0"),&wtu0);
	p.DefineVar(conversion::fromStringToWString("wtv0"),&wtv0);
	p.DefineVar(conversion::fromStringToWString("wtu1"),&wtu1);
	p.DefineVar(conversion::fromStringToWString("wtv1"),&wtv1);
	p.DefineVar(conversion::fromStringToWString("wtu2"),&wtu2);
	p.DefineVar(conversion::fromStringToWString("wtv2"),&wtv2);
	p.DefineVar(conversion::fromStringToWString("ti"), &ti);
	
	//selection
	p.DefineVar(conversion::fromStringToWString("vsel0"), &vsel0);
	p.DefineVar(conversion::fromStringToWString("vsel1"), &vsel1);
	p.DefineVar(conversion::fromStringToWString("vsel2"), &vsel2);
	p.DefineVar(conversion::fromStringToWString("fsel"), &fsel);
	
	// define var for user-defined attributes (if any exists)
	// if vector is empty, code won't be executed
	std::vector<std::string> AllFaceAttribName;
	tri::Allocator<CMeshO>::GetAllPerFaceAttribute< float >(m,AllFaceAttribName);
	f_handlers.clear();
	f_attrNames.clear();
	f_attrValue.clear();
	for(int i = 0; i < (int) AllFaceAttribName.size(); i++)
	{
		CMeshO::PerFaceAttributeHandle<float> hh = tri::Allocator<CMeshO>::GetPerFaceAttribute<float>(m, AllFaceAttribName[i]);
		f_handlers.push_back(hh);
		f_attrNames.push_back(AllFaceAttribName[i]);
		f_attrValue.push_back(0);
		p.DefineVar(conversion::fromStringToWString(f_attrNames.back()), &f_attrValue.back());
	}
	
}

FilterPluginInterface::FILTER_ARITY FilterFunctionPlugin::filterArity(const QAction* filter ) const
{
	switch(ID(filter)) 
	{
	case FF_VERT_SELECTION:     
	case FF_FACE_SELECTION:     
	case FF_GEOM_FUNC:          
	case FF_FACE_COLOR:         
	case FF_FACE_QUALITY:       
	case FF_VERT_COLOR:         
	case FF_VERT_QUALITY:       
	case FF_VERT_TEXTURE_FUNC:  
	case FF_WEDGE_TEXTURE_FUNC: 
	case FF_VERT_NORMAL:        
	case FF_DEF_VERT_ATTRIB:    
	case FF_DEF_FACE_ATTRIB:    
	case FF_REFINE:
		return FilterPluginInterface::SINGLE_MESH;
	case FF_GRID:                            
	case FF_ISOSURFACE:         
		return FilterPluginInterface::NONE;
	}
	return FilterPluginInterface::NONE;
}


MESHLAB_PLUGIN_NAME_EXPORTER(FilterFunctionPlugin)
