1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#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)