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