bool FilterCreateIso::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos * cb)
 {
   md.addNewMesh("",this->filterName(ID(filter)));
   MeshModel &m=*(md.mm());
   if(filter->text() == filterName(FP_CREATEISO) )
   {

     SimpleVolume<SimpleVoxel<Scalarm> > 	volume;

     typedef vcg::tri::TrivialWalker<CMeshO, SimpleVolume<SimpleVoxel<Scalarm> >	> MyWalker;
     typedef vcg::tri::MarchingCubes<CMeshO, MyWalker>	MyMarchingCubes;
     MyWalker walker;

     const int gridSize=par.getInt("Resolution");
     // Simple initialization of the volume with some cool perlin noise
     volume.Init(Point3i(gridSize,gridSize,gridSize), Box3m(Point3m(0,0,0),Point3m(1,1,1)));
     for(int i=0;i<gridSize;i++)
       for(int j=0;j<gridSize;j++)
         for(int k=0;k<gridSize;k++)
           volume.Val(i,j,k)=(j-gridSize/2)*(j-gridSize/2)+(k-gridSize/2)*(k-gridSize/2) + i*gridSize/5*(float)math::Perlin::Noise(i*.2,j*.2,k*.2);

     printf("[MARCHING CUBES] Building mesh...");
     MyMarchingCubes mc(m.cm, walker);
     walker.BuildMesh<MyMarchingCubes>(m.cm, volume, mc, (gridSize*gridSize)/10,cb);
     m.UpdateBoxAndNormals();
   }
   return true;
 }
