first commit
This commit is contained in:
		
							
								
								
									
										174
									
								
								include/bounce/quickhull/qh_hull.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								include/bounce/quickhull/qh_hull.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | ||||
| /* | ||||
| * Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied | ||||
| * warranty.  In no event will the authors be held liable for any damages | ||||
| * arising from the use of this software. | ||||
| * Permission is granted to anyone to use this software for any purpose, | ||||
| * including commercial applications, and to alter it and redistribute it | ||||
| * freely, subject to the following restrictions: | ||||
| * 1. The origin of this software must not be misrepresented; you must not | ||||
| * claim that you wrote the original software. If you use this software | ||||
| * in a product, an acknowledgment in the product documentation would be | ||||
| * appreciated but is not required. | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| */ | ||||
|  | ||||
| #ifndef QH_HULL_H | ||||
| #define QH_HULL_H | ||||
|  | ||||
| #include <bounce\common\geometry.h> | ||||
| #include <bounce\common\template\array.h> | ||||
|  | ||||
| template<class T> | ||||
| struct qhList | ||||
| { | ||||
| 	void PushFront(T* link); | ||||
| 	T* Remove(T* link); | ||||
|  | ||||
| 	T* head; | ||||
| 	u32 count; | ||||
| }; | ||||
|  | ||||
| // Half-edge data structure definition used by qhHull. | ||||
| struct qhHalfEdge; | ||||
| struct qhVertex; | ||||
|  | ||||
| struct qhFace | ||||
| { | ||||
| 	enum State | ||||
| 	{ | ||||
| 		e_invisible, | ||||
| 		e_visible, | ||||
| 		e_unknown, | ||||
| 		e_deleted | ||||
| 	}; | ||||
|  | ||||
| 	qhFace* freeNext; | ||||
|  | ||||
| 	qhFace* prev; | ||||
| 	qhFace* next; | ||||
|  | ||||
| 	qhHalfEdge* edge; | ||||
|  | ||||
| 	qhList<qhVertex> conflictList; | ||||
| 	 | ||||
| 	State state; | ||||
| 	b3Vec3 center; | ||||
| 	b3Plane plane; | ||||
|  | ||||
| 	u32 VertexCount() const; | ||||
| 	u32 EdgeCount() const;  | ||||
| 	qhHalfEdge* FindTwin(const qhVertex* tail, const qhVertex* head) const; | ||||
| 	void ComputeCenterAndPlane(); | ||||
| }; | ||||
|  | ||||
| struct qhHalfEdge | ||||
| { | ||||
| 	qhHalfEdge* freeNext; | ||||
|  | ||||
| 	qhVertex* tail; | ||||
|  | ||||
| 	qhHalfEdge* prev; | ||||
| 	qhHalfEdge* next; | ||||
| 	qhHalfEdge* twin; | ||||
|  | ||||
| 	qhFace* face; | ||||
| }; | ||||
|  | ||||
| struct qhVertex | ||||
| { | ||||
| 	qhVertex* freeNext; | ||||
|  | ||||
| 	qhVertex* prev; | ||||
| 	qhVertex* next; | ||||
|  | ||||
| 	b3Vec3 position; | ||||
|  | ||||
| 	qhFace* conflictFace; | ||||
| }; | ||||
|  | ||||
| // todo | ||||
| // Snapshots of the algorithm for debug drawing. | ||||
| struct qhDraw | ||||
| { | ||||
| 	//DrawIteration* iter; // current iteration | ||||
| 	//b3Array<DrawIteration> iterations; | ||||
| }; | ||||
|  | ||||
| class b3Draw; | ||||
|  | ||||
| // Given a number of points return the required memory size in bytes for constructing the  | ||||
| // convex hull of those points. Use this function before allocating the memory buffer passed  | ||||
| // as argument to Construct. | ||||
| u32 qhGetMemorySize(u32 V); | ||||
|  | ||||
| // A convex hull builder. Given a list of points constructs its convex hull.  | ||||
| // The output convex hull might contain polygonal faces and not only triangles.  | ||||
| // Coplanar face merging is necessary for stable physics simulation. | ||||
| class qhHull | ||||
| { | ||||
| public: | ||||
| 	qhHull(); | ||||
| 	~qhHull(); | ||||
|  | ||||
| 	// Entry point of qhHull. | ||||
| 	// Construct this hull given a memory buffer and a list of points. | ||||
| 	// Use qhGetMemorySize to see how many free bytes should be available in the buffer. | ||||
| 	void Construct(void* memory, const b3Array<b3Vec3>& vertices); | ||||
|  | ||||
| 	// Output of qhHull. | ||||
| 	// todo  | ||||
| 	// Output a cleaner data structure. Maybe similar to b3Hull but storing larger hulls? | ||||
| 	qhList<qhFace> m_faceList; // convex hull | ||||
| 	u32 m_iteration; // number of quickhull iterations | ||||
|  | ||||
| 	bool IsConsistent() const; | ||||
| 	 | ||||
| 	void Draw(b3Draw* draw) const; | ||||
| private: | ||||
| 	bool BuildInitialHull(const b3Array<b3Vec3>& vertices); | ||||
|  | ||||
| 	qhVertex* NextVertex(); | ||||
| 	 | ||||
| 	void AddVertex(qhVertex* v); | ||||
| 	 | ||||
| 	void BuildHorizon(b3Array<qhHalfEdge*>& horizon, qhVertex* eye); | ||||
| 	 | ||||
| 	void BuildHorizon(b3Array<qhHalfEdge*>& horizon, qhVertex* eye, qhHalfEdge* e0, qhFace* f); | ||||
| 	 | ||||
| 	qhFace* AddTriangle(qhVertex* v1, qhVertex* v2, qhVertex* v3); | ||||
| 	 | ||||
| 	qhHalfEdge* AddAdjoiningTriangle(qhVertex* v, qhHalfEdge* he); | ||||
| 	 | ||||
| 	void AddNewFaces(b3Array<qhFace*>& newFaces, qhVertex* eye, const b3Array<qhHalfEdge*>& horizon); | ||||
|  | ||||
| 	bool MergeFace(qhFace* face); | ||||
| 	 | ||||
| 	void MergeFaces(b3Array<qhFace*>& newFaces); | ||||
|  | ||||
| 	qhHalfEdge* FindTwin(const qhVertex* tail, const qhVertex* head) const; | ||||
|  | ||||
| 	// Coplanarity tolerance | ||||
| 	float32 m_tolerance; | ||||
| 	 | ||||
| 	// Memory | ||||
| 	qhVertex* AllocateVertex(); | ||||
| 	void FreeVertex(qhVertex* p); | ||||
| 	 | ||||
| 	qhHalfEdge* AllocateEdge(); | ||||
| 	void FreeEdge(qhHalfEdge* p); | ||||
| 	 | ||||
| 	qhFace* AllocateFace(); | ||||
| 	void FreeFace(qhFace* p); | ||||
| 		 | ||||
| 	qhVertex* m_freeVertices; | ||||
| 	qhHalfEdge* m_freeEdges; | ||||
| 	qhFace* m_freeFaces; | ||||
| }; | ||||
|  | ||||
| #include <bounce/quickhull/qh_hull.inl> | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										190
									
								
								include/bounce/quickhull/qh_hull.inl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								include/bounce/quickhull/qh_hull.inl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| // qhHull.h | ||||
