Initial commit.

This commit is contained in:
Jim Gray
2013-04-04 14:32:05 -07:00
parent ba5c81da32
commit d71d53e8ec
2180 changed files with 1393544 additions and 1 deletions

419
code/ragl/graph_region.h Normal file
View File

@@ -0,0 +1,419 @@
////////////////////////////////////////////////////////////////////////////////////////
// RAVEN STANDARD TEMPLATE LIBRARY
// (c) 2002 Activision
//
//
// Graph Region
// ------------
//
//
////////////////////////////////////////////////////////////////////////////////////////
#if !defined(RATL_GRAPH_REGION_INC)
#define RATL_GRAPH_REGION_INC
////////////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////////////
#if defined(RA_DEBUG_LINKING)
#pragma message("...including graph_region.h")
#endif
#if !defined(RAGL_COMMON_INC)
#include "ragl_common.h"
#endif
#if !defined(RAGL_GRAPH_VS_INC)
#include "graph_vs.h"
#endif
namespace ragl
{
////////////////////////////////////////////////////////////////////////////////////////
// The Graph Region Class
////////////////////////////////////////////////////////////////////////////////////////
template <class TNODE, int MAXNODES, class TEDGE, int MAXEDGES, int NUM_EDGES_PER_NODE, int MAXREGIONS, int MAXREGIONEDGES>
class graph_region : public ratl::ratl_base
{
public:
////////////////////////////////////////////////////////////////////////////////////
// Capacity Enum
////////////////////////////////////////////////////////////////////////////////////
enum
{
NULL_REGION = -1,
NULL_EDGE = -1,
CAPACITY = MAXREGIONS
};
////////////////////////////////////////////////////////////////////////////////////
// Some Public Type Defines
////////////////////////////////////////////////////////////////////////////////////
typedef ragl::graph_vs<TNODE, MAXNODES, TEDGE, MAXEDGES, NUM_EDGES_PER_NODE> TGraph;
typedef ratl::vector_vs<int, MAXNODES> TRegions;
typedef ratl::vector_vs<short, MAXREGIONS> TRegionEdge; // List Of All Edges Which Connect RegionA<->RegionB
typedef ratl::pool_vs<TRegionEdge, MAXREGIONEDGES> TEdges; // Pool Of All RegionEdges
typedef ratl::grid2_vs<short, MAXREGIONS, MAXREGIONS> TLinks; // Graph Of Links From Region To Region, Each Points To A RegionEdge
typedef ratl::bits_vs<MAXREGIONS> TClosed;
////////////////////////////////////////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////////////////////////////////////////
graph_region(TGraph& Graph) : mGraph(Graph)
{
clear();
}
~graph_region()
{
}
////////////////////////////////////////////////////////////////////////////////////
// Clear Out All Temp Data So We Can Recalculate Regions
////////////////////////////////////////////////////////////////////////////////////
void clear()
{
mRegions.resize(0, (int)NULL_REGION);
mRegions.resize(MAXNODES, (int)NULL_REGION);
mRegionCount = 0;
mReservedRegionCount = 0;
mLinks.init(NULL_EDGE);
for (int i=0; i<MAXREGIONEDGES; i++)
{
if (mEdges.is_used(i))
{
mEdges[i].resize(0, NULL_EDGE);
}
}
mEdges.clear();
}
////////////////////////////////////////////////////////////////////////////////////
// How Many Regions Have Been Created
////////////////////////////////////////////////////////////////////////////////////
int size()
{
return mRegionCount;
}
////////////////////////////////////////////////////////////////////////////////////
// Get The Region For A Given Node
////////////////////////////////////////////////////////////////////////////////////
int get_node_region(int Node)
{
return mRegions[mGraph.node_index(Node)];
}
////////////////////////////////////////////////////////////////////////////////////
// Call this function to find out if it is at all possible to get from nodeA to
// nodeB. If there is no possible connection, or there is one, but the connection
// is not valid at the current time, this routine will return false. Use it as
// a quick cull routine before a search.
//
// In order to use this function, you must have an EdgeQuery class (use the default
// above, or derive your own for more specialized behavior).
////////////////////////////////////////////////////////////////////////////////////
bool has_valid_edge(int NodeA, int NodeB, const typename TGraph::user& user)
{
int RegionA = mRegions[NodeA];
int RegionB = mRegions[NodeB];
if (RegionA==RegionB)
{
return true;
}
mClosed.clear();
return has_valid_region_edge(RegionA, RegionB, user);
}
////////////////////////////////////////////////////////////////////////////////////
// Reserve Region
//
// Allows a user to pre-allocate a special region for a group of points
////////////////////////////////////////////////////////////////////////////////////
int reserve()
{
assert(mRegionCount < (MAXREGIONS-1));
if (mRegionCount >= (MAXREGIONS-1) )
{//stop adding points, we're full, you MUST increase MAXREGIONS for this to work
return NULL_REGION;
}
mReservedRegionCount ++;
mRegionCount ++;
return (mRegionCount);
}
////////////////////////////////////////////////////////////////////////////////////
// assign_region
//
// Allows a user to pre-allocate a special region for a group of points
////////////////////////////////////////////////////////////////////////////////////
void assign_region(int NodeIndex, int RegionIndex)
{
mRegions[NodeIndex] = RegionIndex;
}
////////////////////////////////////////////////////////////////////////////////////
// Define Regions
//
// Scan through all the nodes (calling the depth first recursive traversal below),
// and mark regions of nodes which can traverse to one another without needing to check
// for valid edges.
//
////////////////////////////////////////////////////////////////////////////////////
bool find_regions(const typename TGraph::user& user)
{
int CurNodeIndex;
for (TGraph::TNodes::iterator i=mGraph.nodes_begin(); i!=mGraph.nodes_end(); i++)
{
CurNodeIndex = i.index();
if (mRegions[CurNodeIndex] == NULL_REGION)
{
assert(mRegionCount < (MAXREGIONS-1));
if (mRegionCount >= (MAXREGIONS-1) )
{//stop adding points, we're full, you MUST increase MAXREGIONS for this to work
return false;
}
mRegionCount ++; // Allocate The New Region
assign(CurNodeIndex, user); // Assign All Points To It
}
}
mRegionCount ++; // Size is actually 1 greater than the number of regions
return true;
}
////////////////////////////////////////////////////////////////////////////////////
// Search For All Possible Edges Which Connect Regions
//
// Once called, this class will have reference data for how to get from one region
// to another.
////////////////////////////////////////////////////////////////////////////////////
bool find_region_edges()
{
int RegionA;
int RegionB;
int RegionLink;
bool Success = true;
bool ReservedRegionLink;
for (int indexA=0; indexA<MAXNODES; indexA++)
{
RegionA = mRegions[indexA];
if (RegionA!=NULL_REGION)
{
for (int indexB=0; indexB<MAXNODES; indexB++)
{
RegionB = mRegions[indexB];
ReservedRegionLink = (RegionA<=mReservedRegionCount || RegionB<=mReservedRegionCount);
if (RegionB!=NULL_REGION && RegionB!=RegionA && mGraph.get_edge_across(indexA, indexB))
{
RegionLink = mLinks.get(RegionA, RegionB);
// Do We Need To Allocate A New Region Link Vector?
//--------------------------------------------------
if (RegionLink==-1)
{
if (ReservedRegionLink)
{
mLinks.get(RegionA, RegionB) = -2; // Special Flag For Reserved Regions - they have no edges
mLinks.get(RegionB, RegionA) = -2;
}
else
{
if (mEdges.full())
{
assert("graph_region: Too Many Region Edges"==0);
Success = false;
}
else
{
RegionLink = mEdges.alloc();
mEdges[RegionLink].resize(0, NULL_EDGE);
mEdges[RegionLink].push_back(mGraph.get_edge_across(indexA, indexB));
mLinks.get(RegionA, RegionB) = RegionLink;
mLinks.get(RegionB, RegionA) = RegionLink;
}
}
}
// Add This Edge To The Other Region Links
//-----------------------------------------
else if (!ReservedRegionLink)
{
mEdges[RegionLink].push_back(mGraph.get_edge_across(indexA, indexB));
}
}
}
}
}
return Success;
}
private:
////////////////////////////////////////////////////////////////////////////////////
// This Routine Is A Depth First Recursive Traversal
//
// It will visit all neighbors for each node which have not already been visited
// and assigned to a region. Neighbors must always be valid.
////////////////////////////////////////////////////////////////////////////////////
void assign(int Node, const typename TGraph::user& user)
{
mRegions[Node] = mRegionCount;
for (int i=0; i<MAXNODES; i++)
{
if (mRegions[i]==-1)
{
int edgeNum = mGraph.get_edge_across(Node, i);
if (edgeNum && !user.can_be_invalid(mGraph.get_edge(edgeNum)))
{
assign(i, user);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////
// This Routine Is A Depth First Recursive Search For Target Region
//
// Visited regions are makred on the "closed" bit field.
////////////////////////////////////////////////////////////////////////////////////
bool has_valid_region_edge(int CurRegion, int TargetRegion, const typename TGraph::user& user)
{
// Mark The Cur Region As Visited, So We Don't Try To Return To It
//-----------------------------------------------------------------
mClosed.set_bit(CurRegion);
// If The Two Nodes Are In The Same Region, Then This Is Valid
//-------------------------------------------------------------
if (CurRegion==TargetRegion)
{
return true;
}
// Scan Through The Cur Region's Neighbors With Currently Valid Region Edges
//---------------------------------------------------------------------------
int CurRegionEdge;
for (int NextRegion=0; NextRegion<mRegionCount; NextRegion++)
{
// Check If The Link Exists And We Have Not Already Visited The Next Region
//--------------------------------------------------------------------------
CurRegionEdge = mLinks.get(CurRegion, NextRegion);
if (CurRegionEdge!=NULL_EDGE && !mClosed.get_bit(NextRegion))
{
if (CurRegion<=mReservedRegionCount)
{
// Great, So We Have Found A Valid Neighboring Region, Search There
//------------------------------------------------------------------
if (has_valid_region_edge(NextRegion, TargetRegion, user))
{
return true; // HEY! Somehow, Going To Next Region Got Us To The Target Region!
}
}
else
{
// Scan Through This Region Edge List Of Graph Edges For Any Valid One
//---------------------------------------------------------------------
assert(mEdges[CurRegionEdge].size()>0);
for (int j=0; j<mEdges[CurRegionEdge].size(); j++)
{
if (user.is_valid(
mGraph.get_edge(mEdges[CurRegionEdge][j]),
(NextRegion==TargetRegion)?(-1):(0)
)
)
{
// Great, So We Have Found A Valid Neighboring Region, Search There
//------------------------------------------------------------------
if (has_valid_region_edge(NextRegion, TargetRegion, user))
{
return true; // HEY! Somehow, Going To Next Region Got Us To The Target Region!
}
// Ok, The Target Region Turned Out To Be A Dead End, We Can Stop Trying To Get There
//------------------------------------------------------------------------------------
break;
}
}
}
}
}
// Nope, We Failed To Find Any Valid Region Edges Which Lead To The Target Region
//--------------------------------------------------------------------------------
return false;
}
private:
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
TGraph& mGraph;
TRegions mRegions;
int mRegionCount;
int mReservedRegionCount;
TLinks mLinks;
TEdges mEdges;
TClosed mClosed;
public:
#if !defined(FINAL_BUILD)
void ProfileSpew()
{
ProfilePrint("");
ProfilePrint("");
ProfilePrint("--------------------------------------------------------");
ProfilePrint("RAVEN STANDARD LIBRARY - COMPUTATIONAL GEOMETRY MODULE");
ProfilePrint(" Region Profile Results ");
ProfilePrint("--------------------------------------------------------");
ProfilePrint("");
ProfilePrint("REGION SIZE (Bytes): (%d) (KiloBytes): (%5.3f)", sizeof(*this), ((float)(sizeof(*this))/1024.0f));
ProfilePrint("REGION COUNT: (%d) Regions (%d) Edges", mRegionCount, mEdges.size());
if (mRegionCount)
{
int RegionEdges = 0;
for (TEdges::iterator it=mEdges.begin(); it!=mEdges.end(); it++)
{
RegionEdges += (*it).size();
}
ProfilePrint("REGION COUNT: (%f) Ave Edges Size", (float)RegionEdges / (float)mRegionCount);
}
ProfilePrint("");
};
#endif
};
}
#endif

View File

@@ -0,0 +1,833 @@
////////////////////////////////////////////////////////////////////////////////////////
// RAVEN STANDARD TEMPLATE LIBRARY
// (c) 2002 Activision
//
//
// Graph Triangulate
// -----------------
// Triangulation is the process of generating graph edges between "nearby" points.
//
// This class is designed to work with the ragl_graph template class, and requires that
// the same template parameters for that class be used here. The memory requirements
// of this class are not inconsequential, so it is best to allocate this class during
// a preprocess step and then throw it away.
//
// NOTE: This is a 2D triangulation! All Z Coordinates are ignored!
//
//
//
//
// How Do I Triangulate A Raw Set Of Points?
// -----------------------------------------
// First of all, in order to construct a triangulation, you need to have your graph and
// pass it in to the constructor:
//
// typedef ragl::graph_triangulate<TNODE, MAXNODES, TEDGE, MAXEDGES> TTriangulation
// TTriangulation MyTriangulation(mMyGraph);
//
// Next, you are free to call any of the public functions in any order, but the best use
// is to call them in this order:
//
// MyTriangulation.insertion_hull();
// MyTriangulation.delaunay_edge_flip();
// MyTriangulation.alpha_shape(MyGraphUser, <MIN>, <MAX>);
//
// For documentation on the above functions, look at their def below. Also, the doc on
// the Graph User class is in graph_vs.h
//
//
// Finally, when you are ready, call the finish() function. That will populate your
// graph (which has not been altered in any way up until now). After calling finish()
// you can dump the triangulation class, as it has done it's job and all the data is
// now stored in the class.
//
// MyTriangulation.finish();
//
//
//
//
// How Does It Work? (Overview)
// -----------------------------
// The details of how each step works are outlined below, however, here is the general
// idea:
//
// - Call insertion hull to generate a "rough and dirty" triangulation of the point set.
// The algorithm is relativly fast, and as a handy bi-product, generates the convex
// hull of the points. The resulting mesh is ugly though. You probably won't want
// to use it in the rough state. The basic idea of this algorithm is to iterativly
// add points which have been presorted along the x-axis into the triangulation. It
// is easy to do so, because you always know it will be on the right side of any edge
// it needs to connect with.
//
// - Now that you have a functional triangulation with edges and faces, there is fairly
// simple and fast algorithm to "clean it up" called EdgeFlipping. The idea is simple.
// Just scan through the edges, if you find one that is "bad", flip it! Continue until
// you find no "bad" edges. NOTE: This algorithm can lock up if any four points are
// colinear!
//
// - Finally, Alpha Shape is just a simple prune scan of the edges for anything that is
// too big or too small. This step is totally optional.
//
//
////////////////////////////////////////////////////////////////////////////////////////
#if !defined(RATL_GRAPH_TRIANGULATE_INC)
#define RATL_GRAPH_TRIANGULATE_INC
////////////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////////////
#if defined(RA_DEBUG_LINKING)
#pragma message("...including graph_triangulate.h")
#endif
#if !defined(RAGL_COMMON_INC)
#include "ragl_common.h"
#endif
#if !defined(RAGL_GRAPH_VS_INC)
#include "graph_vs.h"
#endif
#if !defined(RATL_LIST_VS_INC)
#include "..\Ratl\list_vs.h"
#endif
namespace ragl
{
////////////////////////////////////////////////////////////////////////////////////////
// The Graph Class
////////////////////////////////////////////////////////////////////////////////////////
template <class TNODE, int MAXNODES, class TEDGE, int MAXEDGES, int MAXNODENEIGHBORS>
class graph_triangulate : public ratl::ratl_base
{
public:
////////////////////////////////////////////////////////////////////////////////////
// Capacity Enum
////////////////////////////////////////////////////////////////////////////////////
enum
{
CAPACITY = MAXNODES,
MAXFACES = MAXEDGES*2,
NULLEDGE = -1
};
typedef graph_vs<TNODE, MAXNODES, TEDGE, MAXEDGES, MAXNODENEIGHBORS> TGraph;
public:
////////////////////////////////////////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////////////////////////////////////////
graph_triangulate(TGraph& Graph) : mGraph(Graph), mHull(), mHullIter(mHull.begin())
{
mLinks.init(0);
}
////////////////////////////////////////////////////////////////////////////////////
// Clear Out All Temp Data So We Can Triangulate Again
////////////////////////////////////////////////////////////////////////////////////
void clear()
{
mLinks.init(0);
mEdges.clear();
mFaces.clear();
mHull.clear();
mHullIter = mHull.begin();
mSortNodes.clear();
}
////////////////////////////////////////////////////////////////////////////////////
// Insertion Hull
//
// This is a "quick and dirty" triangulation technique. It does not give you a very
// nice looking or terribly useful mesh, but it is a good place to start. Once
// you have an insertion hull triangulation, you can call delauny_edge_flip() to
// clean it up some.
//
// This algorithm's complexity isbounded in the worst case where all the points in
// the mesh are on the "hull", in which case it is O(n^2). However the number of
// points on the hull for most common point clouds is more likely to be log n.
//
////////////////////////////////////////////////////////////////////////////////////
void insertion_hull()
{
assert(mGraph.size_nodes()>3); // We Need More Than 3 Points To Triangulate
// STEP ONE: Sort all points along the x axis in increasing order
//----------------------------------------------------------------
// COMPLEXITY: O(n log n) Heapsort
sort_points();
// STEP TWO: Manually constructe the first face of the triangulation out of the 3 rightmost points
//--------------------------------------------------------------------------------------------------
// COMPLEXITY: O(1)
add_face(mSortNodes[0].mNodeHandle, mSortNodes[1].mNodeHandle, mSortNodes[2].mNodeHandle);
// STEP THREE: Add each remaining point to the hull, constructing new faces as we go
//-----------------------------------------------------------------------------------
// COMPLEXITY: O(n*c) (n = num nodes, c = num nodes on hull)
for (int i=3; i<mSortNodes.size(); i++)
{
insert_point(mSortNodes[i].mNodeHandle);
}
}
////////////////////////////////////////////////////////////////////////////////////
// Delaunay Edge Flipping
//
// This algorithm iterativly rotates edges which do not fit the "delaunay" criterion
// of all points on two adjacent faces containment within the circumscribed circles
// of the two faces. It solves the all pairs nearest neighbors problem.
//
// The routine is sadly bounded by n^2 complexity, but in practice perfromes very
// well - much better than n^2 (closer to n log n).
//
////////////////////////////////////////////////////////////////////////////////////
void delaunay_edge_flip()
{
int CurFlipped;
int TotalFlipped = 0;
do
{
CurFlipped = flip();
TotalFlipped += CurFlipped;
}
while (CurFlipped!=0 && TotalFlipped<10000 /*Sanity Condition*/);
}
////////////////////////////////////////////////////////////////////////////////////
// This function attempts to prune out edges which connect across "floors" and
//
//
//
////////////////////////////////////////////////////////////////////////////////////
void floor_shape(typename TGraph::user& user, float maxzdelta)
{
ratl::vector_vs<int, MAXEDGES> CullEdges;
int nEdge;
TEdges::iterator stop=mEdges.end();
for (TEdges::iterator it=mEdges.begin(); it!=mEdges.end(); it++)
{
if (!(*it).mOnHull)
{
edge& EdgeAt = *it;
face& FaceR = mFaces[EdgeAt.mRight];
face& FaceL = mFaces[EdgeAt.mLeft];
// int Edge = mEdges.index_to_handle(it.index());
int R = FaceR.opposing_node(EdgeAt.mA, EdgeAt.mB);
int L = FaceL.opposing_node(EdgeAt.mA, EdgeAt.mB);
int RInd = mGraph.node_index(R);
int LInd = mGraph.node_index(L);
TNODE& PtA = mGraph.get_node(EdgeAt.mA);
TNODE& PtB = mGraph.get_node(EdgeAt.mB);
TNODE& PtR = mGraph.get_node(R);
TNODE& PtL = mGraph.get_node(L);
if (
(user.on_same_floor(PtR, PtL)) &&
(mLinks.get(RInd, LInd)==0) &&
(mLinks.get(LInd, RInd)==0) &&
(!user.on_same_floor(PtL, PtA) || !user.on_same_floor(PtL, PtB))
)
{
nEdge= mEdges.alloc();
mEdges[nEdge].mA = R;
mEdges[nEdge].mB = L;
mEdges[nEdge].mHullLoc = mHullIter;
mEdges[nEdge].mOnHull = true;
mEdges[nEdge].mFlips = 0;
mEdges[nEdge].mLeft = 0;
mEdges[nEdge].mRight = 0;
mLinks.get(RInd, LInd) = nEdge;
mLinks.get(LInd, RInd) = nEdge;
}
if (!user.on_same_floor(PtA, PtB))
{
mLinks.get(mGraph.node_index(EdgeAt.mA), mGraph.node_index(EdgeAt.mB)) = 0;
mLinks.get(mGraph.node_index(EdgeAt.mB), mGraph.node_index(EdgeAt.mA)) = 0;
CullEdges.push_back(it.index());
}
}
}
for (int i=0; i<CullEdges.size(); i++)
{
mEdges.free_index(CullEdges[i]);
}
}
////////////////////////////////////////////////////////////////////////////////////
// This function is a simple routine to prune out any edges which are larger or
// smaller than the desired range (min, max).
////////////////////////////////////////////////////////////////////////////////////
void alpha_shape(typename TGraph::user& user, float max, float min=0)
{
ratl::vector_vs<int, MAXEDGES> CullEdges;
float cost;
for (TEdges::iterator it=mEdges.begin(); it!=mEdges.end(); it++)
{
cost = user.cost(mGraph.get_node((*it).mA), mGraph.get_node((*it).mB));
if (cost<min || cost>max)
{
mLinks.get(mGraph.node_index((*it).mA), mGraph.node_index((*it).mB)) = 0;
mLinks.get(mGraph.node_index((*it).mB), mGraph.node_index((*it).mA)) = 0;
CullEdges.push_back(it.index());
}
}
for (int i=0; i<CullEdges.size(); i++)
{
mEdges.free_index(CullEdges[i]);
}
}
////////////////////////////////////////////////////////////////////////////////////
// Call this function when you are done with the triangulation and want to copy all
// the temp data into your graph.
////////////////////////////////////////////////////////////////////////////////////
void finish(typename TGraph::user& user)
{
mGraph.clear_edges();
TEDGE DefaultEdge;
for (TEdges::iterator it=mEdges.begin(); it!=mEdges.end(); it++)
{
user.setup_edge(DefaultEdge, (*it).mA, (*it).mB, (*it).mOnHull, mGraph.get_node((*it).mA), mGraph.get_node((*it).mB));
mGraph.connect_node(DefaultEdge, (*it).mA, (*it).mB);
}
}
private:
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
typedef typename ratl::list_vs<int, MAXNODES> THull;
typedef typename ratl::list_vs<int, MAXNODES>::iterator THullIter;
typedef typename ratl::grid2_vs<int, MAXNODES, MAXNODES> TLinks;
////////////////////////////////////////////////////////////////////////////////////
// The Local Edge Class
//
// RIGHT
// B<-<-<-<-<-<-A
// LEFT
//
////////////////////////////////////////////////////////////////////////////////////
class edge
{
public:
int mA;
int mB;
int mLeft;
int mRight;
int mFlips;
THullIter mHullLoc;
bool mOnHull;
void flip_face(int OldFace, int NewFace)
{
assert(mRight!=mLeft);
assert(mLeft!=NewFace && mRight!=NewFace);
if (mLeft==OldFace)
{
mLeft=NewFace;
}
else
{
assert(mRight==OldFace);
mRight = NewFace;
}
assert(mRight!=mLeft);
}
void verify(int PtA, int PtB, int Edge)
{
assert(PtA==mA || PtA==mB);
assert(PtB==mA || PtB==mB);
assert(mRight==Edge || mLeft==Edge);
assert(mRight!=mLeft);
assert(mA!=mB);
}
void verify(int PtA, int PtB, int PtC, int Edge)
{
assert((PtC==mA && (PtA==mB || PtB==mB)) || (PtC==mB && (PtA==mA || PtB==mA)));
assert(mRight==Edge || mLeft==Edge);
assert(mRight!=mLeft);
assert(mA!=mB);
}
};
////////////////////////////////////////////////////////////////////////////////////
// The Local Face Class
//
// _ C
// /| \
// LEFT/ \RIGHT
// / \
// B-<-<-<-<-A
// BOTTOM
//
////////////////////////////////////////////////////////////////////////////////////
class face
{
public:
int mA;
int mB;
int mC;
int mLeft;
int mRight;
int mBottom;
int mFlips;
int& opposing_node(int A, int B)
{
if (mA!=A && mA!=B)
{
return mA;
}
if (mB!=A && mB!=B)
{
return mB;
}
assert(mC!=A && mC!=B);
return mC;
}
int& relative_left(int edge)
{
if (edge==mLeft)
{
return mRight;
}
if (edge==mRight)
{
return mBottom;
}
assert(edge==mBottom); // If you hit this assert, then the edge is not in this face
return mLeft;
}
int& relative_right(int edge)
{
if (edge==mLeft)
{
return mBottom;
}
if (edge==mRight)
{
return mLeft;
}
assert(edge==mBottom); // If you hit this assert, then the edge is not in this face
return mRight;
}
};
////////////////////////////////////////////////////////////////////////////////////
// The Sort Node Class
//
// Used To Sort Nodes In Increasing X Order
////////////////////////////////////////////////////////////////////////////////////
class sort_node
{
public:
bool operator<(const sort_node& r) const
{
return ((*r.mNodePointer)[0] < (*mNodePointer)[0]);
}
int mNodeHandle;
TNODE* mNodePointer;
};
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
typedef typename ratl::handle_pool_vs<edge, MAXEDGES> TEdges;
typedef typename ratl::handle_pool_vs<edge, MAXEDGES>::iterator TEdgesIter;
typedef typename ratl::handle_pool_vs<face, MAXFACES> TFaces;
typedef typename ratl::vector_vs<sort_node, MAXNODES> TSortNodes;
TGraph& mGraph; // A Reference To The Graph Points To Triangulate
TLinks mLinks;
TEdges mEdges;
TFaces mFaces;
THull mHull; // The Convex Hull
THullIter mHullIter;
TSortNodes mSortNodes; // Need To Presort Nodes On (x-Axis) For Insertion Hull
sort_node mSortNode;
private:
////////////////////////////////////////////////////////////////////////////////////
// Copy All The Graph Nodes To Our Sort Node Class And Run Heap Sort
////////////////////////////////////////////////////////////////////////////////////
void sort_points()
{
mSortNodes.clear();
for (TGraph::TNodes::iterator i=mGraph.nodes_begin(); i!=mGraph.nodes_end(); i++)
{
mSortNode.mNodeHandle = mGraph.node_handle(i);
mSortNode.mNodePointer = &(*i);
mSortNodes.push_back(mSortNode);
}
mSortNodes.sort();
}
////////////////////////////////////////////////////////////////////////////////////
// Create A New Edge A->B, And Fix Up The Face
////////////////////////////////////////////////////////////////////////////////////
int add_edge(int A, int B, int Face=0, bool OnHull=true)
{
assert(A!=B );
int nEdge = mLinks.get(mGraph.node_index(A), mGraph.node_index(B));
// Apparently This Edge Does Not Exist, So Make A New One
//--------------------------------------------------------
if (nEdge==0)
{
nEdge= mEdges.alloc();
mHull.insert_after(mHullIter, nEdge);
assert(mHullIter!=mHull.end());
mEdges[nEdge].mA = A;
mEdges[nEdge].mB = B;
mEdges[nEdge].mHullLoc = mHullIter;
mEdges[nEdge].mOnHull = true;
mEdges[nEdge].mFlips = 0;
mEdges[nEdge].mLeft = 0;
mEdges[nEdge].mRight = 0;
mLinks.get(mGraph.node_index(A), mGraph.node_index(B)) = nEdge;
mLinks.get(mGraph.node_index(B), mGraph.node_index(A)) = nEdge;
}
// If This Edge DOES Already Exist, Then We Need To Remove It From The Hull
//--------------------------------------------------------------------------
else if (mEdges[nEdge].mOnHull)
{
assert(mEdges[nEdge].mHullLoc!=mHull.end());
if (mHullIter==mEdges[nEdge].mHullLoc)
{
mHull.erase(mHullIter); // Make Sure To Fix Up The Hull Iter If That Is What We Are Removing
}
else
{
mHull.erase(mEdges[nEdge].mHullLoc);
}
mEdges[nEdge].mOnHull = false;
}
// If The Edge Was Made With The Same Orientation Currently Asked For (A->B), Then Mark Face As Right
//----------------------------------------------------------------------------------------------------
if (mEdges[nEdge].mA==A)
{
mEdges[nEdge].mRight = Face;
}
else
{
mEdges[nEdge].mLeft = Face;
}
return nEdge;
}
////////////////////////////////////////////////////////////////////////////////////
// Create A New Face A->B->C, And Fix Up The Edges & Neighboring Faces
////////////////////////////////////////////////////////////////////////////////////
int add_face(int A, int B, int C)
{
int Temp = 0;
int nFace = mFaces.alloc();
// First, Make Sure Node A.x Is Greater Than B and C. If Not, Swap With B or C
//------------------------------------------------------------------------------
if (mGraph.get_node(B)[0]>mGraph.get_node(A)[0])
{
Temp = A;
A = B;
B = Temp;
}
if (mGraph.get_node(C)[0]>mGraph.get_node(A)[0])
{
Temp = A;
A = C;
C = Temp;
}
// Similarly, Make Sure Node B.y Is Greater Than Node C.y
//--------------------------------------------------------
if (mGraph.get_node(C).LRTest(mGraph.get_node(A), mGraph.get_node(B))==Side_Left)
{
Temp = C;
C = B;
B = Temp;
}
// DEBUG ASSERTS
//====================================================================================
// IF YOU HIT THESE ASSERTS, CHANCES ARE THAT YOU ARE TRYING TO TRIANGULATE OVER A SET
// WITH MORE THAN 2 COLINEAR POINTS ON THE SAME FACE. INSERT HULL WILL FAIL IN THIS
// FACE. INSERT HULL WILL FAIL IN THIS SITUATION
assert(mGraph.get_node(C).LRTest(mGraph.get_node(A), mGraph.get_node(B))==Side_Right);
assert(mGraph.get_node(A).LRTest(mGraph.get_node(B), mGraph.get_node(C))==Side_Right);
assert(mGraph.get_node(B).LRTest(mGraph.get_node(C), mGraph.get_node(A))==Side_Right);
//====================================================================================
mFaces[nFace].mA = A;
mFaces[nFace].mB = B;
mFaces[nFace].mC = C;
mFaces[nFace].mRight = add_edge(C, A, nFace);
mFaces[nFace].mBottom = add_edge(A, B, nFace);
mFaces[nFace].mLeft = add_edge(B, C, nFace);
mFaces[nFace].mFlips = 0;
return nFace;
}
////////////////////////////////////////////////////////////////////////////////////
// Insertion Hull Triangulation
//
// This algorithm works by scanning the outer convex hull of the set of points that
// have already been triangulated. When encountering a hull edge which evaluates
// LEFT in a left right test (remember, the triangles always have clockwise orientation)
// it adds a face to the triangulation including the edge as one side of the triangle
// and two new edges to the node handle. It's very important to traverse the convex
// hull in counter clockwise order (backwards).
//
// In the example below, we assume the convex hull starts at the edge (CA). (nodeHandle) is
// RIGHT of (C->A), so it skips that edge and moves on to (D->C). (nodeHandle) is in fact
// LEFT of (D->C), so we would add a new face that would go (D->nodeHandle->C), and we remove
// (D->C) from the hull.
//
//
//
// (C)-------------(A)
// / \ __/ \
// (nodeHandle) / \ __/ \
// / \ / \
// (D)----____(B)_ \
// \ | \ __
// \ | \__
// \ | \
//
////////////////////////////////////////////////////////////////////////////////////
void insert_point(int nodeHandle)
{
// Iterate Over The Existing Convex Hull
//---------------------------------------
for (mHullIter = mHull.begin(); mHullIter!=mHull.end(); mHullIter++)
{
edge& curEdge = mEdges[*mHullIter];
// Can This Edge "See" The node Handle We Have Passed In?
//---------------------------------------------------------
if ( mGraph.get_node(nodeHandle).LRTest(mGraph.get_node(curEdge.mA), mGraph.get_node(curEdge.mB))==Side_Left )
{
// Then Add The Face And Remove This Edge From The Hull
//------------------------------------------------------
add_face(curEdge.mA, curEdge.mB, nodeHandle);
}
}
}
////////////////////////////////////////////////////////////////////////////////////
// Edge Flip Function
//
// This function scans the edge list for any edge that is "bad" (defined as not
// fitting within the circumscribed circle of either adjoining face). When it
// encounters one, it "flips" the edge in question and fixes up the adjoining faces
// which were altered.
//
//
// The Flip Edge (PtA->PtB):
//
//
//
// BEFORE AFTER
//
// (PtR) (PtA)
// / \ / | \
// / \ / | \
// / (FaceR) \ / V \
// / \ / | \
// (PtB)-<---------<-(PtA) (PtR) | (PtL)
// \ / \ | /
// \ (FaceL) / \ V /
// \ / \ | /
// \ / \ | /
// (PtL) (PtB)
//
////////////////////////////////////////////////////////////////////////////////////
int flip()
{
int Flipped = 0;
int EdgeHandle;
int PtR, PtL, PtA, PtB;
int EdgeRL, EdgeRR, EdgeLL, EdgeLR;
// Iterate Through All The Edges Looking For Potential NON-Delauney Edges
//------------------------------------------------------------------------
for (TEdgesIter CurEdge=mEdges.begin(); CurEdge!=mEdges.end(); CurEdge++)
{
// If It Is On The Hull, We Don't Even Need To Look At It
//--------------------------------------------------------
if (!(*CurEdge).mOnHull)
{
edge& EdgeAt = *CurEdge;
face& FaceR = mFaces[EdgeAt.mRight];
face& FaceL = mFaces[EdgeAt.mLeft];
EdgeHandle = mEdges.index_to_handle(CurEdge.index());
PtA = EdgeAt.mA;
PtB = EdgeAt.mB;
PtR = FaceR.opposing_node(PtA, PtB);
PtL = FaceL.opposing_node(PtA, PtB);
assert(EdgeAt.mRight!=EdgeAt.mLeft);
assert(PtA!=PtB);
assert(PtR!=PtL);
assert(PtA!=PtR && PtA!=PtL);
assert(PtB!=PtR && PtB!=PtL);
// Is This Edge Invalid For Delaunay?
//-------------------------------------
if (!mGraph.get_node(PtB).InCircle(mGraph.get_node(PtR), mGraph.get_node(PtL), mGraph.get_node(PtA)) &&
!mGraph.get_node(PtA).InCircle(mGraph.get_node(PtR), mGraph.get_node(PtB), mGraph.get_node(PtL))
)
{
// Change The Link: Remove The Old, Add The New
//----------------------------------------------
mLinks.get(mGraph.node_index(PtA), mGraph.node_index(PtB)) = 0;
mLinks.get(mGraph.node_index(PtB), mGraph.node_index(PtA)) = 0;
mLinks.get(mGraph.node_index(PtR), mGraph.node_index(PtL)) = EdgeHandle;
mLinks.get(mGraph.node_index(PtL), mGraph.node_index(PtR)) = EdgeHandle;
Flipped++;
EdgeAt.mFlips++;
FaceL.mFlips++;
FaceR.mFlips++;
// Flip The Edge We Found
//------------------------
EdgeAt.mA = PtR;
EdgeAt.mB = PtL;
// Calculate Relatave Edges And Points Assuming (EdgeAt) Were mBottom For The Two Faces
//--------------------------------------------------------------------------------------
EdgeRL = FaceR.relative_left(EdgeHandle);
EdgeRR = FaceR.relative_right(EdgeHandle);
EdgeLL = FaceL.relative_left(EdgeHandle);
EdgeLR = FaceL.relative_right(EdgeHandle);
// Fix Edges Which Had Been Rotated To New Faces
//-----------------------------------------------
mEdges[EdgeLR].flip_face(EdgeAt.mLeft, EdgeAt.mRight);
mEdges[EdgeRR].flip_face(EdgeAt.mRight, EdgeAt.mLeft);
// Rotate The Edges Clockwise
//----------------------------
FaceR.mLeft = EdgeLR;
FaceR.mRight = EdgeRL;
FaceR.mBottom = EdgeHandle;
FaceL.mLeft = EdgeRR;
FaceL.mRight = EdgeLL;
FaceL.mBottom = EdgeHandle;
FaceR.mA = PtR;
FaceR.mB = PtL;
FaceR.mC = PtB;
FaceL.mA = PtR;
FaceL.mB = PtL;
FaceL.mC = PtA;
// DEBUG VERIFICATION
//========================================================================
#ifdef _DEBUG
mEdges[FaceR.mLeft ].verify(FaceR.mA, FaceR.mB, FaceR.mC, EdgeAt.mRight);
mEdges[FaceR.mRight ].verify(FaceR.mA, FaceR.mB, FaceR.mC, EdgeAt.mRight);
mEdges[FaceR.mBottom].verify(FaceR.mA, FaceR.mB, EdgeAt.mRight);
mEdges[FaceL.mLeft ].verify(FaceL.mA, FaceL.mB, FaceL.mC, EdgeAt.mLeft);
mEdges[FaceL.mRight ].verify(FaceL.mA, FaceL.mB, FaceL.mC, EdgeAt.mLeft);
mEdges[FaceL.mBottom].verify(FaceL.mA, FaceL.mB, EdgeAt.mLeft);
#endif
assert(EdgeAt.mRight!=EdgeAt.mLeft);
assert(PtA!=PtB);
assert(PtR!=PtL);
//========================================================================
}
}
}
return Flipped;
}
};
}
#endif

1776
code/ragl/graph_vs.h Normal file

File diff suppressed because it is too large Load Diff

458
code/ragl/kdtree_vs.h Normal file
View File

@@ -0,0 +1,458 @@
////////////////////////////////////////////////////////////////////////////////////////
// RAVEN STANDARD TEMPLATE LIBRARY
// (c) 2002 Activision
//
//
// KD Tree
// -------
//
//
//
// NOTES:
//
//
//
////////////////////////////////////////////////////////////////////////////////////////
#if !defined(RATL_KDTREE_VS_INC)
#define RATL_KDTREE_VS_INC
////////////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////////////
#if defined(RA_DEBUG_LINKING)
#pragma message("...including kdtree_vs.h")
#endif
#if !defined(RAGL_COMMON_INC)
#include "ragl_common.h"
#endif
namespace ragl
{
////////////////////////////////////////////////////////////////////////////////////////
// The List Class
////////////////////////////////////////////////////////////////////////////////////////
template <class T, int DIMENSION, int SIZE>
class kdtree_vs : public ratl::ratl_base
{
public:
////////////////////////////////////////////////////////////////////////////////////
// Capacity Enum
////////////////////////////////////////////////////////////////////////////////////
enum
{
CAPACITY = SIZE,
NULL_NODE = SIZE+2, // Invalid Node ID
TARG_NODE = SIZE+3 // Used To Mark Nodes Add Location
};
////////////////////////////////////////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////////////////////////////////////////
kdtree_vs() : mRoot(NULL_NODE)
{
}
////////////////////////////////////////////////////////////////////////////////////
// How Many Objects Are In This Tree
////////////////////////////////////////////////////////////////////////////////////
int size() const
{
return (mPool.size());
}
////////////////////////////////////////////////////////////////////////////////////
// Are There Any Objects In This Tree?
////////////////////////////////////////////////////////////////////////////////////
bool empty() const
{
return (mRoot==NULL_NODE);
}
////////////////////////////////////////////////////////////////////////////////////
// Is This List Filled?
////////////////////////////////////////////////////////////////////////////////////
bool full() const
{
return (mPool.full());
}
////////////////////////////////////////////////////////////////////////////////////
// Clear All Elements
////////////////////////////////////////////////////////////////////////////////////
void clear()
{
mRoot = NULL_NODE;
mPool.clear();
}
////////////////////////////////////////////////////////////////////////////////////
// Add A New Element To The Tree
////////////////////////////////////////////////////////////////////////////////////
void add(const T& data)
{
// CREATE: New
//--------------------------------------------
int nNew = mPool.alloc();
mPool[nNew].mData = data;
mPool[nNew].mLeft = NULL_NODE;
mPool[nNew].mRight = NULL_NODE;
// LINK: (nNew)->(Parent)
//--------------------------------------------
if (mRoot==NULL_NODE)
{
mRoot = nNew;
mPool[nNew].mParent = NULL_NODE;
return;
}
// LINK: (nNew)->(Parent)
//--------------------------------------------
mPool[nNew].mParent = find_index(data, mRoot, 0, true, true);
// LINK: (Parent)->(nNew)
//--------------------------------------------
if (mPool[mPool[nNew].mParent].mLeft==TARG_NODE)
{
mPool[mPool[nNew].mParent].mLeft = nNew;
}
else if (mPool[mPool[nNew].mParent].mRight==TARG_NODE)
{
mPool[mPool[nNew].mParent].mRight = nNew;
}
// Hey! It Didn't Mark Any Targets, Which Means We Found An Exact match To This Data
//------------------------------------------------------------------------------------
else
{
mPool.free(nNew);
}
}
////////////////////////////////////////////////////////////////////////////////////
// Does (data) Exist In The Tree?
////////////////////////////////////////////////////////////////////////////////////
bool find(const T& data)
{
assert(mRoot!=NULL_NODE); // If You Hit This Assert, You Are Asking For Data On An Empty Tree
int node = find_index(data, mRoot, 0, true, true);
// Exact Find, Or Found Root?
//----------------------------
if (mPool[node].mData==data || mPool[node].mParent==NULL_NODE)
{
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
class range_query
{
public:
range_query() {}
public:
ratl::vector_vs<T, SIZE> mReported;
T mMins;
T mMaxs;
};
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
void find(range_query& query)
{
if (mRoot!=NULL_NODE)
{
query.mReported.clear();
tree_search(query);
}
}
private:
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
class node
{
public:
int mParent;
int mLeft;
int mRight;
T mData;
};
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
class range_bounds
{
public:
int mMins[DIMENSION];
int mMaxs[DIMENSION];
};
////////////////////////////////////////////////////////////////////////////////////
// This Private Function Of The Class Does A Standard Binary Tree Search
////////////////////////////////////////////////////////////////////////////////////
int find_index(const T& data, int curNode, int curDimension, bool returnClosest, bool markTarget)
{
// Did We Just Go Off The End Of The Tree Or Find The Data We Were Looking For?
//------------------------------------------------------------------------------
if (curNode==NULL_NODE || mPool[curNode].mData==data)
{
return curNode;
}
// Calculate The Next Dimension For Searching
//--------------------------------------------
int nextDimension = curDimension+1;
if (nextDimension>=DIMENSION)
{
nextDimension = 0;
}
// Search Recursivly Down The Tree Either Left (For Data > Current Node), Or Right
//---------------------------------------------------------------------------------
int findRecursive;
bool goLeft = (data[curDimension] < mPool[curNode].mData[curDimension]);
if (goLeft)
{
findRecursive = find_index(data, mPool[curNode].mLeft, nextDimension, returnClosest, markTarget);
}
else
{
findRecursive = find_index(data, mPool[curNode].mRight, nextDimension, returnClosest, markTarget);
}
// Success!
//----------
if (findRecursive!=NULL_NODE)
{
return findRecursive;
}
// If We Want To Return The CLOSEST Node, And We Went Off The End, Then Return This One
//--------------------------------------------------------------------------------------
if (returnClosest)
{
// If We Are Asked To Mark The Target, We Mark (TARG_NODE) At Either mLeft or mRight,
// Depending On Where The Node Should Have Been
//----------------------------------------------------------------------------------
if (markTarget)
{
if (goLeft)
{
mPool[curNode].mLeft = TARG_NODE;
}
else
{
mPool[curNode].mRight = TARG_NODE;
}
}
// Go Ahead And Return This Node, It's The One We Would Have Put As The Child
return curNode;
}
// Return The Results Of The Recursive Call
//------------------------------------------
return NULL_NODE;
}
////////////////////////////////////////////////////////////////////////////////////
// This function just sets up the range bounds and starts the recursive tree search
////////////////////////////////////////////////////////////////////////////////////
void tree_search(range_query& query)
{
range_bounds bounds;
for (int i=0; i<DIMENSION; i++)
{
bounds.mMins[i] = 0;
bounds.mMaxs[i] = 0;
}
tree_search(query, mRoot, 0, bounds);
}
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
void tree_search(range_query& query, int curNode, int curDimension, range_bounds bounds)
{
assert(curNode<SIZE);
// Is This Node In The Query Range? If So, Report It
//----------------------------------------------------
if (curNode!=NULL_NODE && tree_search_node_in_range(query, mPool[curNode]))
{
query.mReported.push_back(mPool[curNode].mData);
}
// If This Is A Leaf Node, We're Done Here
//-----------------------------------------
if (curNode==NULL_NODE || (mPool[curNode].mLeft==NULL_NODE && mPool[curNode].mRight==NULL_NODE))
{
return;
}
// Calculate The Next Dimension For Searching
//--------------------------------------------
int nextDimension = curDimension+1;
if (nextDimension>=DIMENSION)
{
nextDimension = 0;
}
// Test To See If Our Subtree Is In Range
//----------------------------------------
ESide Side = tree_search_bounds_in_range(query, bounds);
// If The Bounds Are Contained Entirely Within The Query Range, We Report The Sub Tree
//-------------------------------------------------------------------------------------
if (Side==Side_AllIn)
{
tree_search_report_sub_tree(query, curNode);
}
// Otherwise, If Our Bounds Intersect The Query Range, We Need To Look Further
//-----------------------------------------------------------------------------
else if (Side==Side_In)
{
// Test The Left Child
//---------------------
if (mPool[curNode].mLeft!=NULL_NODE)
{
int OldMaxs = bounds.mMaxs[curDimension];
if ( !bounds.mMins[curDimension] || ((mPool[curNode].mData[curDimension]) < (mPool[bounds.mMins[curDimension]].mData[curDimension])) )
{
bounds.mMins[curDimension] = curNode;
}
tree_search(query, mPool[curNode].mLeft, nextDimension, bounds);
bounds.mMaxs[curDimension] = OldMaxs; // Restore Old Maxs For The Right Child Search
}
// Test The Right Child
//----------------------
if (mPool[curNode].mRight!=NULL_NODE)
{
if ( !bounds.mMaxs[curDimension] || ((mPool[bounds.mMaxs[curDimension]].mData[curDimension]) < (mPool[curNode].mData[curDimension])) )
{
bounds.mMaxs[curDimension] = curNode;
}
tree_search(query, mPool[curNode].mRight, nextDimension, bounds);
}
}
}
////////////////////////////////////////////////////////////////////////////////////
// This Function Returns True If The Node Is Within The Query Range
////////////////////////////////////////////////////////////////////////////////////
bool tree_search_node_in_range(range_query& query, node& n)
{
for (int dim=0; dim<DIMENSION; dim++)
{
if (n.mData[dim]<query.mMins[dim] || query.mMaxs[dim]<n.mData[dim])
{
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
ESide tree_search_bounds_in_range(range_query& query, range_bounds& bounds)
{
ESide S = Side_AllIn;
for (int dim=0; dim<DIMENSION; dim++)
{
// If Any Of Our Dimensions Are Undefined Right Now, Always Return INTERSECT
//---------------------------------------------------------------------------
if (!bounds.mMaxs[dim] || !bounds.mMins[dim])
{
return Side_In;
}
// Check To See If They Intersect At All?
//----------------------------------------
if ((mPool[bounds.mMaxs[dim]].mData[dim]<query.mMins[dim]) ||
(query.mMaxs[dim]<mPool[bounds.mMins[dim]].mData[dim]))
{
return Side_None;
}
// Check To See If It Is Contained
//---------------------------------
if ((mPool[bounds.mMins[dim]].mData[dim]<query.mMins[dim]) ||
(query.mMaxs[dim]<mPool[bounds.mMaxs[dim]].mData[dim]))
{
S = Side_In;
}
}
return S;
}
////////////////////////////////////////////////////////////////////////////////////
// Add The Cur Node And All Childeren Of The Cur Node
////////////////////////////////////////////////////////////////////////////////////
void tree_search_report_sub_tree(range_query& query, int curNode)
{
assert(curNode<SIZE);
if (mPool[curNode].mLeft!=NULL_NODE)
{
query.mReported.push_back(mPool[mPool[curNode].mLeft].mData);
tree_search_report_sub_tree(query, mPool[curNode].mRight);
}
if (mPool[curNode].mRight!=NULL_NODE)
{
query.mReported.push_back(mPool[mPool[curNode].mRight].mData);
tree_search_report_sub_tree(query, mPool[curNode].mRight);
}
}
////////////////////////////////////////////////////////////////////////////////////
// Data
////////////////////////////////////////////////////////////////////////////////////
private:
ratl::handle_pool_vs<node, SIZE> mPool; // The Allocation Data Pool
int mRoot; // The Beginning Of The Tree
};
}
#endif

232
code/ragl/ragl_common.h Normal file
View File

@@ -0,0 +1,232 @@
////////////////////////////////////////////////////////////////////////////////////////
// RAVEN STANDARD TEMPLATE LIBRARY
// (c) 2002 Activision
//
//
// Common
// ------
// The raven libraries contain a number of common defines, enums, and typedefs which
// need to be accessed by all templates. Each of these is included here.
//
// Also included is a safeguarded assert file for all the asserts in RTL.
//
// This file is included in EVERY TEMPLATE, so it should be very light in order to
// reduce compile times.
//
//
// Format
// ------
// In order to simplify code and provide readability, the template library has some
// standard formats. Any new templates or functions should adhere to these formats:
//
// - All memory is statically allocated, usually by parameter SIZE
// - All classes provide an enum which defines constant variables, including CAPACITY
// - All classes which moniter the number of items allocated provide the following functions:
// size() - the number of objects
// empty() - does the container have zero objects
// full() - does the container have any room left for more objects
// clear() - remove all objects
//
//
// - Functions are defined in the following order:
// Capacity
// Constructors (copy, from string, etc...)
// Range (size(), empty(), full(), clear(), etc...)
// Access (operator[], front(), back(), etc...)
// Modification (add(), remove(), push(), pop(), etc...)
// Iteration (begin(), end(), insert(), erase(), find(), etc...)
//
//
// NOTES:
//
//
//
////////////////////////////////////////////////////////////////////////////////////////
#if !defined(RAGL_COMMON_INC)
#define RAGL_COMMON_INC
////////////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////////////
#if defined(RA_DEBUG_LINKING)
#pragma message("...including ragl_common.h")
#endif
#if !defined(RAGL_ASSERT_INC)
#define RAGL_ASSERT_INC
#include <assert.h>
#endif
#if !defined(FINAL_BUILD)
#if !defined(RAGL_PROFILE_INC) && !defined(_XBOX)
#define RAGL_PROFILE_INC
#include "Windows.h"
#endif
#endif
#if !defined(RAVL_VEC_INC)
#include "..\Ravl\CVec.h"
#endif
#if !defined(RATL_COMMON_INC)
#include "..\Ratl\ratl_common.h"
#endif
namespace ragl
{
////////////////////////////////////////////////////////////////////////////////////////
// Enums
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// Typedefs
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// The Graph Node Class
////////////////////////////////////////////////////////////////////////////////////////
class CNode
{
public:
CNode() {}
CNode(const CVec3& Pt) : mPoint(Pt) {}
////////////////////////////////////////////////////////////////////////////////////
// Access Operator (For Triangulation)
////////////////////////////////////////////////////////////////////////////////////
float operator[](int dimension)
{
return mPoint[dimension];
}
////////////////////////////////////////////////////////////////////////////////////
// Equality Operator (For KDTree)
////////////////////////////////////////////////////////////////////////////////////
bool operator==(const CNode& t) const
{
return (t.mPoint==mPoint);
}
////////////////////////////////////////////////////////////////////////////////////
// Left Right Test (For Triangulation)
////////////////////////////////////////////////////////////////////////////////////
virtual ESide LRTest(const CNode& A, const CNode& B) const
{
return (mPoint.LRTest(A.mPoint, B.mPoint));
}
////////////////////////////////////////////////////////////////////////////////////
// Point In Circle (For Triangulation)
////////////////////////////////////////////////////////////////////////////////////
virtual bool InCircle(const CNode& A, const CNode& B, const CNode& C) const
{
return (mPoint.PtInCircle(A.mPoint, B.mPoint, C.mPoint));
}
public:
CVec3 mPoint;
};
////////////////////////////////////////////////////////////////////////////////////////
// The Graph Edge Class
////////////////////////////////////////////////////////////////////////////////////////
class CEdge
{
public:
int mNodeA;
int mNodeB;
bool mOnHull;
float mDistance;
bool mCanBeInval;
bool mValid;
};
////////////////////////////////////////////////////////////////////////////////////////
// The Geometric Reference Class
//
// This adds one additional function to the common ratl_ref class to allow access for
// various dimensions. It is used in both Triangulation and KDTree
////////////////////////////////////////////////////////////////////////////////////////
template <class TDATA, class TDATAREF>
class ragl_ref
{
public:
////////////////////////////////////////////////////////////////////////////////////
// Constructors
////////////////////////////////////////////////////////////////////////////////////
ragl_ref() {}
ragl_ref(const ragl_ref & r) {mDataRef = (TDATAREF)(r.mDataRef);}
ragl_ref(const TDATA & r) {mDataRef = (TDATAREF)(& r);}
ragl_ref(const TDATAREF r) {mDataRef = (TDATAREF)(r);}
////////////////////////////////////////////////////////////////////////////////////
// Assignment Operators
////////////////////////////////////////////////////////////////////////////////////
void operator=(const ragl_ref & r) {mDataRef = (TDATAREF)(r.mDataRef);}
void operator=(const TDATA & r) {mDataRef = (TDATAREF)(& r);}
void operator=(const TDATAREF r) {mDataRef = (TDATAREF)(r);}
////////////////////////////////////////////////////////////////////////////////////
// Access Operator (For Triangulation)
////////////////////////////////////////////////////////////////////////////////////
float operator[](int dimension) const {return (*mDataRef)[dimension];}
////////////////////////////////////////////////////////////////////////////////////
// Dereference Operator
////////////////////////////////////////////////////////////////////////////////////
TDATA & operator*() {return (*mDataRef);}
const TDATA & operator*() const {return (*mDataRef);}
TDATAREF handle() const {return mDataRef;}
////////////////////////////////////////////////////////////////////////////////////
// Equality / Inequality Operators
////////////////////////////////////////////////////////////////////////////////////
bool operator== (const ragl_ref& t) const {return (*mDataRef)==(*(t.mDataRef));}
bool operator!= (const ragl_ref& t) const {return (*mDataRef)!=(*(t.mDataRef));}
bool operator< (const ragl_ref& t) const {return (*mDataRef)< (*(t.mDataRef));}
bool operator> (const ragl_ref& t) const {return (*mDataRef)> (*(t.mDataRef));}
bool operator<= (const ragl_ref& t) const {return (*mDataRef)<=(*(t.mDataRef));}
bool operator>= (const ragl_ref& t) const {return (*mDataRef)>=(*(t.mDataRef));}
////////////////////////////////////////////////////////////////////////////////////
// Equality / Inequality Operators
////////////////////////////////////////////////////////////////////////////////////
bool operator== (const TDATA& t) const {return (*mDataRef)==t;}
bool operator!= (const TDATA& t) const {return (*mDataRef)!=t;}
bool operator< (const TDATA& t) const {return (*mDataRef)< t;}
bool operator> (const TDATA& t) const {return (*mDataRef)> t;}
bool operator<= (const TDATA& t) const {return (*mDataRef)<=t;}
bool operator>= (const TDATA& t) const {return (*mDataRef)>=t;}
////////////////////////////////////////////////////////////////////////////////////
// The Data Reference
////////////////////////////////////////////////////////////////////////////////////
private:
TDATAREF mDataRef;
};
}
#endif