Example #2
0
SimpleModel* loadModelSTL_ascii(const char* filename, FMatrix3x3& matrix)
{
    SimpleModel* m = new SimpleModel();
    m->volumes.push_back(SimpleVolume());
    SimpleVolume* vol = &m->volumes[0];
    FILE* f = fopen(filename, "rt");
    char buffer[1024];
    FPoint3 vertex;
    int n = 0;
    Point3 v0(0,0,0), v1(0,0,0), v2(0,0,0);
    while(fgets_(buffer, sizeof(buffer), f))
    {
        if (sscanf(buffer, " vertex %lf %lf %lf", &vertex.x, &vertex.y, &vertex.z) == 3)
        {
            n++;
            switch(n)
            {
            case 1:
                v0 = matrix.apply(vertex);
                break;
            case 2:
                v1 = matrix.apply(vertex);
                break;
            case 3:
                v2 = matrix.apply(vertex);
                vol->addFace(v0, v1, v2);
                n = 0;
                break;
            }
        }
    }
    fclose(f);
    return m;
}
Example #3
0
SimpleModel* loadModelSTL_binary(const char* filename, FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rb");
    char buffer[80];
    uint32_t faceCount;
    //Skip the header
    if (fread(buffer, 80, 1, f) != 1)
    {
        fclose(f);
        return NULL;
    }
    //Read the face count
    if (fread(&faceCount, sizeof(uint32_t), 1, f) != 1)
    {
        fclose(f);
        return NULL;
    }
    //For each face read:
    //float(x,y,z) = normal, float(X,Y,Z)*3 = vertexes, uint16_t = flags
    SimpleModel* m = new SimpleModel();
    m->volumes.push_back(SimpleVolume());
    SimpleVolume* vol = &m->volumes[0];
	if(vol == NULL)
	{
		fclose(f);
		return NULL;
	}

    for(unsigned int i=0;i<faceCount;i++)
    {
        if (fread(buffer, sizeof(float) * 3, 1, f) != 1)
        {
            fclose(f);
            return NULL;
        }
        float v[9];
        if (fread(v, sizeof(float) * 9, 1, f) != 1)
        {
            fclose(f);
            return NULL;
        }
        Point3 v0 = matrix.apply(FPoint3(v[0], v[1], v[2]));
        Point3 v1 = matrix.apply(FPoint3(v[3], v[4], v[5]));
        Point3 v2 = matrix.apply(FPoint3(v[6], v[7], v[8]));
        vol->addFace(v0, v1, v2);
        if (fread(buffer, sizeof(uint16_t), 1, f) != 1)
        {
            fclose(f);
            return NULL;
        }
    } 
    fclose(f);
    return m;
}
Example #4
0
void CreateNoisyIsosurface(uintptr_t _m, int gridSize)
{
  MyMesh &m = *((MyMesh*) _m);
  SimpleVolume<SimpleVoxel<float> > 	volume;

  typedef vcg::tri::TrivialWalker<MyMesh, SimpleVolume<SimpleVoxel<float> >	> MyWalker;
  typedef vcg::tri::MarchingCubes<MyMesh, MyWalker>	MyMarchingCubes;
  MyWalker walker;

  // Simple initialization of the volume with some cool perlin noise
  volume.Init(Point3i(gridSize,gridSize,gridSize), Box3f(Point3f(0,0,0),Point3f(1,1,1)));
  for(int i=0;i<gridSize;i++)
    for(int j=0;j<gridSize;j++)
      for(int k=0;k<gridSize;k++)
        volume.Val(i,j,k)=(j-gridSize/2)*(j-gridSize/2)+(k-gridSize/2)*(k-gridSize/2) + i*gridSize/5*(float)math::Perlin::Noise(i*.2,j*.2,k*.2);

  printf("[MARCHING CUBES] Building mesh...\n");
  MyMarchingCubes mc(m, walker);
  walker.BuildMesh<MyMarchingCubes>(m, volume, mc, (gridSize*gridSize)/10);
}
Example #5
0
SimpleModel* loadModel(const char* filename, FMatrix3x3& matrix)
{
    const char* ext = strrchr(filename, '.');
    if (ext && strcasecmp(ext, ".stl") == 0)
    {
        return loadModelSTL(filename, matrix);
    }
    if (filename[0] == '#' && binaryMeshBlob != NULL)
    {
        SimpleModel* m = new SimpleModel();
        
        while(*filename == '#')
        {
            filename++;
            
            m->volumes.push_back(SimpleVolume());
            SimpleVolume* vol = &m->volumes[m->volumes.size()-1];
            int32_t n, pNr = 0;
            if (fread(&n, 1, sizeof(int32_t), binaryMeshBlob) < 1)
                return NULL;
            log("Reading mesh from binary blob with %i vertexes\n", n);
            Point3 v[3];
            while(n)
            {
                float f[3];
                if (fread(f, 3, sizeof(float), binaryMeshBlob) < 1)
                    return NULL;
                FPoint3 fp(f[0], f[1], f[2]);
                v[pNr++] = matrix.apply(fp);
                if (pNr == 3)
                {
                    vol->addFace(v[0], v[1], v[2]);
                    pNr = 0;
                }
                n--;
            }
        }
        return m;
    }
    return NULL;
}
Example #6
0
void createSphereInVolume(SimpleVolume<Density8>& volData, float fRadius)
{
	//This vector hold the position of the center of the volume
	Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2);

	//This three-level for loop iterates over every voxel in the volume
	for (int z = 0; z < volData.getWidth(); z++)
	{
		for (int y = 0; y < volData.getHeight(); y++)
		{
			for (int x = 0; x < volData.getDepth(); x++)
			{
				//Store our current position as a vector...
				Vector3DFloat v3dCurrentPos(x,y,z);	
				//And compute how far the current position is from the center of the volume
				float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length();

				if(fDistToCenter <= fRadius)
				{
					//Our new density value
					uint8_t uDensity = Density8::getMaxDensity();

					//Get the old voxel
					Density8 voxel = volData.getVoxelAt(x,y,z);

					//Modify the density
					voxel.setDensity(uDensity);

					//Wrte the voxel value into the volume	
					volData.setVoxelAt(x, y, z, voxel);
				}

				//144 in the middle, (144 - 32) at the edges. Threshold of 128 is between these
				//volData.setVoxelAt(x, y, z, 144 - fDistToCenter);
			}
		}
	}
}
Example #7
0
void render_gdpt(const char *filename, const int width, const int height, const int num_sample_per_subpixel, const int num_thread, unsigned long long seed,
                 const SimpleVolume& ovolume,
                 const rt::PerspectiveCamera& camera) {

    std::vector<Color> coarse_image(width * height);
    std::vector<Color> debug_image(width * height);
    std::vector<Color> diff_image[4];
    for (int i = 0; i < 4; ++i)
        diff_image[i].resize(width * height);

    Timer timer;
    timer.begin();

    for (int iy = 0; iy < height; ++iy) {
        std::cout << "y: " << iy << std::endl;
        #pragma omp parallel for schedule(dynamic, 1) num_threads(8)
        for (int ix = 0; ix < width; ++ix) {
            Random random((unsigned long long)(iy * width + ix));

            const int image_index = iy * width + ix;
            for (int ss = 0; ss < num_sample_per_subpixel; ++ss) {
                float sx = random.next01();
                float sy = random.next01();

                std::vector<Vertex> baseVertices;
                baseVertices.reserve(16);
                float basePathPDF = 1;
                Color baseContritbuion;
                Color finalL;

                float baseX = ix + sx;
                float baseY = iy + sy;
                const unsigned long long random2_seed = (unsigned long long)(iy * width + ix) * num_sample_per_subpixel + ss;
                rt::Ray base_ray;
                {
                    const float u = baseX / width;
                    const float v = baseY / height;
                    base_ray = camera.get_ray(u, v);
                    baseContritbuion = radiance_gdpt(random, random, ovolume, base_ray, &baseVertices, &basePathPDF, &finalL);
                }

                if (basePathPDF > 0)
                    coarse_image[image_index] += baseContritbuion / basePathPDF;
                if (basePathPDF <= 0)
                    continue;
                // 4 sub-path
                const Float3 offset[4] = {
                    Float3( 1, 0, 0),
                    Float3(-1, 0, 0),
                    Float3( 0, 1, 0),
                    Float3( 0,-1, 0)
                };
                std::vector<Vertex> offsetVertices[4];
                for (int offsetDir = 0; offsetDir < 4; ++offsetDir) {
                    const float u = (baseX + offset[offsetDir].x) / width;
                    const float v = (baseY + offset[offsetDir].y) / height;
                    const rt::Ray offset_ray = camera.get_ray(u, v);
                    offsetVertices[offsetDir].reserve(16);

                    enum Result {
                        Naive,
                        Invertible
                    };

                    // Shift
                    rt::Ray current_ray = offset_ray;
                    Result result = Naive;

                    // baseが少なくとも2回は散乱している、有効なパスのときのみ考える
                    Color offsetContribution;
                    float J = 0;
                    if (basePathPDF > 0 && baseVertices.size() >= 3) {
                        const float initial_length = (baseVertices[1].position - base_ray.org).length();

                        const Float3 offset_dir0 = current_ray.dir;
                        const Float3 offset_1 = current_ray.org + initial_length * offset_dir0;

                        if (!ovolume.inside(offset_1)) {
                            // offsetが外に出てしまったので、Naiveにやる
                        } else {
                            result = Invertible;
                            float hitt0 = -1, hitt1 = -1;
                            ovolume.check_intersect(current_ray, &hitt0, &hitt1);

                            const Float3 new_org0 = current_ray.org + (hitt0 + 1e-3f) * offset_dir0;
                            const Float3 new_org1 = current_ray.org + (hitt1 + 1e-3f) * offset_dir0;
                            if (!ovolume.inside(current_ray.org)) {
                                // Volumeの外だったら中からスタート
                                current_ray.org = new_org0;
                            }
                            const Float3 offset_0 = current_ray.org;



                            // Baseの3個目の頂点につなげる
                            const Float3 offset_2 = baseVertices[2].position;

                            // 0 - 1と 1- 2の間のtransmittanceを求める
                            const rt::Ray ray01(offset_0, normalize(offset_1 - offset_0));
                            const rt::Ray ray12(offset_1, normalize(offset_2 - offset_1));
                            const float length01 = (offset_0 - offset_1).length();
                            const float length12 = (offset_1 - offset_2).length();
                            float transmittance01 = 0;
                            float transmittance12 = 0;
                            const int kNumSample = 16;


                            /*
                            {
                                float sum = 0;
                                for (int i = 0; i < kNumSample; ++i) {
                                    const float current = length01 / kNumSample * (i + random.next01());
                                    sum += ovolume.sample_transmittance(ray01.org + current * ray01.dir) / kNumSample;
                                }
                                transmittance01 = exp(-sum);
                            }
                            {
                                float sum = 0;
                                for (int i = 0; i < kNumSample; ++i) {
                                    const float current = length12 / kNumSample * (i + random.next01());
                                    sum += ovolume.sample_transmittance(ray12.org + current * ray12.dir) / kNumSample;
                                }
                                transmittance12 = exp(-sum);
                            }
                            */
                            for (int i = 0; i < kNumSample; ++i) {
                                const float X = ovolume.next_event(ray01, random);
                                if (!(0 <= X && X < length01)) {
                                    transmittance01 += 1.0f / kNumSample;
                                }

                            }
                            /*
                                if (baseVertices[1].transmittance != transmittance01)
                                    printf("%f %f\n", baseVertices[1].transmittance, transmittance01);
                                */
                            for (int i = 0; i < kNumSample; ++i) {
                                const float X = ovolume.next_event(ray12, random);
                                if (!(0 <= X && X < length12)) {
                                    transmittance12 += 1.0f / kNumSample;
                                }
                            }

                            // ヤコビアン計算
                            J = (baseVertices[2].position - baseVertices[1].position).lengthSquared() /
                                (offset_2 - offset_1).lengthSquared();

                            // 残りのTransmittanceはBaseと同じ!
                            float total_transmittance = transmittance01 * transmittance12;
                            for (int i = 3; i < baseVertices.size(); ++i)
                                total_transmittance *= baseVertices[i].transmittance;

                            // その他の要素
                            const float phase = 1.0f / (4.0f * kPI);
                            const int numScattering = baseVertices.size() - 1;

                            const float throughput = total_transmittance * pow(phase * kAlbedo, numScattering);

                            offsetContribution = throughput * finalL;

                        }
                    }
                    Color accum;
                    if (result == Naive) {
                        /*
                        if (iy > 100)
                        printf("%f %d\n", basePathPDF, baseVertices.size());
                        */

                        float pdf = 1;
                        const Float3 contribution = radiance(random, ovolume, offset_ray, &pdf);
                        if (pdf > 0) {
                            accum = baseContritbuion / basePathPDF - contribution / pdf;
                        } else {
                            accum = baseContritbuion / basePathPDF;
                        }


                        /*
                        if (ix == 320 && iy == 240) {
                            printf("%f %f %f %f\n", baseContritbuion.x, basePathPDF, contribution.x, pdf);
                            std::cout << accum << std::endl;
                        }
                        */
                    } else {
                        // printf("%f %f %f\n", baseContritbuion.x, offsetContribution.x, J);
                        accum = 0.5f * (baseContritbuion - offsetContribution * J) / basePathPDF;

                    }

                    // 前方差分 or 後方差分
                    if (offsetDir == 1 || offsetDir == 2)
                        diff_image[offsetDir][image_index] += accum;
                    else
                        diff_image[offsetDir][image_index] += -accum;
                }
            }
            coarse_image[image_index] = coarse_image[image_index] / num_sample_per_subpixel;
            for (int i = 0; i < 4; ++i)
                diff_image[i][image_index] = diff_image[i][image_index] / num_sample_per_subpixel;
        }
    }

    std::cout << "Time: " << (timer.end() / 1000.0f) << " sec" << std::endl;

    char buf[256];
    char name[4][256] = {
        "__1_0",
        "_-1_0",
        "__0_1",
        "__0-1"
    };
    sprintf(buf, "%s_J.hdr", filename);
    save_hdr_file(buf, &debug_image[0], width, height);

    sprintf(buf, "%s_coarse.hdr", filename);
    save_hdr_file(buf, &coarse_image[0], width, height);
    sprintf(buf, "%s_coarse.bin", filename);
    save_binary_file(buf, &coarse_image[0], width, height);

    for (int i = 0; i < 4; ++i) {
        sprintf(buf, "%s_%s.hdr", filename, name[i]);
        save_hdr_file(buf, &diff_image[i][0], width, height);
        sprintf(buf, "%s_%s.bin", filename, name[i]);
        save_binary_file(buf, &diff_image[i][0], width, height);
    }
}
Example #8
0
Float3 radiance_gdpt(Random& random, Random& random2, const SimpleVolume& volume, const rt::Ray& initial_ray, std::vector<Vertex>* vertices, float *path_pdf, Color *finalL) {
    const int kMaxScattering = 256;

    rt::Ray current_ray = initial_ray;

    Color througput(1, 1, 1);
    Color L(0, 0, 0);


    for (int scattering = 0; scattering < kMaxScattering; ++scattering) {
        // VolumeのBBoxにヒットするか否か
        float hitt0 = -1, hitt1 = -1;
        bool is_volume_hit = false;
        if (volume.check_intersect(current_ray, &hitt0, &hitt1)) {
            is_volume_hit = true;
        }

        rt::Hitpoint current_hp;
        if (!volume.inside(current_ray.org)) {
            if (is_volume_hit) {
                current_hp.distance = hitt0;
            }
        }

        if (!is_volume_hit) {
            L += outside(current_ray);
            break;
        }

        const Float3 new_org0 = current_ray.org + (hitt0 + 1e-3f) * current_ray.dir;
        const Float3 new_org1 = current_ray.org + (hitt1 + 1e-3f) * current_ray.dir;
        if (!volume.inside(current_ray.org)) {
            // Volumeの外だったら中からスタート
            current_ray.org = new_org0;
        }
        if (scattering == 0) {
            // 一個目の頂点を入れる
            vertices->push_back(Vertex(current_ray.org, current_ray.dir, 1));
        }
        const float tu = volume.next_event(current_ray, random);
        if (tu < 0) {
            // ボリューム外
            current_ray.org = new_org1;
            continue;
        }

        // 散乱した!

        // pdf_transmittance
        float transmittance = 0;
        const int kNumSample = 16;
        /*
        {
            float sum = 0;
            for (int i = 0; i < kNumSample; ++i) {
                const float length = tu;

                const float current = length / kNumSample * (i + random.next01());

                sum += volume.sample_transmittance(current_ray.org + current * current_ray.dir) / kNumSample;
            }

            transmittance = exp(-sum);
        }*/
        for (int i = 0; i < kNumSample; ++i) {
            const float X = volume.next_event(current_ray, random2);
            if (!(0 <= X && X < tu)) {
                transmittance += 1.0f / kNumSample;
            }
        }

        const Float3 next_pos = current_ray.org + tu * current_ray.dir;
        const bool cond2 = random.next01() < kAlbedo;
        if (!cond2) {
            *path_pdf = 0;
            througput = Float3(0, 0, 0); // absorp
            break;
        }

        // 位相関数でインポータンスサンプリング
        // 今回はとりあえず等方散乱としておく
        const Float3 next_dir = Sampling::uniformSphereSurface(random);
        const float phase = 1.0f / (4.0f * kPI);
        const float pdf_phase = 1.0f / (4.0f * kPI);

        /*
        througput *= 0.99f;
        *path_pdf *= 0.99f;
        */

        througput *= transmittance * phase * kAlbedo;
        *path_pdf *= transmittance * pdf_phase * kAlbedo;


        // 頂点追加
        vertices->push_back(Vertex(next_pos, next_dir, transmittance));


        // throughtput = (phase / pdf) * throughtput;
        current_ray = rt::Ray(next_pos, next_dir);
    }
    *finalL = L;

    return times(L, througput);
}
Example #9
0
Float3 radiance(Random& random, const SimpleVolume& volume, const rt::Ray& initial_ray, float *path_pdf) {
    const int kMaxScattering = 256;

    rt::Ray current_ray = initial_ray;

    Color througput(1, 1, 1);
    Color L(0, 0, 0);
    for (int scattering = 0; scattering < kMaxScattering; ++scattering) {
        // VolumeのBBoxにヒットするか否か
        float hitt0 = -1, hitt1 = -1;
        bool is_volume_hit = false;
        if (volume.check_intersect(current_ray, &hitt0, &hitt1)) {
            is_volume_hit = true;
        }

        rt::Hitpoint current_hp;
        if (!volume.inside(current_ray.org)) {
            if (is_volume_hit) {
                current_hp.distance = hitt0;
            }
        }

        if (!is_volume_hit) {
            L += outside(current_ray);
            break;
        }

        const Float3 new_org0 = current_ray.org + (hitt0 + 1e-3f) * current_ray.dir;
        const Float3 new_org1 = current_ray.org + (hitt1 + 1e-3f) * current_ray.dir;
        if (!volume.inside(current_ray.org)) {
            // Volumeの外だったら中からスタート
            current_ray.org = new_org0;
        }

        const float tu = volume.next_event(current_ray, random);
        if (tu < 0) {
            // ボリューム外
            current_ray.org = new_org1;
            continue;
        }

        // pdf_transmittance
        float transmittance = 0;
        const int kNumSample = 16;
        for (int i = 0; i < kNumSample; ++i) {
            const float X = volume.next_event(current_ray, random);
            if (!(0 <= X && X < tu)) {
                transmittance += 1.0f / kNumSample;
            }
        }

        const Float3 next_pos = current_ray.org + tu * current_ray.dir;
        const bool cond2 = random.next01() < kAlbedo;
        if (!cond2) {
            througput = Float3(0, 0, 0); // absorp
            break;
        }


        // 位相関数でインポータンスサンプリング
        // 今回はとりあえず等方散乱としておく
        const Float3 next_dir = Sampling::uniformSphereSurface(random);
        const float phase = 1.0f / (4.0f * kPI);
        const float pdf_phase = 1.0f / (4.0f * kPI);

        /*
        througput *= 0.99f;
        *path_pdf *= 0.99f;
        */

        througput *= transmittance * phase * kAlbedo;
        *path_pdf *= transmittance * pdf_phase * kAlbedo;



        // throughtput = (phase / pdf) * throughtput;
        current_ray = rt::Ray(next_pos, next_dir);
    }

    return times(L, througput);
}
Example #10
0
// The Real Core Function doing the actual mesh processing.
bool FilterFunctionPlugin::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb)
{
  if(this->getClass(filter) == MeshFilterInterface::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();
			
				// muparser initialization and explicitely define parser variables
				Parser p;
        setPerVertexVariables(p,m.cm);

				// set expression inserted by user as string (required by muparser)
				p.SetExpr(expr);

				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 = e.GetMsg().c_str();
  						return false;
					}

					// set vertex as selected or clear selection
					if(selected) { 
						(*vi).SetS();
						numvert++;
					} else (*vi).ClearS();
				}

				// strict face selection
				if(par.getBool("strictSelect"))
						tri::UpdateSelection<CMeshO>::FaceFromVertexStrict(m.cm); 
				else  
						tri::UpdateSelection<CMeshO>::FaceFromVertexLoose(m.cm); 
		
				// if succeded 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 explicitely define parser variables
				Parser p;
        setPerFaceVariables(p,m.cm);

				// set expression inserted by user as string (required by muparser)
				p.SetExpr(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 = e.GetMsg().c_str();
  						return false;
					}

					// set face as selected or clear selection
					if(selected) { 
						(*fi).SetS();
						numface++;
					} else (*fi).ClearS();
				}

				// if succeded 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();

				// muparser initialization and explicitely 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(func_x);
				p2.SetExpr(func_y);
				p3.SetExpr(func_z);
        p4.SetExpr(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())
				{
					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() = Point3f(newx,newy,newz); 
          if(ID(filter) == FF_VERT_COLOR) // set new color for this iteration
            (*vi).C() = Color4b(newx,newy,newz,newa);
          if(ID(filter) == FF_VERT_NORMAL) // set new color for this iteration
            (*vi).N() = Point3f(newx,newy,newz);
          }

				if(ID(filter) == FF_GEOM_FUNC) {
					// update bounding box, normalize normals
					tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m.cm);
					tri::UpdateNormals<CMeshO>::NormalizeFace(m.cm);
					tri::UpdateBounding<CMeshO>::Box(m.cm);
				}

				// if succeded 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();
				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(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())
				{
					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 = 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>::VertexQualityRamp(m.cm);

				// if succeded 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_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();

				// muparser initialization and explicitely 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(func_r);
				p2.SetExpr(func_g);
				p3.SetExpr(func_b);
        p4.SetExpr(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())
				{
					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 succeded 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();
				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(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())
				{
					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>::FaceQualityRamp(m.cm);

				// if succeded 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>::GetPerVertexAttribute<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 %i vertex float attribute",AllVertexAttribName.size());
				Parser p;
        setPerVertexVariables(p,m.cm);
				p.SetExpr(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 = 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 possibile to use custom attributes in other filters
				v_attrNames.push_back(name);
				v_attrValue.push_back(0);
        v_handlers.push_back(h);

				// if succeded 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>::GetPerFaceAttribute<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(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 = 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 possibile to use custom attributes in other filters
//				f_attrNames.push_back(name);
//				f_attrValue.push_back(0);
//				fhandlers.push_back(h);

				// if succeded 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
				std::vector<float> data(w*h,0);
				tri::Grid<CMeshO>(m.cm, w, h, wl, hl, &data[0]);

				// if "centered on origin" is checked than move generated Grid in (0,0,0)
				if(par.getBool("center")) 
				{
					// move x and y
					double halfw = double(w-1)/2;
					double halfh = double(h-1)/2;
					double wld = wl/double(w);
					double hld = hl/float(h);

					CMeshO::VertexIterator vi;
					for(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
        Matrix44f rot; rot.SetRotateDeg(180,Point3f(0,1,0));
        tri::UpdatePosition<CMeshO>::Matrix(m.cm,rot,false);
				tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m.cm);	
				tri::UpdateNormals<CMeshO>::NormalizeFace(m.cm);
				tri::UpdateBounding<CMeshO>::Box(m.cm);
				
				return true;
			}
		break;
		case FF_ISOSURFACE :
			{
					SimpleVolume<SimpleVoxel> 	volume;
		
					typedef vcg::tri::TrivialWalker<CMeshO, SimpleVolume<SimpleVoxel> >	MyWalker;
					typedef vcg::tri::MarchingCubes<CMeshO, MyWalker>	MyMarchingCubes;
					MyWalker walker;
		
					Box3d rbb;
					rbb.min[0]=par.getFloat("minX");
					rbb.min[1]=par.getFloat("minY");
					rbb.min[2]=par.getFloat("minZ");
					rbb.max[0]=par.getFloat("maxX");
					rbb.max[1]=par.getFloat("maxY");
					rbb.max[2]=par.getFloat("maxZ");
					double step=par.getFloat("voxelSize");
					Point3i siz= Point3i::Construct((rbb.max-rbb.min)*(1.0/step));
					
					Parser p;
					double x,y,z;
					p.DefineVar("x", &x);
					p.DefineVar("y", &y);
					p.DefineVar("z", &z);
					std::string expr = par.getString("expr").toStdString();
					p.SetExpr(expr);
					Log("Filling a Volume of %i %i %i",siz[0],siz[1],siz[2]);
					volume.Init(siz);
					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 = rbb.min[0]+step*i;
							 y = rbb.min[1]+step*j;
							 z = rbb.min[2]+step*k;
							 	try {
										volume.Val(i,j,k)=p.Eval();
										} catch(Parser::exception_type &e) {
												errorMessage = 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);
		Matrix44f tr; tr.SetIdentity(); tr.SetTranslate(rbb.min[0],rbb.min[1],rbb.min[2]);
		Matrix44f sc; sc.SetIdentity(); sc.SetScale(step,step,step);
		tr=tr*sc;
		
		tri::UpdatePosition<CMeshO>::Matrix(m.cm,tr);
		tri::UpdateNormals<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 choosen with MidPointCustom created above
				RefineE<CMeshO, MidPointCustom<CMeshO>, CustomEdge<CMeshO> >
					(m.cm, mid, edge, false, cb);

				m.clearDataMask( MeshModel::MM_VERTMARK);
				vcg::tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m.cm);

				return true;
			}
		break;

		default : assert (0);
	}
	return false;
}