|  | ||||
| template<class T> | ||||
| inline void qhList<T>::PushFront(T* link) | ||||
| { | ||||
| 	link->prev = nullptr; | ||||
| 	link->next = head; | ||||
| 	if (head) | ||||
| 	{ | ||||
| 		head->prev = link; | ||||
| 	} | ||||
| 	head = link; | ||||
| 	++count; | ||||
| } | ||||
|  | ||||
| template<class T> | ||||
| inline T* qhList<T>::Remove(T* link) | ||||
| { | ||||
| 	T* next = link->next; | ||||
|  | ||||
| 	if (link->prev) | ||||
| 	{ | ||||
| 		link->prev->next = link->next; | ||||
| 	} | ||||
| 	if (link->next) | ||||
| 	{ | ||||
| 		link->next->prev = link->prev; | ||||
| 	} | ||||
| 	if (link == head) | ||||
| 	{ | ||||
| 		head = link->next; | ||||
| 	} | ||||
|  | ||||
| 	link->prev = nullptr; | ||||
| 	link->next = nullptr; | ||||
|  | ||||
| 	--count; | ||||
| 	return next; | ||||
| } | ||||
|  | ||||
| inline u32 qhFace::VertexCount() const | ||||
| { | ||||
| 	u32 count = 0; | ||||
| 	qhHalfEdge* e = edge; | ||||
| 	do | ||||
| 	{ | ||||
| 		++count; | ||||
| 		e = e->next; | ||||
| 	} while (e != edge); | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| inline u32 qhFace::EdgeCount() const | ||||
| { | ||||
| 	u32 count = 0; | ||||
| 	qhHalfEdge* e = edge; | ||||
| 	do | ||||
| 	{ | ||||
| 		++count; | ||||
| 		e = e->next; | ||||
| 	} while (e != edge); | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| inline qhHalfEdge* qhFace::FindTwin(const qhVertex* tail, const qhVertex* head) const | ||||
| { | ||||
| 	qhHalfEdge* e = edge; | ||||
| 	do | ||||
| 	{ | ||||
| 		qhVertex* tail2 = e->tail; | ||||
| 		qhVertex* head2 = e->next->tail; | ||||
|  | ||||
| 		if (tail2 == tail && head2 == head) | ||||
| 		{ | ||||
| 			return e; | ||||
| 		} | ||||
|  | ||||
| 		e = e->next; | ||||
| 	} while (e != edge); | ||||
|  | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| inline b3Vec3 b3Newell(const b3Vec3& a, const b3Vec3& b) | ||||
| { | ||||
| 	return b3Vec3((a.y - b.y) * (a.z + b.z), (a.z - b.z) * (a.x + b.x), (a.x - b.x) * (a.y + b.y)); | ||||
| } | ||||
|  | ||||
| inline void qhFace::ComputeCenterAndPlane() | ||||
| { | ||||
| 	b3Vec3 c; | ||||
| 	c.SetZero(); | ||||
|  | ||||
| 	b3Vec3 n; | ||||
| 	n.SetZero(); | ||||
|  | ||||
| 	u32 count = 0; | ||||
| 	qhHalfEdge* e = edge; | ||||
| 	do | ||||
| 	{ | ||||
| 		b3Vec3 v1 = e->tail->position; | ||||
| 		b3Vec3 v2 = e->next->tail->position; | ||||
|  | ||||
| 		n += b3Newell(v1, v2); | ||||
| 		c += v1; | ||||
|  | ||||
| 		++count; | ||||
| 		e = e->next; | ||||
| 	} while (e != edge); | ||||
|  | ||||
| 	B3_ASSERT(count > 0); | ||||
| 	c /= float32(count); | ||||
| 	n.Normalize(); | ||||
| 	plane.normal = n; | ||||
| 	plane.offset = b3Dot(n, c); | ||||
| 	center = c; | ||||
| } | ||||
|  | ||||
| inline qhHalfEdge* qhHull::FindTwin(const qhVertex* tail, const qhVertex* head) const | ||||
| { | ||||
| 	qhFace* face = m_faceList.head; | ||||
| 	while (face) | ||||
| 	{ | ||||
| 		qhHalfEdge* e = face->FindTwin(tail, head); | ||||
| 		if (e) | ||||
| 		{ | ||||
| 			return e; | ||||
| 		} | ||||
| 		face = face->next; | ||||
| 	} | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| inline u32 qhGetMemorySize(u32 V) | ||||
| { | ||||
| 	u32 E = 3 * V - 6; | ||||
| 	u32 HE = 2 * E; | ||||
| 	u32 F = 2 * V - 4; | ||||
|  | ||||
| 	// V - E + F = 2 | ||||
| 	 | ||||
| 	HE *= 2; | ||||
| 	F *= 2; | ||||
|  | ||||
| 	u32 size = 0; | ||||
| 	size += V * sizeof(qhVertex); | ||||
| 	size += HE * sizeof(qhHalfEdge); | ||||
| 	size += F * sizeof(qhFace); | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| inline qhVertex* qhHull::AllocateVertex() | ||||
| { | ||||
| 	qhVertex* v = m_freeVertices; | ||||
| 	m_freeVertices = v->freeNext; | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| inline void qhHull::FreeVertex(qhVertex* v) | ||||
| { | ||||
| 	v->freeNext = m_freeVertices; | ||||
| 	m_freeVertices = v; | ||||
| } | ||||
|  | ||||
| inline qhHalfEdge* qhHull::AllocateEdge() | ||||
| { | ||||
| 	qhHalfEdge* e = m_freeEdges; | ||||
| 	m_freeEdges = e->freeNext; | ||||
| 	return e; | ||||
| } | ||||
|  | ||||
| inline void qhHull::FreeEdge(qhHalfEdge* e) | ||||
| { | ||||
| 	e->freeNext = m_freeEdges; | ||||
| 	m_freeEdges = e; | ||||
| } | ||||
|  | ||||
| inline qhFace* qhHull::AllocateFace() | ||||
| { | ||||
| 	qhFace* f = m_freeFaces; | ||||
| 	m_freeFaces = f->freeNext; | ||||
| 	return f; | ||||
| } | ||||
|  | ||||
| inline void qhHull::FreeFace(qhFace* f) | ||||
| { | ||||
| 	f->state = qhFace::e_deleted; | ||||
| 	f->freeNext = m_freeFaces; | ||||
| 	m_freeFaces = f; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user