All pastes #775298 Raw Edit

houlala

public cpp v1 · immutable
·published 2007-11-15 15:33 UTC
rendered paste body
// Dimitri Kudelski (Master SIS 2 Pro - Imagerie Numerique)// Projet de Modelisation Geometrique : surfaces de subdivision//// Derniere modification : 10 Octobre 2007//// classe heSubdivider // he_subdivider.cpp// gestionnaire de subdivisions (undo/redo, etc...)#include <he_subdivider.h>#include <math.h>using namespace std;// constructeur par defaut//// construit le gestionnaire avec les valeurs par defaut//heSubdivider :: heSubdivider() : currentMesh(NULL){}// methode de nettoyage de liste :)//// supprime toute la fin de la liste pour ne pas bugger lors d'un redo//void heSubdivider :: clearEndList(){	list<heMesh *>::iterator it = currentMesh;	meshList.erase(++it, meshList.end());}heMesh * heSubdivider :: subLoop(heMesh * _mesh){	heMesh * result;	// variable de parcours	heHalfEdge * he;		// variables pour le triangle :)	heHalfEdge * he1, * he2, * he3;	vec3 mid;		// coefficient de positionnement	float beta;	int boundaries;		// tableaux pour tenir les nouvelles creations	heVertex * new_vertices[3];	heVertex * new_edges   [3];		if(_mesh->type != heMesh::MeshTriangulated)		return NULL;		result = new heMesh();		// augmentation du niveau de subdivision	result->level = _mesh->level + 1;		for(heEdge * ptr = _mesh->edges; ptr; ptr = ptr->next)	{		ptr->half->data = NULL;	}		for(heVertex * ptr = _mesh->vertices; ptr; ptr = ptr->next)	{		boundaries = 0;		he1 = NULL;		he2 = NULL;				ptr->data	 = NULL;		ptr->valence = ptr->edges.size();		ptr->average = vec3::zero;				for(list<heHalfEdge *>::iterator it = ptr->edges.begin(); it != ptr->edges.end(); it++)		{			if((*it)->twin == NULL)			{				boundaries++;								if(he1 == NULL)					he1 = *it;				else					he2 = *it;			}						if((*it)->head != ptr)				ptr->average += (*it)->head->coord;			else				ptr->average += (*it)->tail->coord;		}				if(boundaries == 0)		{			beta = (0.625 - pow(0.375 + 0.25 * cos(2.0 * M_PI / ptr->valence), 2)) / ptr->valence;			mid  = ptr->coord * (1.0 - ptr->valence * beta) + ptr->average * beta;		}		else		{			mid = vec3::zero;						if(boundaries != 2)			{				beta = (0.625 - pow(0.375 + 0.25 * cos(2.0 * M_PI / ptr->valence), 2)) / ptr->valence;				mid  = ptr->coord * (1.0 - ptr->valence * beta) + ptr->average * beta;			}			else			{				if(he1->tail != ptr)					mid += he1->tail->coord;				else					mid += he1->head->coord;								if(he2->tail != ptr)					mid += he2->tail->coord;				else					mid += he2->head->coord;								mid += ptr->coord * 6.0;				mid /= 8.0;			}		}				ptr->data = result->buildVertex(mid);	}		for(heFace * ptr = _mesh->faces; ptr; ptr = ptr->next)	{		he = ptr->edge;		do		{			he1 = he;			he2 = he1->next;						if(he1->data == NULL)			{				mid = (he1->tail->coord + he1->head->coord) * 0.5;								if(he1->twin != NULL)					mid = (he1->tail->coord + he1->head->coord) * 0.375 + (he2->head->coord + he1->twin->next->head->coord) * 0.125;								he1->data = result->buildVertex(mid);								if(he1->twin != NULL)					he1->twin->data = he1->data;			}						he = he->next;		}		while(he != ptr->edge);	}		for(heFace * ptr = _mesh->faces; ptr; ptr = ptr->next)	{				uint i = 0;		he = ptr->edge;		do		{			new_vertices[i] = he->tail->data;			new_edges   [i] = he->data;						i++;			he = he->next;		}		while(he != ptr->edge);				he1 = result->buildEdge(new_vertices[0], new_edges[0]   )->half;		he2 = result->buildEdge(new_edges[0],    new_edges[2]   )->half;		he3 = result->buildEdge(new_edges[2],    new_vertices[0])->half;				result->linkHalfEdges(he1, he2);		result->linkHalfEdges(he2, he3);		result->linkHalfEdges(he3, he1);				result->buildFace(he1);				he1 = result->buildEdge(new_vertices[1], new_edges[1]   )->half;		he2 = result->buildEdge(new_edges[1],    new_edges[0]   )->half;		he3 = result->buildEdge(new_edges[0],    new_vertices[1])->half;				result->linkHalfEdges(he1, he2);		result->linkHalfEdges(he2, he3);		result->linkHalfEdges(he3, he1);				result->buildFace(he1);				he1 = result->buildEdge(new_vertices[2], new_edges[2]   )->half;		he2 = result->buildEdge(new_edges[2],    new_edges[1]   )->half;		he3 = result->buildEdge(new_edges[1],    new_vertices[2])->half;				result->linkHalfEdges(he1, he2);		result->linkHalfEdges(he2, he3);		result->linkHalfEdges(he3, he1);				result->buildFace(he1);				he1 = result->buildEdge(new_edges[0], new_edges[1])->half;		he2 = result->buildEdge(new_edges[1], new_edges[2])->half;		he3 = result->buildEdge(new_edges[2], new_edges[0])->half;				result->linkHalfEdges(he1, he2);		result->linkHalfEdges(he2, he3);		result->linkHalfEdges(he3, he1);				result->buildFace(he1);	}		result->type = heMesh::MeshTriangulated;		result->updateVerticesInfo();	return result;}heMesh * heSubdivider :: subCatmullClark(heMesh * _mesh){	heMesh * result = new heMesh();		vec3 mid;	uint n;	heHalfEdge * he, * he1, * he2, * he3, * he4;	float beta;	bool twin;		result->level = _mesh->level + 1;		for(heEdge * ptr = _mesh->edges; ptr; ptr = ptr->next)	{		ptr->half->data = NULL;	}		for(heVertex * ptr = _mesh->vertices; ptr; ptr = ptr->next)	{		ptr->data = NULL;		ptr->valence = ptr->edges.size();	}		for(heFace * ptr = _mesh->faces; ptr; ptr = ptr->next)	{		n   = 0;		mid = vec3::zero;		he  = ptr->edge;		do		{			n++;			mid += he->tail->coord;						he = he->next;		}		while(he != ptr->edge);				mid /= n;		ptr->data = result->buildVertex(mid);	}		for(heEdge * ptr = _mesh->edges; ptr; ptr = ptr->next)	{		he  = ptr->half;				if(he->data == NULL)		{			mid = he->tail->coord + he->head->coord;						if(he->twin != NULL)			{				mid += he->face->data->coord + he->twin->face->data->coord;				mid *= 0.25;			}			else				mid *= 0.5;						he->data = result->buildVertex(mid);						if(he->twin != NULL)				he->twin->data = he->data;		}	}		vec3 midE, midF;	for(heVertex * ptr = _mesh->vertices; ptr; ptr = ptr->next)	{		twin = true;		n = ptr->valence;		mid  = vec3::zero;		midE = vec3::zero;		midF = vec3::zero;				if(n > 2)		{			list<heFace *> faceList;						beta = 1.0 / (n * n);						he1 = he2 = NULL;			for(list<heHalfEdge *>::iterator it = ptr->edges.begin(); it != ptr->edges.end(); it++)			{				if((*it)->twin == NULL)				{					twin = false;					if(he1 == NULL)						he1 = *it;					else						he2 = *it;				}								if((*it)->tail != ptr)					midE += (*it)->tail->coord;				else					midE += (*it)->head->coord;								if(find(faceList.begin(), faceList.end(), (*it)->face) == faceList.end())					faceList.push_back((*it)->face);			}						for(list<heFace *>::iterator it = faceList.begin(); it != faceList.end(); it++)				midF += (*it)->data->coord;						midE *= beta;			midF *= beta;			if(twin == true)				mid = midE + midF + ptr->coord * (n - 2.0) / n;			else			{				if(he1 && he2)				{					mid = ptr->coord * 0.75;										if(he1->tail != ptr)						mid += he1->tail->coord * 0.125;					else						mid += he1->head->coord * 0.125;										if(he2->tail != ptr)						mid += he2->tail->coord * 0.125;					else						mid += he2->head->coord * 0.125;				}				else					mid = ptr->coord;			}		}		else		{			if(n == 2)			{								he1 = ptr->edges.front();				he2 = ptr->edges.back();								if(he1->tail != ptr)					midE += he1->tail->coord;				else					midE += he1->head->coord;								if(he2->tail != ptr)					midE += he2->tail->coord;				else					midE += he2->head->coord;								mid = ptr->coord * 0.75 + midE * 0.125;			}			else			{				mid = ptr->coord;			}		}				ptr->data = result->buildVertex(mid);	}		for(heFace * ptr = _mesh->faces; ptr; ptr = ptr->next)	{		vector<heVertex *> new_vert;		vector<heVertex *> new_edge;				he = ptr->edge;		do		{			new_vert.push_back(he->tail->data);			new_edge.push_back(he->data);						he = he->next;		}		while(he != ptr->edge);				n = new_vert.size() - 1;		for(uint i(0); i < n; i++)		{			he1 = result->buildEdge(ptr->data, new_edge[i])->half;			he2 = result->buildEdge(new_edge[i], new_vert[i+1])->half;			he3 = result->buildEdge(new_vert[i+1], new_edge[i+1])->half;			he4 = result->buildEdge(new_edge[i+1], ptr->data)->half;			result->linkHalfEdges(he1, he2);			result->linkHalfEdges(he2, he3);			result->linkHalfEdges(he3, he4);			result->linkHalfEdges(he4, he1);						result->buildFace(he1);		}				he1 = result->buildEdge(ptr->data, new_edge[n])->half;		he2 = result->buildEdge(new_edge[n], new_vert[0])->half;		he3 = result->buildEdge(new_vert[0], new_edge[0])->half;		he4 = result->buildEdge(new_edge[0], ptr->data)->half;		result->linkHalfEdges(he1, he2);		result->linkHalfEdges(he2, he3);		result->linkHalfEdges(he3, he4);		result->linkHalfEdges(he4, he1);				result->buildFace(he1);	}		result->updateVerticesInfo();		return result;}heMesh * heSubdivider :: subDooSabin(heMesh * _mesh){	heMesh * result = new heMesh();		vec3 mid;	uint i, n;	heHalfEdge * he, * hebis, * he1, * he2, * new_edges[3];	bool twin;		result->level = _mesh->level + 1;		for(heEdge * ptr = _mesh->edges; ptr; ptr = ptr->next)	{		ptr->half->data = NULL;		ptr->half->mark = false;	}		for(heVertex * ptr = _mesh->vertices; ptr; ptr = ptr->next)	{		ptr->data 	 = NULL;		ptr->mark 	 = false;		ptr->valence = ptr->edges.size();	}		for(heFace * ptr = _mesh->faces; ptr; ptr = ptr->next)	{		n   = 0;		mid = vec3::zero;				he  = ptr->edge;		do		{			n++;			he = he->next;		}		while(he != ptr->edge);				he = ptr->edge;		do		{			if(he->twin != NULL)			{				mid = he->tail->coord * (0.25 + 5.0 / (4.0 * n));				i   = 1;								hebis = he->next;				do				{					mid += hebis->tail->coord * (3.0 + 2.0 * cos(2.0 * i * M_PI / n)) / (4.0 * n);					i++;										hebis = hebis->next;				}				while(hebis != he);			}			else			{				he1 = he2 = NULL;				for(list<heHalfEdge *>::iterator it = he->tail->edges.begin(); it != he->tail->edges.end(); it++)				{					if((*it)->twin == NULL)					{						twin = false;						if(he1 == NULL)							he1 = *it;						else							he2 = *it;					}				}								mid = vec3::zero;				if(he1->tail != he->tail)					mid += he1->tail->coord * 0.5;				else					mid += he1->head->coord * 0.5;								if(he2->tail != he->tail)					mid += he2->tail->coord * 0.5;				else					mid += he2->head->coord * 0.5;								//mid = he->tail->coord * 0.75 + he->head->coord * 0.25;			}						he->data = result->buildVertex(mid);			he = he->next;		}		while(he != ptr->edge);	}		for(heFace * ptr = _mesh->faces; ptr; ptr = ptr->next)	{		he = ptr->edge;				new_edges[0] = new_edges[2] = result->buildEdge(he->data, he->next->data)->half;		he = he->next;		do		{			new_edges[1] = new_edges[2];			new_edges[2] = result->buildEdge(he->data, he->next->data)->half;						result->linkHalfEdges(new_edges[1], new_edges[2]);						he = he->next;		}		while(he != ptr->edge);				result->linkHalfEdges(new_edges[2], new_edges[0]);		result->buildFace(new_edges[0]);	}		for(heEdge * ptr = _mesh->edges; ptr; ptr = ptr->next)	{		he = ptr->half;				if(he->twin != NULL && he->twin->mark == false)		{			he->mark 	   = true;			he->twin->mark = true;						new_edges[0] = new_edges[1] = result->buildEdge(he->next->data, he->data)->half;			new_edges[2] = result->buildEdge(he->data, he->twin->next->data)->half;			result->linkHalfEdges(new_edges[1], new_edges[2]);						new_edges[1] = result->buildEdge(he->twin->next->data, he->twin->data)->half;			result->linkHalfEdges(new_edges[2], new_edges[1]);						new_edges[2] = result->buildEdge(he->twin->data, he->next->data)->half;			result->linkHalfEdges(new_edges[1], new_edges[2]);						result->linkHalfEdges(new_edges[2], new_edges[0]);			result->buildFace(new_edges[0]);		}	}		for(heFace * ptr = _mesh->faces; ptr; ptr = ptr->next)	{		he = ptr->edge;				do		{			if(he->tail->mark == false)			{				twin      	   = true;				he->tail->mark = true;							hebis = he;				do				{					if(hebis->twin == NULL)						twin = false;					else						hebis = hebis->twin->next;				}				while(hebis != he && twin == true);								if(twin == true)				{					hebis = he;										new_edges[0] = new_edges[2] = result->buildEdge(hebis->data, hebis->prev->twin->data)->half;					do					{						hebis = hebis->prev->twin;						new_edges[1] = new_edges[2];																		if(hebis == he)						{							new_edges[2] = new_edges[1];						}						else						{							new_edges[2] = result->buildEdge(hebis->data, hebis->prev->twin->data)->half;							result->linkHalfEdges(new_edges[1], new_edges[2]);						}					}					while(hebis != he);										result->linkHalfEdges(new_edges[2], new_edges[0]);										hebis = new_edges[0];					result->buildFace(new_edges[0]);				}			}						he = he->next;		}		while(he != ptr->edge);	}		result->updateVerticesInfo();	return result;}heMesh * heSubdivider :: subMidEdge(heMesh * _mesh){	heMesh * result = new heMesh();		vec3 mid;	uint n;	heHalfEdge * he, * he1, * he2, * he3, * he4, * new_edges[4];		if(_mesh->type != heMesh::MeshQuadrangulated)		return NULL;		result->level = _mesh->level + 1;		for(heEdge * ptr = _mesh->edges; ptr; ptr = ptr->next)	{		ptr->half->data = NULL;	}		for(heVertex * ptr = _mesh->vertices; ptr; ptr = ptr->next)	{		ptr->data = NULL;		ptr->valence = ptr->edges.size();	}		for(heFace * ptr = _mesh->faces; ptr; ptr = ptr->next)	{		n   = 0;		mid = vec3::zero;				he  = ptr->edge;		do		{			mid = he->tail->coord * 2.0 + (he->head->coord + he->prev->tail->coord);			mid /= 4.0;						he->data = result->buildVertex(mid);			he = he->next;		}		while(he != ptr->edge);	}		for(heFace * ptr = _mesh->faces; ptr; ptr = ptr->next)	{		new_edges[0] = he;		for(uint i(1); i < 4; i++)			new_edges[i] = new_edges[i-1]->next;				he1 = result->buildEdge(new_edges[1]->data, new_edges[0]->data)->half;		he2 = result->buildEdge(new_edges[2]->data, new_edges[1]->data)->half;		he3 = result->buildEdge(new_edges[3]->data, new_edges[2]->data)->half;		he4 = result->buildEdge(new_edges[0]->data, new_edges[3]->data)->half;				result->linkHalfEdges(he1, he2);		result->linkHalfEdges(he2, he3);		result->linkHalfEdges(he3, he4);		result->linkHalfEdges(he4, he1);				result->buildFace(he1);				he = ptr->edge;		do		{			new_edges[0] = he;			for(uint i(1); i < 4; i++)				new_edges[i] = new_edges[i-1]->next;					if(new_edges[0]->twin != NULL)			{				new_edges[2] = new_edges[0]->twin;				new_edges[3] = new_edges[0]->twin->next;			}						he1 = result->buildEdge(new_edges[1]->data, new_edges[0]->data)->half;			he2 = result->buildEdge(new_edges[2]->data, new_edges[1]->data)->half;			he3 = result->buildEdge(new_edges[3]->data, new_edges[2]->data)->half;			he4 = result->buildEdge(new_edges[0]->data, new_edges[3]->data)->half;						result->linkHalfEdges(he1, he2);			result->linkHalfEdges(he2, he3);			result->linkHalfEdges(he3, he4);			result->linkHalfEdges(he4, he1);						result->buildFace(he1);						he = he->next;		}		while(he != ptr->edge);	}		for(heVertex * ptr = _mesh->vertices; ptr; ptr = ptr->next)	{		bool twin = true;		for(list<heHalfEdge *>::iterator it = ptr->edges.begin(); it != ptr->edges.end(); it++)			if((*it)->twin == NULL)				twin = false;					if(twin == true)		{			uint n = 0;			heHalfEdge * ptr_edges[4];						he1 = ptr->edges.front();			if(he1->tail != ptr)				he1 = he1->twin;						he = he1;			do			{				new_edges[n++] = he;				he = he->twin->next;			}			while(he != he1);									for(uint i(0); i < n; i++)				ptr_edges[i] = result->buildEdge(new_edges[(i+1)%n]->data, new_edges[i]->data)->half;						for(uint i(0); i < n; i++)				result->linkHalfEdges(ptr_edges[i], ptr_edges[(i+1)%n]);						result->buildFace(ptr_edges[0]);		}	}		result->updateVerticesInfo();	return result;}// methode de chargement d'un maillage et d'ajout a la liste//// charge un maillage et l'ajoute dans la liste des maillages//bool heSubdivider :: load(const char * _filename){	for(uint i(0); i < meshList.size(); i++)		meshList.clear();		meshList.clear();	meshList.push_back(new heMesh());		if(meshList.size() == 1)		currentMesh = meshList.begin();	else		currentMesh++;		if((*currentMesh)->load(_filename) == true)	{		(*currentMesh)->unitize();		(*currentMesh)->computeNormals();				return true;	}	else		return false;}// methode d'enregistrement d'un maillage//// enregistre le maillage courant//bool heSubdivider :: save(const char * _filename) const{	if(isLoaded())		return (*currentMesh)->save(_filename);	else		return false;}// methode de triangulation du maillage//// prend le maillage courant non-triangule et le triangule a la facon GL_TRIANGLE_FAN//void heSubdivider :: triangulate(){	if(!isLoaded())		return;		clearEndList();		meshList.push_back(new heMesh(*(*currentMesh)));	currentMesh++;		(*currentMesh)->triangulate();	(*currentMesh)->computeNormals();}// methode d'affichage du maillage courant//// affiche le maillage courant dans la liste//void heSubdivider :: display() const{	if(isLoaded())		(*currentMesh)->display();}// methode d'acces au nombre de sommets//// renvoie le nombre de sommets du maillage courant//uint heSubdivider :: getNVertices() const{	if(isLoaded())		return (*currentMesh)->getNVertices();	else		return 0;}// methode d'acces au nombre d'aretes//// renvoie le nombre d'aretes du maillage courant//uint heSubdivider :: getNEdges() const{	if(isLoaded())		return (*currentMesh)->getNEdges();	else		return 0;}// methode d'acces au nombre de faces//// renvoie le nombre de faces du maillage courant//uint heSubdivider :: getNFaces() const{	if(isLoaded())		return (*currentMesh)->getNFaces();	else		return 0;}// methode d'acces au type de maillage//// renvoie le type du maillage courant//uint heSubdivider :: getType() const{	if(isLoaded())		return (*currentMesh)->getType();	else		return 0;}// methode qui permet de connaitre l'etat du manager//// renvoie true si un maillage est charge//bool heSubdivider :: isLoaded() const{	return (meshList.size() > 0);}// methode qui permet de savoir si on peut annuler l'action//// renvoie true si c'est possible//bool heSubdivider :: isUndoable(){	return (currentMesh != meshList.begin() && meshList.size() > 0);}// methode qui permet de savoir si on peut retablir l'action annulee//// renvoie true si c'est possible//bool heSubdivider :: isRedoable(){	if(meshList.size() == 0)		return false;		currentMesh++;	if(currentMesh == meshList.end())	{		currentMesh--;		return false;	}	else	{		currentMesh--;		return true;	}}// methode qui permet d'annuler la derniere action//// annule la derniere action effectuee sur le maillage//void heSubdivider :: undo(){	if(isUndoable())		currentMesh--;}// methode qui permet de retablir la derniere action annulee//// annule l'annulation :)//void heSubdivider :: redo(){	if(isRedoable())		currentMesh++;}// methode qui permet de subdiviser un maillage par la methode de Loop//// subdivise le maillage en creant un point au milieu de chaques aretes, ajuste par la suite//void heSubdivider :: subdivide(heScheme _scheme){	if(!isLoaded())		return;			switch(_scheme)	{		case SubLoop :			clearEndList();						meshList.push_back(subLoop(*currentMesh));			currentMesh++;			(*currentMesh)->computeNormals();			break;				case SubCatmullClark :			clearEndList();						meshList.push_back(subCatmullClark(*currentMesh));			currentMesh++;			(*currentMesh)->computeNormals();			break;				case SubDooSabin :			clearEndList();						meshList.push_back(subDooSabin(*currentMesh));			currentMesh++;			(*currentMesh)->computeNormals();			break;				case SubMidEdge :			clearEndList();						meshList.push_back(subMidEdge(*currentMesh));			currentMesh++;			(*currentMesh)->computeNormals();			break;				default :			break;	}	}