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

324 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.
//
// ----------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------ */
/* */
/* Locality Query (LQ) Facility */
/* */
/* ------------------------------------------------------------------ */
/*
This utility is a spatial database which stores objects each of
which is associated with a 3d point (a location in a 3d space).
The points serve as the "search key" for the associated object.
It is intended to efficiently answer "sphere inclusion" queries,
also known as range queries: basically questions like:
Which objects are within a radius R of the location L?
In this context, "efficiently" means significantly faster than the
naive, brute force O(n) testing of all known points. Additionally
it is assumed that the objects move along unpredictable paths, so
that extensive preprocessing (for example, constructing a Delaunay
triangulation of the point set) may not be practical.
The implementation is a "bin lattice": a 3d rectangular array of
brick-shaped (rectangular parallelepipeds) regions of space. Each
region is represented by a pointer to a (possibly empty) doubly-
linked list of objects. All of these sub-bricks are the same
size. All bricks are aligned with the global coordinate axes.
Terminology used here: the region of space associated with a bin
is called a sub-brick. The collection of all sub-bricks is called
the super-brick. The super-brick should be specified to surround
the region of space in which (almost) all the key-points will
exist. If key-points move outside the super-brick everything will
continue to work, but without the speed advantage provided by the
spatial subdivision. For more details about how to specify the
super-brick's position, size and subdivisions see lqCreateDatabase
below.
Overview of usage: an application using this facility would first
create a database with lqCreateDatabase. For each client object
the application wants to put in the database it creates a
lqClientProxy and initializes it with lqInitClientProxy. When a
client object moves, the application calls lqUpdateForNewLocation.
To perform a query lqMapOverAllObjectsInLocality is passed an
application-supplied call-back function to be applied to all
client objects in the locality. See lqCallBackFunction below for
more detail. The lqFindNearestNeighborWithinRadius function can
be used to find a single nearest neighbor using the database.
Note that "locality query" is also known as neighborhood query,
neighborhood search, near neighbor search, and range query. For
additional information on this and related topics see:
http://www.red3d.com/cwr/boids/ips.html
For some description and illustrations of this database in use,
see this paper: http://www.red3d.com/cwr/papers/2000/pip.html
*/
#ifndef _lq_h
#define _lq_h
#ifdef __cplusplus
extern "C"
{
#endif
/* ------------------------------------------------------------------ */
/* */
/* Data types use by LQ */
/* */
/* ------------------------------------------------------------------ */
/* This structure represents the spatial database. Typically one of
these would be created (by a call to lqCreateDatabase) for a given
application. */
typedef struct lqInternalDB lqDB;
/* ------------------------------------------------------------------ */
/* This structure is a proxy for (and contains a pointer to) a client
(application) object in the spatial database. One of these exists
for each client object. This might be included within the
structure of a client object, or could be allocated separately. */
typedef struct lqClientProxy
{
/* previous object in this bin, or NULL */
struct lqClientProxy* prev;
/* next object in this bin, or NULL */
struct lqClientProxy* next;
/* bin ID (pointer to pointer to bin contents list) */
struct lqClientProxy** bin;
/* pointer to client object */
void* object;
/* the object's location ("key point") used for spatial sorting */
float x;
float y;
float z;
} lqClientProxy;
/* ------------------------------------------------------------------ */
/* */
/* Basic API */
/* */
/* ------------------------------------------------------------------ */
/* Allocate and initialize an LQ database, returns a pointer to it.
The application needs to call this before using the LQ facility.
The nine parameters define the properties of the "super-brick":
(1) origin: coordinates of one corner of the super-brick, its
minimum x, y and z extent.
(2) size: the width, height and depth of the super-brick.
(3) the number of subdivisions (sub-bricks) along each axis.
This routine also allocates the bin array, and initialize its
contents. */
lqDB* lqCreateDatabase (float originx, float originy, float originz,
float sizex, float sizey, float sizez,
int divx, int divy, int divz);
/* ------------------------------------------------------------------ */
/* Deallocates the LQ database */
void lqDeleteDatabase (lqDB*);
/* ------------------------------------------------------------------ */
/* The application needs to call this once on each lqClientProxy at
setup time to initialize its list pointers and associate the proxy
with its client object. */
void lqInitClientProxy (lqClientProxy* proxy, void* clientObject);
/* ------------------------------------------------------------------ */
/* Call for each client object every time its location changes. For
example, in an animation application, this would be called each
frame for every moving object. */
void lqUpdateForNewLocation (lqDB* lq,
lqClientProxy* object,
float x, float y, float z);
/* ------------------------------------------------------------------ */
/* Apply an application-specific function to all objects in a certain
locality. The locality is specified as a sphere with a given
center and radius. All objects whose location (key-point) is
within this sphere are identified and the function is applied to
them. The application-supplied function takes three arguments:
(1) a void* pointer to an lqClientProxy's "object".
(2) the square of the distance from the center of the search
locality sphere (x,y,z) to object's key-point.
(3) a void* pointer to the caller-supplied "client query state"
object -- typically NULL, but can be used to store state
between calls to the lqCallBackFunction.
This routine uses the LQ database to quickly reject any objects in
bins which do not overlap with the sphere of interest. Incremental
calculation of index values is used to efficiently traverse the
bins of interest. */
/* type for a pointer to a function used to map over client objects */
typedef void (* lqCallBackFunction) (void* clientObject,
float distanceSquared,
void* clientQueryState);
void lqMapOverAllObjectsInLocality (lqDB* lq,
float x, float y, float z,
float radius,
lqCallBackFunction func,
void* clientQueryState);
/* ------------------------------------------------------------------ */
/* */
/* Other API */
/* */
/* ------------------------------------------------------------------ */
/* Search the database to find the object whose key-point is nearest
to a given location yet within a given radius. That is, it finds
the object (if any) within a given search sphere which is nearest
to the sphere's center. The ignoreObject argument can be used to
exclude an object from consideration (or it can be NULL). This is
useful when looking for the nearest neighbor of an object in the
database, since otherwise it would be its own nearest neighbor.
The function returns a void* pointer to the nearest object, or
NULL if none is found. */
void* lqFindNearestNeighborWithinRadius (lqDB* lq,
float x, float y, float z,
float radius,
void* ignoreObject);
/* ------------------------------------------------------------------ */
/* Adds a given client object to a given bin, linking it into the bin
contents list. */
void lqAddToBin (lqClientProxy* object, lqClientProxy** bin);
/* ------------------------------------------------------------------ */
/* Removes a given client object from its current bin, unlinking it
from the bin contents list. */
void lqRemoveFromBin (lqClientProxy* object);
/* ------------------------------------------------------------------ */
/* Given an LQ database object and the nine basic parameters: fill in
the object's slots, allocate the bin array, and initialize its
contents. Normally the application does NOT call this directly, it
is called by lqCreateDatabase. */
void lqInitDatabase (lqDB* lq,
float originx, float originy, float originz,
float sizex, float sizey, float sizez,
int divx, int divy, int divz);
/* ------------------------------------------------------------------ */
/* Find the bin ID for a location in space. The location is given in
terms of its XYZ coordinates. The bin ID is a pointer to a pointer
to the bin contents list. */
lqClientProxy** lqBinForLocation (lqDB* lq, float x, float y, float z);
/* ------------------------------------------------------------------ */
/* Apply a user-supplied function to all objects in the database,
regardless of locality (cf lqMapOverAllObjectsInLocality) */
void lqMapOverAllObjects (lqDB* lq,
lqCallBackFunction func,
void* clientQueryState);
/* ------------------------------------------------------------------ */
/* Removes (all proxies for) all objects from all bins */
void lqRemoveAllObjects (lqDB* lq);
/* ------------------------------------------------------------------ */
/* Get statistics about bin populations: min, max and average of
non-empty bins. */
#ifndef NO_LQ_BIN_STATS
void lqGetBinPopulationStats (lqDB* lq,
int* min,
int* max,
float* average);
#endif /* NO_LQ_BIN_STATS */
/* ------------------------------------------------------------------ */
#ifndef NULL
#define NULL 0
#endif
/* ------------------------------------------------------------------ */
#ifdef __cplusplus
}
#endif
#endif /* _lq_h */