00001 #include "RakAssert.h"
00002 #include "GridSectorizer.h"
00003
00004 #include <math.h>
00005
00006 GridSectorizer::GridSectorizer()
00007 {
00008 grid=0;
00009 }
00010 GridSectorizer::~GridSectorizer()
00011 {
00012 if (grid)
00013 RakNet::OP_DELETE_ARRAY(grid, __FILE__, __LINE__);
00014 }
00015 void GridSectorizer::Init(const float _maxCellWidth, const float _maxCellHeight, const float minX, const float minY, const float maxX, const float maxY)
00016 {
00017 RakAssert(_maxCellWidth > 0.0f && _maxCellHeight > 0.0f);
00018 if (grid)
00019 RakNet::OP_DELETE_ARRAY(grid, __FILE__, __LINE__);
00020
00021 cellOriginX=minX;
00022 cellOriginY=minY;
00023 gridWidth=maxX-minX;
00024 gridHeight=maxY-minY;
00025 gridCellWidthCount=(int) ceil(gridWidth/_maxCellWidth);
00026 gridCellHeightCount=(int) ceil(gridHeight/_maxCellHeight);
00027
00028 cellWidth=gridWidth/gridCellWidthCount;
00029 cellHeight=gridHeight/gridCellHeightCount;
00030 invCellWidth = 1.0f / cellWidth;
00031 invCellHeight = 1.0f / cellHeight;
00032
00033 #ifdef _USE_ORDERED_LIST
00034 grid = RakNet::OP_NEW<DataStructures::OrderedList<void*, void*>>(gridCellWidthCount*gridCellHeightCount, __FILE__, __LINE__ );
00035 DataStructures::OrderedList<void*,void*>::IMPLEMENT_DEFAULT_COMPARISON();
00036 #else
00037 grid = RakNet::OP_NEW_ARRAY<DataStructures::List<void*> >(gridCellWidthCount*gridCellHeightCount, __FILE__, __LINE__ );
00038 #endif
00039 }
00040 void GridSectorizer::AddEntry(void *entry, const float minX, const float minY, const float maxX, const float maxY)
00041 {
00042 RakAssert(cellWidth>0.0f);
00043 RakAssert(minX < maxX && minY < maxY);
00044
00045 int xStart, yStart, xEnd, yEnd, xCur, yCur;
00046 xStart=WorldToCellXOffsetAndClamped(minX);
00047 yStart=WorldToCellYOffsetAndClamped(minY);
00048 xEnd=WorldToCellXOffsetAndClamped(maxX);
00049 yEnd=WorldToCellYOffsetAndClamped(maxY);
00050
00051 for (xCur=xStart; xCur <= xEnd; ++xCur)
00052 {
00053 for (yCur=yStart; yCur <= yEnd; ++yCur)
00054 {
00055 #ifdef _USE_ORDERED_LIST
00056 grid[yCur*gridCellWidthCount+xCur].Insert(entry,entry, true);
00057 #else
00058 grid[yCur*gridCellWidthCount+xCur].Insert(entry, __FILE__, __LINE__);
00059 #endif
00060 }
00061 }
00062 }
00063 #ifdef _USE_ORDERED_LIST
00064 void GridSectorizer::RemoveEntry(void *entry, const float minX, const float minY, const float maxX, const float maxY)
00065 {
00066 RakAssert(cellWidth>0.0f);
00067 RakAssert(minX <= maxX && minY <= maxY);
00068
00069 int xStart, yStart, xEnd, yEnd, xCur, yCur;
00070 xStart=WorldToCellXOffsetAndClamped(minX);
00071 yStart=WorldToCellYOffsetAndClamped(minY);
00072 xEnd=WorldToCellXOffsetAndClamped(maxX);
00073 yEnd=WorldToCellYOffsetAndClamped(maxY);
00074
00075 for (xCur=xStart; xCur <= xEnd; ++xCur)
00076 {
00077 for (yCur=yStart; yCur <= yEnd; ++yCur)
00078 {
00079 grid[yCur*gridCellWidthCount+xCur].RemoveIfExists(entry);
00080 }
00081 }
00082 }
00083 void GridSectorizer::MoveEntry(void *entry, const float sourceMinX, const float sourceMinY, const float sourceMaxX, const float sourceMaxY,
00084 const float destMinX, const float destMinY, const float destMaxX, const float destMaxY)
00085 {
00086 RakAssert(cellWidth>0.0f);
00087 RakAssert(sourceMinX < sourceMaxX && sourceMinY < sourceMaxY);
00088 RakAssert(destMinX < destMaxX && destMinY < destMaxY);
00089
00090 if (PositionCrossesCells(sourceMinX, sourceMinY, destMinX, destMinY)==false &&
00091 PositionCrossesCells(destMinX, destMinY, destMinX, destMinY)==false)
00092 return;
00093
00094 int xStartSource, yStartSource, xEndSource, yEndSource;
00095 int xStartDest, yStartDest, xEndDest, yEndDest;
00096 int xCur, yCur;
00097 xStartSource=WorldToCellXOffsetAndClamped(sourceMinX);
00098 yStartSource=WorldToCellYOffsetAndClamped(sourceMinY);
00099 xEndSource=WorldToCellXOffsetAndClamped(sourceMaxX);
00100 yEndSource=WorldToCellYOffsetAndClamped(sourceMaxY);
00101
00102 xStartDest=WorldToCellXOffsetAndClamped(destMinX);
00103 yStartDest=WorldToCellYOffsetAndClamped(destMinY);
00104 xEndDest=WorldToCellXOffsetAndClamped(destMaxX);
00105 yEndDest=WorldToCellYOffsetAndClamped(destMaxY);
00106
00107
00108 for (xCur=xStartSource; xCur <= xEndSource; ++xCur)
00109 {
00110 for (yCur=yStartSource; yCur <= yEndSource; ++yCur)
00111 {
00112 if (xCur < xStartDest || xCur > xEndDest ||
00113 yCur < yStartDest || yCur > yEndDest)
00114 {
00115 grid[yCur*gridCellWidthCount+xCur].RemoveIfExists(entry);
00116 }
00117 }
00118 }
00119
00120
00121 for (xCur=xStartDest; xCur <= xEndDest; ++xCur)
00122 {
00123 for (yCur=yStartDest; yCur <= yEndDest; ++yCur)
00124 {
00125 if (xCur < xStartSource || xCur > xEndSource ||
00126 yCur < yStartSource || yCur > yEndSource)
00127 {
00128 grid[yCur*gridCellWidthCount+xCur].Insert(entry,entry, true);
00129 }
00130 }
00131 }
00132 }
00133 #endif
00134 void GridSectorizer::GetEntries(DataStructures::List<void*>& intersectionList, const float minX, const float minY, const float maxX, const float maxY)
00135 {
00136 #ifdef _USE_ORDERED_LIST
00137 DataStructures::OrderedList<void*, void*>* cell;
00138 #else
00139 DataStructures::List<void*>* cell;
00140 #endif
00141 int xStart, yStart, xEnd, yEnd, xCur, yCur;
00142 unsigned index;
00143 xStart=WorldToCellXOffsetAndClamped(minX);
00144 yStart=WorldToCellYOffsetAndClamped(minY);
00145 xEnd=WorldToCellXOffsetAndClamped(maxX);
00146 yEnd=WorldToCellYOffsetAndClamped(maxY);
00147
00148 intersectionList.Clear(true, __FILE__,__LINE__);
00149 for (xCur=xStart; xCur <= xEnd; ++xCur)
00150 {
00151 for (yCur=yStart; yCur <= yEnd; ++yCur)
00152 {
00153 cell = grid+yCur*gridCellWidthCount+xCur;
00154 for (index=0; index < cell->Size(); ++index)
00155 intersectionList.Insert(cell->operator [](index), __FILE__, __LINE__);
00156 }
00157 }
00158 }
00159 bool GridSectorizer::PositionCrossesCells(const float originX, const float originY, const float destinationX, const float destinationY) const
00160 {
00161 return originX/cellWidth!=destinationX/cellWidth || originY/cellHeight!=destinationY/cellHeight;
00162 }
00163 int GridSectorizer::WorldToCellX(const float input) const
00164 {
00165 return (int)((input-cellOriginX)*invCellWidth);
00166 }
00167 int GridSectorizer::WorldToCellY(const float input) const
00168 {
00169 return (int)((input-cellOriginY)*invCellHeight);
00170 }
00171 int GridSectorizer::WorldToCellXOffsetAndClamped(const float input) const
00172 {
00173 int cell=WorldToCellX(input);
00174 cell = cell > 0 ? cell : 0;
00175 cell = gridCellWidthCount-1 < cell ? gridCellWidthCount-1 : cell;
00176 return cell;
00177 }
00178 int GridSectorizer::WorldToCellYOffsetAndClamped(const float input) const
00179 {
00180 int cell=WorldToCellY(input);
00181 cell = cell > 0 ? cell : 0;
00182 cell = gridCellHeightCount-1 < cell ? gridCellHeightCount-1 : cell;
00183 return cell;
00184 }
00185 void GridSectorizer::Clear(void)
00186 {
00187 int cur;
00188 int count = gridCellWidthCount*gridCellHeightCount;
00189 for (cur=0; cur<count;cur++)
00190 grid[cur].Clear(true, __FILE__,__LINE__);
00191 }