Raw File
voxel_resampler.cpp
#include "voxel_resampler.h"

#include "DynamicVoxel.h"
#include "Voxeler.h"

#include <QStack>
#include <QSet>

void voxel_resampler::initParameters(RichParameterSet *pars)
{
	pars->addParam(new RichBool("apply_original", true, "Apply to original", ""));
	pars->addParam(new RichFloat("voxel_scale", 0.1f, "Voxel scale", "Voxel scale in % of maximum bounding extent"));
	pars->addParam(new RichBool("keep_inside", false, "Keep inner sheels", ""));
	pars->addParam(new RichFloat("mcf_smoothing", 0.0f, "MCF Smoothing", ""));
	pars->addParam(new RichInt("laplacian_smoothing", 2, "Laplacian Smoothing", ""));
}

void voxel_resampler::applyFilter(RichParameterSet *pars)
{
	// Voxel size
	double vox_scale = pars->getFloat("voxel_scale");
	double voxel_size = vox_scale * mesh()->bbox().diagonal().norm();

	// Voxelize the mesh
	VoxelerLibrary::Voxeler voxeler(mesh(), voxel_size, true);
	//std::vector<VoxelerLibrary::Voxel> voxels = voxeler.fillInside();
	std::vector<VoxelerLibrary::Voxel> voxels = voxeler.voxels;

	// Add voxels to a Dynamic Voxel object
	DynamicVoxelLib::DynamicVoxel vox(voxel_size);
	vox.begin();
	foreach(VoxelerLibrary::Voxel v, voxels) vox.setVoxel(v.x, v.y, v.z);
	vox.end();

	// Build mesh
	SurfaceMesh::Model m (mesh()->path, mesh()->name);
	SurfaceMeshModel * outMesh = &m; // assume we use all output of voxelization step

	vox.buildMesh( &m );
	m.triangulate();

	bool apply_original = pars->getBool("apply_original");

	if( apply_original )
	{
		// Remove original geometry
		outMesh = mesh();
	}
	else
	{
		outMesh = new SurfaceMeshModel(m.path, m.name);
		document()->addModel( outMesh );
	}

	/// Remove inner shells if requested
	if( !pars->getBool("keep_inside") )
	{
		// Find new mesh segments
		Vector3VertexProperty points = m.vertex_property<Vector3>(VPOINT);

		QVector< QSet<int> > segments;
		SurfaceMesh::Model::Face_property<bool> fvisited = m.add_face_property<bool>("f:visited", false);
		int visitedCount = 0;

		while(visitedCount < (int)m.n_faces()){
			QStack<SurfaceMesh::Model::Face> tovisit;

			// Seed face
			foreach(SurfaceMesh::Model::Face f, m.faces()){
				if(!fvisited[f]){
					tovisit.push(f);
					break;
				}
			}

			segments.push_back( QSet<int>() );

			while( !tovisit.isEmpty() )	{
				SurfaceMesh::Model::Face f = tovisit.pop();
				SurfaceMesh::Model::Halfedge_around_face_circulator adjE(&m, f), eend = adjE;
				fvisited[f] = true;
				segments.back().insert(f.idx());

				do{ 
					Face adjF = m.face( m.opposite_halfedge(adjE) );

					if( !fvisited[adjF] ){
						tovisit.push(adjF);
						fvisited[adjF] = true;
						segments.back().insert(adjF.idx());
					}
				} while(++adjE != eend);
			}

			visitedCount += segments.back().size();
		}

		// Sorted by size
		QMap< int, QSet<int> > segmentMap;
		foreach(QSet<int> segment, segments) segmentMap[segment.size()] = segment;

		// Assumption: keep every other
		QVector< QSet<int> > allSegments = segmentMap.values().toVector();

		outMesh->isVisible = false;
		outMesh->clear();

		// One segment case: Skip extraction step
		if(allSegments.size() == 1){
			foreach(Vertex v, m.vertices()) outMesh->add_vertex( points[v] );
			foreach(Face f, m.faces()){
				std::vector<Vertex> verts;
				Surface_mesh::Vertex_around_face_circulator vit = m.vertices(f),vend=vit;
				do{ verts.push_back( vit ); } while(++vit != vend);
				outMesh->add_face(verts);
			}
		}
		else
		{
			// Collect set of used vertices
			QSet<int> vset, fset;
			QMap<int,int> vmap;

			for (int si = 0; si < (int)allSegments.size(); si++)
			{
				// Even indices starting from zero
				if(si % 2 == 0) continue;

				foreach( int fidx, allSegments[si] )
				{
					Face face(fidx);
					Surface_mesh::Vertex_around_face_circulator vit = m.vertices(face),vend=vit;
					do{ vset.insert( Vertex(vit).idx() ); } while(++vit != vend);
					fset.insert(fidx);
				}
			}

			// Remap vertex indices and add to new mesh
			foreach(int vi, vset)
			{
				vmap[vi] = vmap.size();
				outMesh->add_vertex( points[Vertex(vi)] );
			}

			// Add faces to new mesh
			foreach(int fi, fset)
			{
				std::vector<Vertex> verts;
				Surface_mesh::Vertex_around_face_circulator vit = m.vertices(Face(fi)),vend=vit;
				do{ verts.push_back( Vertex( vmap[ Vertex(vit).idx() ] ) ); } while(++vit != vend);
				outMesh->add_face(verts);
			}
		}
	}

	// Post processing:
	if(pars->getFloat("mcf_smoothing") > 0.0) DynamicVoxelLib::DynamicVoxel::MeanCurvatureFlow( outMesh, voxel_size * pars->getFloat("mcf_smoothing") );
	if(pars->getInt("laplacian_smoothing") > 0){
		for(int i = 0; i < pars->getInt("laplacian_smoothing"); i++)
			vox.LaplacianSmoothing( outMesh );
	}

	// Clean up
	outMesh->updateBoundingBox();
	outMesh->update_face_normals();
	outMesh->update_vertex_normals();
	outMesh->isVisible = true;
}

Q_EXPORT_PLUGIN(voxel_resampler)
back to top