OpenGTA/opensteer/include/OpenSteer/Proximity.h
Anonymous Maarten e20673c2cd 2007-04-16
2015-12-03 01:37:37 +01:00

338 lines
12 KiB
C++

// ----------------------------------------------------------------------------
//
//
// OpenSteer -- Steering Behaviors for Autonomous Characters
//
// Copyright (c) 2002-2005, Sony Computer Entertainment America
// Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//
// ----------------------------------------------------------------------------
//
//
// Proximity
//
// Data structures for accelerating proximity/locality/neighborhood queries
//
// 10-04-04 bk: put everything into the OpenSteer namespace
// 06-20-01 cwr: created
//
//
// ----------------------------------------------------------------------------
#ifndef OPENSTEER_PROXIMITY_H
#define OPENSTEER_PROXIMITY_H
#include <algorithm>
#include <vector>
#include "OpenSteer/Vec3.h"
#include "OpenSteer/lq.h" // XXX temp?
namespace OpenSteer {
// ----------------------------------------------------------------------------
// "tokens" are the objects manipulated by the spatial database
template <class ContentType>
class AbstractTokenForProximityDatabase
{
public:
virtual ~AbstractTokenForProximityDatabase () {}
// the client object calls this each time its position changes
virtual void updateForNewPosition (const Vec3& position) = 0;
// find all neighbors within the given sphere (as center and radius)
virtual void findNeighbors (const Vec3& center,
const float radius,
std::vector<ContentType>& results) = 0;
#ifndef NO_LQ_BIN_STATS
// only meaningful for LQProximityDatabase, provide dummy default
virtual void getBinPopulationStats (int& min, int& max, float& average)
{min=max=0; average=0.0;}
#endif // NO_LQ_BIN_STATS
};
// ----------------------------------------------------------------------------
// abstract type for all kinds of proximity databases
template <class ContentType>
class AbstractProximityDatabase
{
public:
// type for the "tokens" manipulated by this spatial database
typedef AbstractTokenForProximityDatabase<ContentType> tokenType;
virtual ~AbstractProximityDatabase() { /* Nothing to do? */ }
// allocate a token to represent a given client object in this database
virtual tokenType* allocateToken (ContentType parentObject) = 0;
// insert
// XXX maybe this should return an iterator?
// XXX see http://www.sgi.com/tech/stl/set.html
// virtual void insert (const ContentType& x) = 0;
// XXX name?
// returns the number of tokens in the proximity database
virtual int getPopulation (void) = 0;
};
// ----------------------------------------------------------------------------
// This is the "brute force" O(n^2) approach implemented in terms of the
// AbstractProximityDatabase protocol so it can be compared directly to other
// approaches. (e.g. the Boids plugin allows switching at runtime.)
template <class ContentType>
class BruteForceProximityDatabase
: public AbstractProximityDatabase<ContentType>
{
public:
// constructor
BruteForceProximityDatabase (void)
{
}
// destructor
virtual ~BruteForceProximityDatabase ()
{
}
// "token" to represent objects stored in the database
class tokenType : public AbstractTokenForProximityDatabase<ContentType>
{
public:
// constructor
tokenType (ContentType parentObject, BruteForceProximityDatabase& pd)
{
// store pointer to our associated database and the object this
// token represents, and store this token on the database's vector
bfpd = &pd;
object = parentObject;
bfpd->group.push_back (this);
}
// destructor
virtual ~tokenType ()
{
// remove this token from the database's vector
bfpd->group.erase (std::find (bfpd->group.begin(),
bfpd->group.end(),
this));
}
// the client object calls this each time its position changes
void updateForNewPosition (const Vec3& newPosition)
{
position = newPosition;
}
// find all neighbors within the given sphere (as center and radius)
void findNeighbors (const Vec3& center,
const float radius,
std::vector<ContentType>& results)
{
// loop over all tokens
const float r2 = radius * radius;
for (tokenIterator i = bfpd->group.begin();
i != bfpd->group.end();
i++)
{
const Vec3 offset = center - (**i).position;
const float d2 = offset.lengthSquared();
// push onto result vector when within given radius
if (d2 < r2) results.push_back ((**i).object);
}
}
private:
BruteForceProximityDatabase* bfpd;
ContentType object;
Vec3 position;
};
typedef std::vector<tokenType*> tokenVector;
typedef typename tokenVector::const_iterator tokenIterator;
// allocate a token to represent a given client object in this database
tokenType* allocateToken (ContentType parentObject)
{
return new tokenType (parentObject, *this);
}
// return the number of tokens currently in the database
int getPopulation (void)
{
return (int) group.size();
}
private:
// STL vector containing all tokens in database
tokenVector group;
};
// ----------------------------------------------------------------------------
// A AbstractProximityDatabase-style wrapper for the LQ bin lattice system
template <class ContentType>
class LQProximityDatabase : public AbstractProximityDatabase<ContentType>
{
public:
// constructor
LQProximityDatabase (const Vec3& center,
const Vec3& dimensions,
const Vec3& divisions)
{
const Vec3 halfsize (dimensions * 0.5f);
const Vec3 origin (center - halfsize);
lq = lqCreateDatabase (origin.x, origin.y, origin.z,
dimensions.x, dimensions.y, dimensions.z,
(int) round (divisions.x),
(int) round (divisions.y),
(int) round (divisions.z));
}
// destructor
virtual ~LQProximityDatabase ()
{
lqDeleteDatabase (lq);
lq = NULL;
}
// "token" to represent objects stored in the database
class tokenType : public AbstractTokenForProximityDatabase<ContentType>
{
public:
// constructor
tokenType (ContentType parentObject, LQProximityDatabase& lqsd)
{
lqInitClientProxy (&proxy, parentObject);
lq = lqsd.lq;
}
// destructor
virtual ~tokenType (void)
{
lqRemoveFromBin (&proxy);
}
// the client object calls this each time its position changes
void updateForNewPosition (const Vec3& p)
{
lqUpdateForNewLocation (lq, &proxy, p.x, p.y, p.z);
}
// find all neighbors within the given sphere (as center and radius)
void findNeighbors (const Vec3& center,
const float radius,
std::vector<ContentType>& results)
{
lqMapOverAllObjectsInLocality (lq,
center.x, center.y, center.z,
radius,
perNeighborCallBackFunction,
(void*)&results);
}
// called by LQ for each clientObject in the specified neighborhood:
// push that clientObject onto the ContentType vector in void*
// clientQueryState
// (parameter names commented out to prevent compiler warning from "-W")
static void perNeighborCallBackFunction (void* clientObject,
float /*distanceSquared*/,
void* clientQueryState)
{
typedef std::vector<ContentType> ctv;
ctv& results = *((ctv*) clientQueryState);
results.push_back ((ContentType) clientObject);
}
#ifndef NO_LQ_BIN_STATS
// Get statistics about bin populations: min, max and
// average of non-empty bins.
void getBinPopulationStats (int& min, int& max, float& average)
{
lqGetBinPopulationStats (lq, &min, &max, &average);
}
#endif // NO_LQ_BIN_STATS
private:
lqClientProxy proxy;
lqDB* lq;
};
// allocate a token to represent a given client object in this database
tokenType* allocateToken (ContentType parentObject)
{
return new tokenType (parentObject, *this);
}
// count the number of tokens currently in the database
int getPopulation (void)
{
int count = 0;
lqMapOverAllObjects (lq, counterCallBackFunction, &count);
return count;
}
// (parameter names commented out to prevent compiler warning from "-W")
static void counterCallBackFunction (void* /*clientObject*/,
float /*distanceSquared*/,
void* clientQueryState)
{
int& counter = *(int*)clientQueryState;
counter++;
}
private:
lqDB* lq;
};
} // namespace OpenSteer
// ----------------------------------------------------------------------------
#endif // OPENSTEER_PROXIMITY_H