TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
RecastRegion.cpp File Reference
#include <float.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "Recast.h"
#include "RecastAlloc.h"
#include "RecastAssert.h"
#include <new>
+ Include dependency graph for RecastRegion.cpp:

Classes

struct  rcRegion
 
struct  rcSweepSpan
 

Macros

#define _USE_MATH_DEFINES
 

Functions

static void calculateDistanceField (rcCompactHeightfield &chf, unsigned short *src, unsigned short &maxDist)
 
static unsigned short * boxBlur (rcCompactHeightfield &chf, int thr, unsigned short *src, unsigned short *dst)
 
static bool floodRegion (int x, int y, int i, unsigned short level, unsigned short r, rcCompactHeightfield &chf, unsigned short *srcReg, unsigned short *srcDist, rcIntArray &stack)
 
static unsigned short * expandRegions (int maxIter, unsigned short level, rcCompactHeightfield &chf, unsigned short *srcReg, unsigned short *srcDist, unsigned short *dstReg, unsigned short *dstDist, rcIntArray &stack, bool fillStack)
 
static void sortCellsByLevel (unsigned short startLevel, rcCompactHeightfield &chf, unsigned short *srcReg, unsigned int nbStacks, rcIntArray *stacks, unsigned short loglevelsPerStack)
 
static void appendStacks (rcIntArray &srcStack, rcIntArray &dstStack, unsigned short *srcReg)
 
static void removeAdjacentNeighbours (rcRegion &reg)
 
static void replaceNeighbour (rcRegion &reg, unsigned short oldId, unsigned short newId)
 
static bool canMergeWithRegion (const rcRegion &rega, const rcRegion &regb)
 
static void addUniqueFloorRegion (rcRegion &reg, int n)
 
static bool mergeRegions (rcRegion &rega, rcRegion &regb)
 
static bool isRegionConnectedToBorder (const rcRegion &reg)
 
static bool isSolidEdge (rcCompactHeightfield &chf, unsigned short *srcReg, int x, int y, int i, int dir)
 
static void walkContour (int x, int y, int i, int dir, rcCompactHeightfield &chf, unsigned short *srcReg, rcIntArray &cont)
 
static bool mergeAndFilterRegions (rcContext *ctx, int minRegionArea, int mergeRegionSize, unsigned short &maxRegionId, rcCompactHeightfield &chf, unsigned short *srcReg, rcIntArray &overlaps)
 
static void addUniqueConnection (rcRegion &reg, int n)
 
static bool mergeAndFilterLayerRegions (rcContext *ctx, int minRegionArea, unsigned short &maxRegionId, rcCompactHeightfield &chf, unsigned short *srcReg, rcIntArray &)
 
bool rcBuildDistanceField (rcContext *ctx, rcCompactHeightfield &chf)
 
static void paintRectRegion (int minx, int maxx, int miny, int maxy, unsigned short regId, rcCompactHeightfield &chf, unsigned short *srcReg)
 
bool rcBuildRegionsMonotone (rcContext *ctx, rcCompactHeightfield &chf, const int borderSize, const int minRegionArea, const int mergeRegionArea)
 
bool rcBuildRegions (rcContext *ctx, rcCompactHeightfield &chf, const int borderSize, const int minRegionArea, const int mergeRegionArea)
 
bool rcBuildLayerRegions (rcContext *ctx, rcCompactHeightfield &chf, const int borderSize, const int minRegionArea)
 

Variables

static const unsigned short RC_NULL_NEI = 0xffff
 

Macro Definition Documentation

#define _USE_MATH_DEFINES

Function Documentation

static void addUniqueConnection ( rcRegion reg,
int  n 
)
static
1034 {
1035  for (int i = 0; i < reg.connections.size(); ++i)
1036  if (reg.connections[i] == n)
1037  return;
1038  reg.connections.push(n);
1039 }
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
rcIntArray connections
Definition: RecastRegion.cpp:535
void push(int item)
Definition: RecastAlloc.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void addUniqueFloorRegion ( rcRegion reg,
int  n 
)
static
598 {
599  for (int i = 0; i < reg.floors.size(); ++i)
600  if (reg.floors[i] == n)
601  return;
602  reg.floors.push(n);
603 }
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
rcIntArray floors
Definition: RecastRegion.cpp:536
void push(int item)
Definition: RecastAlloc.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void appendStacks ( rcIntArray srcStack,
rcIntArray dstStack,
unsigned short *  srcReg 
)
static
501 {
502  for (int j=0; j<srcStack.size(); j+=3)
503  {
504  int i = srcStack[j+2];
505  if ((i < 0) || (srcReg[i] != 0))
506  continue;
507  dstStack.push(srcStack[j]);
508  dstStack.push(srcStack[j+1]);
509  dstStack.push(srcStack[j+2]);
510  }
511 }
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
void push(int item)
Definition: RecastAlloc.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static unsigned short* boxBlur ( rcCompactHeightfield chf,
int  thr,
unsigned short *  src,
unsigned short *  dst 
)
static
186 {
187  const int w = chf.width;
188  const int h = chf.height;
189 
190  thr *= 2;
191 
192  for (int y = 0; y < h; ++y)
193  {
194  for (int x = 0; x < w; ++x)
195  {
196  const rcCompactCell& c = chf.cells[x+y*w];
197  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
198  {
199  const rcCompactSpan& s = chf.spans[i];
200  const unsigned short cd = src[i];
201  if (cd <= thr)
202  {
203  dst[i] = cd;
204  continue;
205  }
206 
207  int d = (int)cd;
208  for (int dir = 0; dir < 4; ++dir)
209  {
210  if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
211  {
212  const int ax = x + rcGetDirOffsetX(dir);
213  const int ay = y + rcGetDirOffsetY(dir);
214  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
215  d += (int)src[ai];
216 
217  const rcCompactSpan& as = chf.spans[ai];
218  const int dir2 = (dir+1) & 0x3;
219  if (rcGetCon(as, dir2) != RC_NOT_CONNECTED)
220  {
221  const int ax2 = ax + rcGetDirOffsetX(dir2);
222  const int ay2 = ay + rcGetDirOffsetY(dir2);
223  const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2);
224  d += (int)src[ai2];
225  }
226  else
227  {
228  d += cd;
229  }
230  }
231  else
232  {
233  d += cd*2;
234  }
235  }
236  dst[i] = (unsigned short)((d+5)/9);
237  }
238  }
239  }
240  return dst;
241 }
int height
The height of the heightfield. (Along the z-axis in cell units.)
Definition: Recast.h:308
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
G3D::int16 x
Definition: Vector2int16.h:37

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void calculateDistanceField ( rcCompactHeightfield chf,
unsigned short *  src,
unsigned short &  maxDist 
)
static
32 {
33  const int w = chf.width;
34  const int h = chf.height;
35 
36  // Init distance and points.
37  for (int i = 0; i < chf.spanCount; ++i)
38  src[i] = 0xffff;
39 
40  // Mark boundary cells.
41  for (int y = 0; y < h; ++y)
42  {
43  for (int x = 0; x < w; ++x)
44  {
45  const rcCompactCell& c = chf.cells[x+y*w];
46  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
47  {
48  const rcCompactSpan& s = chf.spans[i];
49  const unsigned char area = chf.areas[i];
50 
51  int nc = 0;
52  for (int dir = 0; dir < 4; ++dir)
53  {
54  if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
55  {
56  const int ax = x + rcGetDirOffsetX(dir);
57  const int ay = y + rcGetDirOffsetY(dir);
58  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
59  if (area == chf.areas[ai])
60  nc++;
61  }
62  }
63  if (nc != 4)
64  src[i] = 0;
65  }
66  }
67  }
68 
69 
70  // Pass 1
71  for (int y = 0; y < h; ++y)
72  {
73  for (int x = 0; x < w; ++x)
74  {
75  const rcCompactCell& c = chf.cells[x+y*w];
76  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
77  {
78  const rcCompactSpan& s = chf.spans[i];
79 
80  if (rcGetCon(s, 0) != RC_NOT_CONNECTED)
81  {
82  // (-1,0)
83  const int ax = x + rcGetDirOffsetX(0);
84  const int ay = y + rcGetDirOffsetY(0);
85  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
86  const rcCompactSpan& as = chf.spans[ai];
87  if (src[ai]+2 < src[i])
88  src[i] = src[ai]+2;
89 
90  // (-1,-1)
91  if (rcGetCon(as, 3) != RC_NOT_CONNECTED)
92  {
93  const int aax = ax + rcGetDirOffsetX(3);
94  const int aay = ay + rcGetDirOffsetY(3);
95  const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 3);
96  if (src[aai]+3 < src[i])
97  src[i] = src[aai]+3;
98  }
99  }
100  if (rcGetCon(s, 3) != RC_NOT_CONNECTED)
101  {
102  // (0,-1)
103  const int ax = x + rcGetDirOffsetX(3);
104  const int ay = y + rcGetDirOffsetY(3);
105  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
106  const rcCompactSpan& as = chf.spans[ai];
107  if (src[ai]+2 < src[i])
108  src[i] = src[ai]+2;
109 
110  // (1,-1)
111  if (rcGetCon(as, 2) != RC_NOT_CONNECTED)
112  {
113  const int aax = ax + rcGetDirOffsetX(2);
114  const int aay = ay + rcGetDirOffsetY(2);
115  const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 2);
116  if (src[aai]+3 < src[i])
117  src[i] = src[aai]+3;
118  }
119  }
120  }
121  }
122  }
123 
124  // Pass 2
125  for (int y = h-1; y >= 0; --y)
126  {
127  for (int x = w-1; x >= 0; --x)
128  {
129  const rcCompactCell& c = chf.cells[x+y*w];
130  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
131  {
132  const rcCompactSpan& s = chf.spans[i];
133 
134  if (rcGetCon(s, 2) != RC_NOT_CONNECTED)
135  {
136  // (1,0)
137  const int ax = x + rcGetDirOffsetX(2);
138  const int ay = y + rcGetDirOffsetY(2);
139  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 2);
140  const rcCompactSpan& as = chf.spans[ai];
141  if (src[ai]+2 < src[i])
142  src[i] = src[ai]+2;
143 
144  // (1,1)
145  if (rcGetCon(as, 1) != RC_NOT_CONNECTED)
146  {
147  const int aax = ax + rcGetDirOffsetX(1);
148  const int aay = ay + rcGetDirOffsetY(1);
149  const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 1);
150  if (src[aai]+3 < src[i])
151  src[i] = src[aai]+3;
152  }
153  }
154  if (rcGetCon(s, 1) != RC_NOT_CONNECTED)
155  {
156  // (0,1)
157  const int ax = x + rcGetDirOffsetX(1);
158  const int ay = y + rcGetDirOffsetY(1);
159  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 1);
160  const rcCompactSpan& as = chf.spans[ai];
161  if (src[ai]+2 < src[i])
162  src[i] = src[ai]+2;
163 
164  // (-1,1)
165  if (rcGetCon(as, 0) != RC_NOT_CONNECTED)
166  {
167  const int aax = ax + rcGetDirOffsetX(0);
168  const int aay = ay + rcGetDirOffsetY(0);
169  const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 0);
170  if (src[aai]+3 < src[i])
171  src[i] = src[aai]+3;
172  }
173  }
174  }
175  }
176  }
177 
178  maxDist = 0;
179  for (int i = 0; i < chf.spanCount; ++i)
180  maxDist = rcMax(src[i], maxDist);
181 
182 }
int height
The height of the heightfield. (Along the z-axis in cell units.)
Definition: Recast.h:308
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
unsigned char * areas
Array containing area id data. [Size: spanCount].
Definition: Recast.h:322
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
int spanCount
The number of spans in the heightfield.
Definition: Recast.h:309
T rcMax(T a, T b)
Definition: Recast.h:572
G3D::int16 x
Definition: Vector2int16.h:37

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool canMergeWithRegion ( const rcRegion rega,
const rcRegion regb 
)
static
578 {
579  if (rega.areaType != regb.areaType)
580  return false;
581  int n = 0;
582  for (int i = 0; i < rega.connections.size(); ++i)
583  {
584  if (rega.connections[i] == regb.id)
585  n++;
586  }
587  if (n > 1)
588  return false;
589  for (int i = 0; i < rega.floors.size(); ++i)
590  {
591  if (rega.floors[i] == regb.id)
592  return false;
593  }
594  return true;
595 }
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
rcIntArray connections
Definition: RecastRegion.cpp:535
unsigned char areaType
Definition: RecastRegion.cpp:529
rcIntArray floors
Definition: RecastRegion.cpp:536
unsigned short id
Definition: RecastRegion.cpp:528

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static unsigned short* expandRegions ( int  maxIter,
unsigned short  level,
rcCompactHeightfield chf,
unsigned short *  srcReg,
unsigned short *  srcDist,
unsigned short *  dstReg,
unsigned short *  dstDist,
rcIntArray stack,
bool  fillStack 
)
static
352 {
353  const int w = chf.width;
354  const int h = chf.height;
355 
356  if (fillStack)
357  {
358  // Find cells revealed by the raised level.
359  stack.resize(0);
360  for (int y = 0; y < h; ++y)
361  {
362  for (int x = 0; x < w; ++x)
363  {
364  const rcCompactCell& c = chf.cells[x+y*w];
365  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
366  {
367  if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
368  {
369  stack.push(x);
370  stack.push(y);
371  stack.push(i);
372  }
373  }
374  }
375  }
376  }
377  else // use cells in the input stack
378  {
379  // mark all cells which already have a region
380  for (int j=0; j<stack.size(); j+=3)
381  {
382  int i = stack[j+2];
383  if (srcReg[i] != 0)
384  stack[j+2] = -1;
385  }
386  }
387 
388  int iter = 0;
389  while (stack.size() > 0)
390  {
391  int failed = 0;
392 
393  memcpy(dstReg, srcReg, sizeof(unsigned short)*chf.spanCount);
394  memcpy(dstDist, srcDist, sizeof(unsigned short)*chf.spanCount);
395 
396  for (int j = 0; j < stack.size(); j += 3)
397  {
398  int x = stack[j+0];
399  int y = stack[j+1];
400  int i = stack[j+2];
401  if (i < 0)
402  {
403  failed++;
404  continue;
405  }
406 
407  unsigned short r = srcReg[i];
408  unsigned short d2 = 0xffff;
409  const unsigned char area = chf.areas[i];
410  const rcCompactSpan& s = chf.spans[i];
411  for (int dir = 0; dir < 4; ++dir)
412  {
413  if (rcGetCon(s, dir) == RC_NOT_CONNECTED) continue;
414  const int ax = x + rcGetDirOffsetX(dir);
415  const int ay = y + rcGetDirOffsetY(dir);
416  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
417  if (chf.areas[ai] != area) continue;
418  if (srcReg[ai] > 0 && (srcReg[ai] & RC_BORDER_REG) == 0)
419  {
420  if ((int)srcDist[ai]+2 < (int)d2)
421  {
422  r = srcReg[ai];
423  d2 = srcDist[ai]+2;
424  }
425  }
426  }
427  if (r)
428  {
429  stack[j+2] = -1; // mark as used
430  dstReg[i] = r;
431  dstDist[i] = d2;
432  }
433  else
434  {
435  failed++;
436  }
437  }
438 
439  // rcSwap source and dest.
440  rcSwap(srcReg, dstReg);
441  rcSwap(srcDist, dstDist);
442 
443  if (failed*3 == stack.size())
444  break;
445 
446  if (level > 0)
447  {
448  ++iter;
449  if (iter >= maxIter)
450  break;
451  }
452  }
453 
454  return srcReg;
455 }
int height
The height of the heightfield. (Along the z-axis in cell units.)
Definition: Recast.h:308
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
unsigned short * dist
Array containing border distance data. [Size: spanCount].
Definition: Recast.h:321
void rcSwap(T &a, T &b)
Definition: Recast.h:560
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
unsigned char * areas
Array containing area id data. [Size: spanCount].
Definition: Recast.h:322
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
int spanCount
The number of spans in the heightfield.
Definition: Recast.h:309
static const unsigned char RC_NULL_AREA
Definition: Recast.h:538
G3D::int16 x
Definition: Vector2int16.h:37
static const unsigned short RC_BORDER_REG
Definition: Recast.h:498
void resize(int n)
Definition: RecastAlloc.cpp:75
void push(int item)
Definition: RecastAlloc.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool floodRegion ( int  x,
int  y,
int  i,
unsigned short  level,
unsigned short  r,
rcCompactHeightfield chf,
unsigned short *  srcReg,
unsigned short *  srcDist,
rcIntArray stack 
)
static
249 {
250  const int w = chf.width;
251 
252  const unsigned char area = chf.areas[i];
253 
254  // Flood fill mark region.
255  stack.resize(0);
256  stack.push((int)x);
257  stack.push((int)y);
258  stack.push((int)i);
259  srcReg[i] = r;
260  srcDist[i] = 0;
261 
262  unsigned short lev = level >= 2 ? level-2 : 0;
263  int count = 0;
264 
265  while (stack.size() > 0)
266  {
267  int ci = stack.pop();
268  int cy = stack.pop();
269  int cx = stack.pop();
270 
271  const rcCompactSpan& cs = chf.spans[ci];
272 
273  // Check if any of the neighbours already have a valid region set.
274  unsigned short ar = 0;
275  for (int dir = 0; dir < 4; ++dir)
276  {
277  // 8 connected
278  if (rcGetCon(cs, dir) != RC_NOT_CONNECTED)
279  {
280  const int ax = cx + rcGetDirOffsetX(dir);
281  const int ay = cy + rcGetDirOffsetY(dir);
282  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir);
283  if (chf.areas[ai] != area)
284  continue;
285  unsigned short nr = srcReg[ai];
286  if (nr & RC_BORDER_REG) // Do not take borders into account.
287  continue;
288  if (nr != 0 && nr != r)
289  {
290  ar = nr;
291  break;
292  }
293 
294  const rcCompactSpan& as = chf.spans[ai];
295 
296  const int dir2 = (dir+1) & 0x3;
297  if (rcGetCon(as, dir2) != RC_NOT_CONNECTED)
298  {
299  const int ax2 = ax + rcGetDirOffsetX(dir2);
300  const int ay2 = ay + rcGetDirOffsetY(dir2);
301  const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2);
302  if (chf.areas[ai2] != area)
303  continue;
304  unsigned short nr2 = srcReg[ai2];
305  if (nr2 != 0 && nr2 != r)
306  {
307  ar = nr2;
308  break;
309  }
310  }
311  }
312  }
313  if (ar != 0)
314  {
315  srcReg[ci] = 0;
316  continue;
317  }
318 
319  count++;
320 
321  // Expand neighbours.
322  for (int dir = 0; dir < 4; ++dir)
323  {
324  if (rcGetCon(cs, dir) != RC_NOT_CONNECTED)
325  {
326  const int ax = cx + rcGetDirOffsetX(dir);
327  const int ay = cy + rcGetDirOffsetY(dir);
328  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir);
329  if (chf.areas[ai] != area)
330  continue;
331  if (chf.dist[ai] >= lev && srcReg[ai] == 0)
332  {
333  srcReg[ai] = r;
334  srcDist[ai] = 0;
335  stack.push(ax);
336  stack.push(ay);
337  stack.push(ai);
338  }
339  }
340  }
341  }
342 
343  return count > 0;
344 }
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
unsigned short * dist
Array containing border distance data. [Size: spanCount].
Definition: Recast.h:321
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
unsigned char * areas
Array containing area id data. [Size: spanCount].
Definition: Recast.h:322
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
int pop()
Definition: RecastAlloc.h:87
G3D::int16 x
Definition: Vector2int16.h:37
static const unsigned short RC_BORDER_REG
Definition: Recast.h:498
void resize(int n)
Definition: RecastAlloc.cpp:75
void push(int item)
Definition: RecastAlloc.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool isRegionConnectedToBorder ( const rcRegion reg)
static
663 {
664  // Region is connected to border if
665  // one of the neighbours is null id.
666  for (int i = 0; i < reg.connections.size(); ++i)
667  {
668  if (reg.connections[i] == 0)
669  return true;
670  }
671  return false;
672 }
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
rcIntArray connections
Definition: RecastRegion.cpp:535

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool isSolidEdge ( rcCompactHeightfield chf,
unsigned short *  srcReg,
int  x,
int  y,
int  i,
int  dir 
)
static
676 {
677  const rcCompactSpan& s = chf.spans[i];
678  unsigned short r = 0;
679  if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
680  {
681  const int ax = x + rcGetDirOffsetX(dir);
682  const int ay = y + rcGetDirOffsetY(dir);
683  const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
684  r = srcReg[ai];
685  }
686  if (r == srcReg[i])
687  return false;
688  return true;
689 }
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
G3D::int16 x
Definition: Vector2int16.h:37

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool mergeAndFilterLayerRegions ( rcContext ctx,
int  minRegionArea,
unsigned short &  maxRegionId,
rcCompactHeightfield chf,
unsigned short *  srcReg,
rcIntArray  
)
static
1045 {
1046  const int w = chf.width;
1047  const int h = chf.height;
1048 
1049  const int nreg = maxRegionId+1;
1050  rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP);
1051  if (!regions)
1052  {
1053  ctx->log(RC_LOG_ERROR, "mergeAndFilterLayerRegions: Out of memory 'regions' (%d).", nreg);
1054  return false;
1055  }
1056 
1057  // Construct regions
1058  for (int i = 0; i < nreg; ++i)
1059  new(&regions[i]) rcRegion((unsigned short)i);
1060 
1061  // Find region neighbours and overlapping regions.
1062  rcIntArray lregs(32);
1063  for (int y = 0; y < h; ++y)
1064  {
1065  for (int x = 0; x < w; ++x)
1066  {
1067  const rcCompactCell& c = chf.cells[x+y*w];
1068 
1069  lregs.resize(0);
1070 
1071  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1072  {
1073  const rcCompactSpan& s = chf.spans[i];
1074  const unsigned short ri = srcReg[i];
1075  if (ri == 0 || ri >= nreg) continue;
1076  rcRegion& reg = regions[ri];
1077 
1078  reg.spanCount++;
1079 
1080  reg.ymin = rcMin(reg.ymin, s.y);
1081  reg.ymax = rcMax(reg.ymax, s.y);
1082 
1083  // Collect all region layers.
1084  lregs.push(ri);
1085 
1086  // Update neighbours
1087  for (int dir = 0; dir < 4; ++dir)
1088  {
1089  if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
1090  {
1091  const int ax = x + rcGetDirOffsetX(dir);
1092  const int ay = y + rcGetDirOffsetY(dir);
1093  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
1094  const unsigned short rai = srcReg[ai];
1095  if (rai > 0 && rai < nreg && rai != ri)
1096  addUniqueConnection(reg, rai);
1097  if (rai & RC_BORDER_REG)
1098  reg.connectsToBorder = true;
1099  }
1100  }
1101 
1102  }
1103 
1104  // Update overlapping regions.
1105  for (int i = 0; i < lregs.size()-1; ++i)
1106  {
1107  for (int j = i+1; j < lregs.size(); ++j)
1108  {
1109  if (lregs[i] != lregs[j])
1110  {
1111  rcRegion& ri = regions[lregs[i]];
1112  rcRegion& rj = regions[lregs[j]];
1113  addUniqueFloorRegion(ri, lregs[j]);
1114  addUniqueFloorRegion(rj, lregs[i]);
1115  }
1116  }
1117  }
1118 
1119  }
1120  }
1121 
1122  // Create 2D layers from regions.
1123  unsigned short layerId = 1;
1124 
1125  for (int i = 0; i < nreg; ++i)
1126  regions[i].id = 0;
1127 
1128  // Merge montone regions to create non-overlapping areas.
1129  rcIntArray stack(32);
1130  for (int i = 1; i < nreg; ++i)
1131  {
1132  rcRegion& root = regions[i];
1133  // Skip already visited.
1134  if (root.id != 0)
1135  continue;
1136 
1137  // Start search.
1138  root.id = layerId;
1139 
1140  stack.resize(0);
1141  stack.push(i);
1142 
1143  while (stack.size() > 0)
1144  {
1145  // Pop front
1146  rcRegion& reg = regions[stack[0]];
1147  for (int j = 0; j < stack.size()-1; ++j)
1148  stack[j] = stack[j+1];
1149  stack.resize(stack.size()-1);
1150 
1151  const int ncons = (int)reg.connections.size();
1152  for (int j = 0; j < ncons; ++j)
1153  {
1154  const int nei = reg.connections[j];
1155  rcRegion& regn = regions[nei];
1156  // Skip already visited.
1157  if (regn.id != 0)
1158  continue;
1159  // Skip if the neighbour is overlapping root region.
1160  bool overlap = false;
1161  for (int k = 0; k < root.floors.size(); k++)
1162  {
1163  if (root.floors[k] == nei)
1164  {
1165  overlap = true;
1166  break;
1167  }
1168  }
1169  if (overlap)
1170  continue;
1171 
1172  // Deepen
1173  stack.push(nei);
1174 
1175  // Mark layer id
1176  regn.id = layerId;
1177  // Merge current layers to root.
1178  for (int k = 0; k < regn.floors.size(); ++k)
1179  addUniqueFloorRegion(root, regn.floors[k]);
1180  root.ymin = rcMin(root.ymin, regn.ymin);
1181  root.ymax = rcMax(root.ymax, regn.ymax);
1182  root.spanCount += regn.spanCount;
1183  regn.spanCount = 0;
1185  }
1186  }
1187 
1188  layerId++;
1189  }
1190 
1191  // Remove small regions
1192  for (int i = 0; i < nreg; ++i)
1193  {
1194  if (regions[i].spanCount > 0 && regions[i].spanCount < minRegionArea && !regions[i].connectsToBorder)
1195  {
1196  unsigned short reg = regions[i].id;
1197  for (int j = 0; j < nreg; ++j)
1198  if (regions[j].id == reg)
1199  regions[j].id = 0;
1200  }
1201  }
1202 
1203  // Compress region Ids.
1204  for (int i = 0; i < nreg; ++i)
1205  {
1206  regions[i].remap = false;
1207  if (regions[i].id == 0) continue; // Skip nil regions.
1208  if (regions[i].id & RC_BORDER_REG) continue; // Skip external regions.
1209  regions[i].remap = true;
1210  }
1211 
1212  unsigned short regIdGen = 0;
1213  for (int i = 0; i < nreg; ++i)
1214  {
1215  if (!regions[i].remap)
1216  continue;
1217  unsigned short oldId = regions[i].id;
1218  unsigned short newId = ++regIdGen;
1219  for (int j = i; j < nreg; ++j)
1220  {
1221  if (regions[j].id == oldId)
1222  {
1223  regions[j].id = newId;
1224  regions[j].remap = false;
1225  }
1226  }
1227  }
1228  maxRegionId = regIdGen;
1229 
1230  // Remap regions.
1231  for (int i = 0; i < chf.spanCount; ++i)
1232  {
1233  if ((srcReg[i] & RC_BORDER_REG) == 0)
1234  srcReg[i] = regions[srcReg[i]].id;
1235  }
1236 
1237  for (int i = 0; i < nreg; ++i)
1238  regions[i].~rcRegion();
1239  rcFree(regions);
1240 
1241  return true;
1242 }
int height
The height of the heightfield. (Along the z-axis in cell units.)
Definition: Recast.h:308
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
unsigned short y
The lower extent of the span. (Measured from the heightfield's base.)
Definition: Recast.h:297
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
T rcMin(T a, T b)
Definition: Recast.h:566
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
bool remap
Definition: RecastRegion.cpp:530
unsigned short ymax
Definition: RecastRegion.cpp:534
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
bool connectsToBorder
Definition: RecastRegion.cpp:533
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
An error log entry.
Definition: Recast.h:31
void rcFree(void *ptr)
Definition: RecastAlloc.cpp:55
unsigned short ymin
Definition: RecastRegion.cpp:534
rcIntArray connections
Definition: RecastRegion.cpp:535
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
int spanCount
Definition: RecastRegion.cpp:527
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
rcIntArray floors
Definition: RecastRegion.cpp:536
static void addUniqueConnection(rcRegion &reg, int n)
Definition: RecastRegion.cpp:1033
int spanCount
The number of spans in the heightfield.
Definition: Recast.h:309
static void addUniqueFloorRegion(rcRegion &reg, int n)
Definition: RecastRegion.cpp:597
unsigned short id
Definition: RecastRegion.cpp:528
Memory used temporarily within a function.
Definition: RecastAlloc.h:27
T rcMax(T a, T b)
Definition: Recast.h:572
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
G3D::int16 x
Definition: Vector2int16.h:37
Definition: RecastRegion.cpp:513
static const unsigned short RC_BORDER_REG
Definition: Recast.h:498
A simple dynamic array of integers.
Definition: RecastAlloc.h:61

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool mergeAndFilterRegions ( rcContext ctx,
int  minRegionArea,
int  mergeRegionSize,
unsigned short &  maxRegionId,
rcCompactHeightfield chf,
unsigned short *  srcReg,
rcIntArray overlaps 
)
static
784 {
785  const int w = chf.width;
786  const int h = chf.height;
787 
788  const int nreg = maxRegionId+1;
789  rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP);
790  if (!regions)
791  {
792  ctx->log(RC_LOG_ERROR, "mergeAndFilterRegions: Out of memory 'regions' (%d).", nreg);
793  return false;
794  }
795 
796  // Construct regions
797  for (int i = 0; i < nreg; ++i)
798  new(&regions[i]) rcRegion((unsigned short)i);
799 
800  // Find edge of a region and find connections around the contour.
801  for (int y = 0; y < h; ++y)
802  {
803  for (int x = 0; x < w; ++x)
804  {
805  const rcCompactCell& c = chf.cells[x+y*w];
806  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
807  {
808  unsigned short r = srcReg[i];
809  if (r == 0 || r >= nreg)
810  continue;
811 
812  rcRegion& reg = regions[r];
813  reg.spanCount++;
814 
815  // Update floors.
816  for (int j = (int)c.index; j < ni; ++j)
817  {
818  if (i == j) continue;
819  unsigned short floorId = srcReg[j];
820  if (floorId == 0 || floorId >= nreg)
821  continue;
822  if (floorId == r)
823  reg.overlap = true;
824  addUniqueFloorRegion(reg, floorId);
825  }
826 
827  // Have found contour
828  if (reg.connections.size() > 0)
829  continue;
830 
831  reg.areaType = chf.areas[i];
832 
833  // Check if this cell is next to a border.
834  int ndir = -1;
835  for (int dir = 0; dir < 4; ++dir)
836  {
837  if (isSolidEdge(chf, srcReg, x, y, i, dir))
838  {
839  ndir = dir;
840  break;
841  }
842  }
843 
844  if (ndir != -1)
845  {
846  // The cell is at border.
847  // Walk around the contour to find all the neighbours.
848  walkContour(x, y, i, ndir, chf, srcReg, reg.connections);
849  }
850  }
851  }
852  }
853 
854  // Remove too small regions.
855  rcIntArray stack(32);
856  rcIntArray trace(32);
857  for (int i = 0; i < nreg; ++i)
858  {
859  rcRegion& reg = regions[i];
860  if (reg.id == 0 || (reg.id & RC_BORDER_REG))
861  continue;
862  if (reg.spanCount == 0)
863  continue;
864  if (reg.visited)
865  continue;
866 
867  // Count the total size of all the connected regions.
868  // Also keep track of the regions connects to a tile border.
869  bool connectsToBorder = false;
870  int spanCount = 0;
871  stack.resize(0);
872  trace.resize(0);
873 
874  reg.visited = true;
875  stack.push(i);
876 
877  while (stack.size())
878  {
879  // Pop
880  int ri = stack.pop();
881 
882  rcRegion& creg = regions[ri];
883 
884  spanCount += creg.spanCount;
885  trace.push(ri);
886 
887  for (int j = 0; j < creg.connections.size(); ++j)
888  {
889  if (creg.connections[j] & RC_BORDER_REG)
890  {
891  connectsToBorder = true;
892  continue;
893  }
894  rcRegion& neireg = regions[creg.connections[j]];
895  if (neireg.visited)
896  continue;
897  if (neireg.id == 0 || (neireg.id & RC_BORDER_REG))
898  continue;
899  // Visit
900  stack.push(neireg.id);
901  neireg.visited = true;
902  }
903  }
904 
905  // If the accumulated regions size is too small, remove it.
906  // Do not remove areas which connect to tile borders
907  // as their size cannot be estimated correctly and removing them
908  // can potentially remove necessary areas.
909  if (spanCount < minRegionArea && !connectsToBorder)
910  {
911  // Kill all visited regions.
912  for (int j = 0; j < trace.size(); ++j)
913  {
914  regions[trace[j]].spanCount = 0;
915  regions[trace[j]].id = 0;
916  }
917  }
918  }
919 
920  // Merge too small regions to neighbour regions.
921  int mergeCount = 0 ;
922  do
923  {
924  mergeCount = 0;
925  for (int i = 0; i < nreg; ++i)
926  {
927  rcRegion& reg = regions[i];
928  if (reg.id == 0 || (reg.id & RC_BORDER_REG))
929  continue;
930  if (reg.overlap)
931  continue;
932  if (reg.spanCount == 0)
933  continue;
934 
935  // Check to see if the region should be merged.
936  if (reg.spanCount > mergeRegionSize && isRegionConnectedToBorder(reg))
937  continue;
938 
939  // Small region with more than 1 connection.
940  // Or region which is not connected to a border at all.
941  // Find smallest neighbour region that connects to this one.
942  int smallest = 0xfffffff;
943  unsigned short mergeId = reg.id;
944  for (int j = 0; j < reg.connections.size(); ++j)
945  {
946  if (reg.connections[j] & RC_BORDER_REG) continue;
947  rcRegion& mreg = regions[reg.connections[j]];
948  if (mreg.id == 0 || (mreg.id & RC_BORDER_REG) || mreg.overlap) continue;
949  if (mreg.spanCount < smallest &&
950  canMergeWithRegion(reg, mreg) &&
951  canMergeWithRegion(mreg, reg))
952  {
953  smallest = mreg.spanCount;
954  mergeId = mreg.id;
955  }
956  }
957  // Found new id.
958  if (mergeId != reg.id)
959  {
960  unsigned short oldId = reg.id;
961  rcRegion& target = regions[mergeId];
962 
963  // Merge neighbours.
964  if (mergeRegions(target, reg))
965  {
966  // Fixup regions pointing to current region.
967  for (int j = 0; j < nreg; ++j)
968  {
969  if (regions[j].id == 0 || (regions[j].id & RC_BORDER_REG)) continue;
970  // If another region was already merged into current region
971  // change the nid of the previous region too.
972  if (regions[j].id == oldId)
973  regions[j].id = mergeId;
974  // Replace the current region with the new one if the
975  // current regions is neighbour.
976  replaceNeighbour(regions[j], oldId, mergeId);
977  }
978  mergeCount++;
979  }
980  }
981  }
982  }
983  while (mergeCount > 0);
984 
985  // Compress region Ids.
986  for (int i = 0; i < nreg; ++i)
987  {
988  regions[i].remap = false;
989  if (regions[i].id == 0) continue; // Skip nil regions.
990  if (regions[i].id & RC_BORDER_REG) continue; // Skip external regions.
991  regions[i].remap = true;
992  }
993 
994  unsigned short regIdGen = 0;
995  for (int i = 0; i < nreg; ++i)
996  {
997  if (!regions[i].remap)
998  continue;
999  unsigned short oldId = regions[i].id;
1000  unsigned short newId = ++regIdGen;
1001  for (int j = i; j < nreg; ++j)
1002  {
1003  if (regions[j].id == oldId)
1004  {
1005  regions[j].id = newId;
1006  regions[j].remap = false;
1007  }
1008  }
1009  }
1010  maxRegionId = regIdGen;
1011 
1012  // Remap regions.
1013  for (int i = 0; i < chf.spanCount; ++i)
1014  {
1015  if ((srcReg[i] & RC_BORDER_REG) == 0)
1016  srcReg[i] = regions[srcReg[i]].id;
1017  }
1018 
1019  // Return regions that we found to be overlapping.
1020  for (int i = 0; i < nreg; ++i)
1021  if (regions[i].overlap)
1022  overlaps.push(regions[i].id);
1023 
1024  for (int i = 0; i < nreg; ++i)
1025  regions[i].~rcRegion();
1026  rcFree(regions);
1027 
1028 
1029  return true;
1030 }
int height
The height of the heightfield. (Along the z-axis in cell units.)
Definition: Recast.h:308
static bool isRegionConnectedToBorder(const rcRegion &reg)
Definition: RecastRegion.cpp:662
static bool canMergeWithRegion(const rcRegion &rega, const rcRegion &regb)
Definition: RecastRegion.cpp:577
static bool isSolidEdge(rcCompactHeightfield &chf, unsigned short *srcReg, int x, int y, int i, int dir)
Definition: RecastRegion.cpp:674
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
bool remap
Definition: RecastRegion.cpp:530
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
static void replaceNeighbour(rcRegion &reg, unsigned short oldId, unsigned short newId)
Definition: RecastRegion.cpp:557
An error log entry.
Definition: Recast.h:31
void rcFree(void *ptr)
Definition: RecastAlloc.cpp:55
rcIntArray connections
Definition: RecastRegion.cpp:535
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
unsigned char areaType
Definition: RecastRegion.cpp:529
int spanCount
Definition: RecastRegion.cpp:527
unsigned char * areas
Array containing area id data. [Size: spanCount].
Definition: Recast.h:322
bool overlap
Definition: RecastRegion.cpp:532
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
bool visited
Definition: RecastRegion.cpp:531
int spanCount
The number of spans in the heightfield.
Definition: Recast.h:309
static void walkContour(int x, int y, int i, int dir, rcCompactHeightfield &chf, unsigned short *srcReg, rcIntArray &cont)
Definition: RecastRegion.cpp:691
static bool mergeRegions(rcRegion &rega, rcRegion &regb)
Definition: RecastRegion.cpp:605
static void addUniqueFloorRegion(rcRegion &reg, int n)
Definition: RecastRegion.cpp:597
unsigned short id
Definition: RecastRegion.cpp:528
Memory used temporarily within a function.
Definition: RecastAlloc.h:27
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
G3D::int16 x
Definition: Vector2int16.h:37
Definition: RecastRegion.cpp:513
static const unsigned short RC_BORDER_REG
Definition: Recast.h:498
void push(int item)
Definition: RecastAlloc.h:83
A simple dynamic array of integers.
Definition: RecastAlloc.h:61

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool mergeRegions ( rcRegion rega,
rcRegion regb 
)
static
606 {
607  unsigned short aid = rega.id;
608  unsigned short bid = regb.id;
609 
610  // Duplicate current neighbourhood.
611  rcIntArray acon;
612  acon.resize(rega.connections.size());
613  for (int i = 0; i < rega.connections.size(); ++i)
614  acon[i] = rega.connections[i];
615  rcIntArray& bcon = regb.connections;
616 
617  // Find insertion point on A.
618  int insa = -1;
619  for (int i = 0; i < acon.size(); ++i)
620  {
621  if (acon[i] == bid)
622  {
623  insa = i;
624  break;
625  }
626  }
627  if (insa == -1)
628  return false;
629 
630  // Find insertion point on B.
631  int insb = -1;
632  for (int i = 0; i < bcon.size(); ++i)
633  {
634  if (bcon[i] == aid)
635  {
636  insb = i;
637  break;
638  }
639  }
640  if (insb == -1)
641  return false;
642 
643  // Merge neighbours.
644  rega.connections.resize(0);
645  for (int i = 0, ni = acon.size(); i < ni-1; ++i)
646  rega.connections.push(acon[(insa+1+i) % ni]);
647 
648  for (int i = 0, ni = bcon.size(); i < ni-1; ++i)
649  rega.connections.push(bcon[(insb+1+i) % ni]);
650 
652 
653  for (int j = 0; j < regb.floors.size(); ++j)
654  addUniqueFloorRegion(rega, regb.floors[j]);
655  rega.spanCount += regb.spanCount;
656  regb.spanCount = 0;
657  regb.connections.resize(0);
658 
659  return true;
660 }
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
rcIntArray connections
Definition: RecastRegion.cpp:535
int spanCount
Definition: RecastRegion.cpp:527
rcIntArray floors
Definition: RecastRegion.cpp:536
static void addUniqueFloorRegion(rcRegion &reg, int n)
Definition: RecastRegion.cpp:597
unsigned short id
Definition: RecastRegion.cpp:528
static void removeAdjacentNeighbours(rcRegion &reg)
Definition: RecastRegion.cpp:539
void resize(int n)
Definition: RecastAlloc.cpp:75
void push(int item)
Definition: RecastAlloc.h:83
A simple dynamic array of integers.
Definition: RecastAlloc.h:61

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void paintRectRegion ( int  minx,
int  maxx,
int  miny,
int  maxy,
unsigned short  regId,
rcCompactHeightfield chf,
unsigned short *  srcReg 
)
static
1311 {
1312  const int w = chf.width;
1313  for (int y = miny; y < maxy; ++y)
1314  {
1315  for (int x = minx; x < maxx; ++x)
1316  {
1317  const rcCompactCell& c = chf.cells[x+y*w];
1318  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1319  {
1320  if (chf.areas[i] != RC_NULL_AREA)
1321  srcReg[i] = regId;
1322  }
1323  }
1324  }
1325 }
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
unsigned char * areas
Array containing area id data. [Size: spanCount].
Definition: Recast.h:322
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
static const unsigned char RC_NULL_AREA
Definition: Recast.h:538
G3D::int16 x
Definition: Vector2int16.h:37

+ Here is the caller graph for this function:

bool rcBuildDistanceField ( rcContext ctx,
rcCompactHeightfield chf 
)

This is usually the second to the last step in creating a fully built compact heightfield. This step is required before regions are built using rcBuildRegions or rcBuildRegionsMonotone.

After this step, the distance data is available via the rcCompactHeightfield::maxDistance and rcCompactHeightfield::dist fields.

See also
rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone
1257 {
1258  rcAssert(ctx);
1259 
1261 
1262  if (chf.dist)
1263  {
1264  rcFree(chf.dist);
1265  chf.dist = 0;
1266  }
1267 
1268  unsigned short* src = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
1269  if (!src)
1270  {
1271  ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'src' (%d).", chf.spanCount);
1272  return false;
1273  }
1274  unsigned short* dst = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
1275  if (!dst)
1276  {
1277  ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dst' (%d).", chf.spanCount);
1278  rcFree(src);
1279  return false;
1280  }
1281 
1282  unsigned short maxDist = 0;
1283 
1285 
1286  calculateDistanceField(chf, src, maxDist);
1287  chf.maxDistance = maxDist;
1288 
1290 
1292 
1293  // Blur
1294  if (boxBlur(chf, 1, src, dst) != src)
1295  rcSwap(src, dst);
1296 
1297  // Store distance.
1298  chf.dist = src;
1299 
1301 
1303 
1304  rcFree(dst);
1305 
1306  return true;
1307 }
#define rcAssert
Definition: RecastAssert.h:30
The time to build the distances of the distance field. (See: rcBuildDistanceField) ...
Definition: Recast.h:75
unsigned short * dist
Array containing border distance data. [Size: spanCount].
Definition: Recast.h:321
void rcSwap(T &a, T &b)
Definition: Recast.h:560
An error log entry.
Definition: Recast.h:31
The time to blur the distance field. (See: rcBuildDistanceField)
Definition: Recast.h:77
void rcFree(void *ptr)
Definition: RecastAlloc.cpp:55
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
The total time to build the distance field. (See: rcBuildDistanceField)
Definition: Recast.h:73
static void calculateDistanceField(rcCompactHeightfield &chf, unsigned short *src, unsigned short &maxDist)
Definition: RecastRegion.cpp:31
void startTimer(const rcTimerLabel label)
Definition: Recast.h:131
int spanCount
The number of spans in the heightfield.
Definition: Recast.h:309
unsigned short maxDistance
The maximum distance value of any span within the field.
Definition: Recast.h:313
Memory used temporarily within a function.
Definition: RecastAlloc.h:27
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
void stopTimer(const rcTimerLabel label)
Definition: Recast.h:135
static unsigned short * boxBlur(rcCompactHeightfield &chf, int thr, unsigned short *src, unsigned short *dst)
Definition: RecastRegion.cpp:184

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool rcBuildLayerRegions ( rcContext ctx,
rcCompactHeightfield chf,
const int  borderSize,
const int  minRegionArea 
)

Builds region data for the heightfield by partitioning the heightfield in non-overlapping layers.

Parameters
[in,out]ctxThe build context to use during the operation.
[in,out]chfA populated compact heightfield.
[in]borderSizeThe size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx]
[in]minRegionAreaThe minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx].
Returns
True if the operation completed successfully.
1672 {
1673  rcAssert(ctx);
1674 
1676 
1677  const int w = chf.width;
1678  const int h = chf.height;
1679  unsigned short id = 1;
1680 
1681  rcScopedDelete<unsigned short> srcReg = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
1682  if (!srcReg)
1683  {
1684  ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
1685  return false;
1686  }
1687  memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
1688 
1689  const int nsweeps = rcMax(chf.width,chf.height);
1691  if (!sweeps)
1692  {
1693  ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
1694  return false;
1695  }
1696 
1697 
1698  // Mark border regions.
1699  if (borderSize > 0)
1700  {
1701  // Make sure border will not overflow.
1702  const int bw = rcMin(w, borderSize);
1703  const int bh = rcMin(h, borderSize);
1704  // Paint regions
1705  paintRectRegion(0, bw, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
1706  paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
1707  paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++;
1708  paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++;
1709 
1710  chf.borderSize = borderSize;
1711  }
1712 
1713  rcIntArray prev(256);
1714 
1715  // Sweep one line at a time.
1716  for (int y = borderSize; y < h-borderSize; ++y)
1717  {
1718  // Collect spans from this row.
1719  prev.resize(id+1);
1720  memset(&prev[0],0,sizeof(int)*id);
1721  unsigned short rid = 1;
1722 
1723  for (int x = borderSize; x < w-borderSize; ++x)
1724  {
1725  const rcCompactCell& c = chf.cells[x+y*w];
1726 
1727  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1728  {
1729  const rcCompactSpan& s = chf.spans[i];
1730  if (chf.areas[i] == RC_NULL_AREA) continue;
1731 
1732  // -x
1733  unsigned short previd = 0;
1734  if (rcGetCon(s, 0) != RC_NOT_CONNECTED)
1735  {
1736  const int ax = x + rcGetDirOffsetX(0);
1737  const int ay = y + rcGetDirOffsetY(0);
1738  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
1739  if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
1740  previd = srcReg[ai];
1741  }
1742 
1743  if (!previd)
1744  {
1745  previd = rid++;
1746  sweeps[previd].rid = previd;
1747  sweeps[previd].ns = 0;
1748  sweeps[previd].nei = 0;
1749  }
1750 
1751  // -y
1752  if (rcGetCon(s,3) != RC_NOT_CONNECTED)
1753  {
1754  const int ax = x + rcGetDirOffsetX(3);
1755  const int ay = y + rcGetDirOffsetY(3);
1756  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
1757  if (srcReg[ai] && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
1758  {
1759  unsigned short nr = srcReg[ai];
1760  if (!sweeps[previd].nei || sweeps[previd].nei == nr)
1761  {
1762  sweeps[previd].nei = nr;
1763  sweeps[previd].ns++;
1764  prev[nr]++;
1765  }
1766  else
1767  {
1768  sweeps[previd].nei = RC_NULL_NEI;
1769  }
1770  }
1771  }
1772 
1773  srcReg[i] = previd;
1774  }
1775  }
1776 
1777  // Create unique ID.
1778  for (int i = 1; i < rid; ++i)
1779  {
1780  if (sweeps[i].nei != RC_NULL_NEI && sweeps[i].nei != 0 &&
1781  prev[sweeps[i].nei] == (int)sweeps[i].ns)
1782  {
1783  sweeps[i].id = sweeps[i].nei;
1784  }
1785  else
1786  {
1787  sweeps[i].id = id++;
1788  }
1789  }
1790 
1791  // Remap IDs
1792  for (int x = borderSize; x < w-borderSize; ++x)
1793  {
1794  const rcCompactCell& c = chf.cells[x+y*w];
1795 
1796  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1797  {
1798  if (srcReg[i] > 0 && srcReg[i] < rid)
1799  srcReg[i] = sweeps[srcReg[i]].id;
1800  }
1801  }
1802  }
1803 
1804 
1806 
1807  // Merge monotone regions to layers and remove small regions.
1808  rcIntArray overlaps;
1809  chf.maxRegions = id;
1810  if (!mergeAndFilterLayerRegions(ctx, minRegionArea, chf.maxRegions, chf, srcReg, overlaps))
1811  return false;
1812 
1814 
1815 
1816  // Store the result out.
1817  for (int i = 0; i < chf.spanCount; ++i)
1818  chf.spans[i].reg = srcReg[i];
1819 
1821 
1822  return true;
1823 }
int height
The height of the heightfield. (Along the z-axis in cell units.)
Definition: Recast.h:308
#define rcAssert
Definition: RecastAssert.h:30
int borderSize
The AABB border size used during the build of the field. (See: rcConfig::borderSize) ...
Definition: Recast.h:312
unsigned short maxRegions
The maximum region id of any span within the field.
Definition: Recast.h:314
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
static const unsigned short RC_NULL_NEI
Definition: RecastRegion.cpp:1328
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
unsigned short reg
The id of the region the span belongs to. (Or zero if not in a region.)
Definition: Recast.h:298
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
T rcMin(T a, T b)
Definition: Recast.h:566
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
An error log entry.
Definition: Recast.h:31
Definition: RecastAlloc.h:105
static bool mergeAndFilterLayerRegions(rcContext *ctx, int minRegionArea, unsigned short &maxRegionId, rcCompactHeightfield &chf, unsigned short *srcReg, rcIntArray &)
Definition: RecastRegion.cpp:1041
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
unsigned char * areas
Array containing area id data. [Size: spanCount].
Definition: Recast.h:322
Definition: RecastRegion.cpp:1330
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
The total time to build the regions. (See: rcBuildRegions, rcBuildRegionsMonotone) ...
Definition: Recast.h:79
void startTimer(const rcTimerLabel label)
Definition: Recast.h:131
int spanCount
The number of spans in the heightfield.
Definition: Recast.h:309
static void paintRectRegion(int minx, int maxx, int miny, int maxy, unsigned short regId, rcCompactHeightfield &chf, unsigned short *srcReg)
Definition: RecastRegion.cpp:1309
int prev(int i, int n)
Definition: RecastContour.cpp:468
static const unsigned char RC_NULL_AREA
Definition: Recast.h:538
Memory used temporarily within a function.
Definition: RecastAlloc.h:27
T rcMax(T a, T b)
Definition: Recast.h:572
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
G3D::int16 x
Definition: Vector2int16.h:37
void stopTimer(const rcTimerLabel label)
Definition: Recast.h:135
static const unsigned short RC_BORDER_REG
Definition: Recast.h:498
A simple dynamic array of integers.
Definition: RecastAlloc.h:61
The time to filter out small regions. (See: rcBuildRegions, rcBuildRegionsMonotone) ...
Definition: Recast.h:87

+ Here is the call graph for this function:

bool rcBuildRegions ( rcContext ctx,
rcCompactHeightfield chf,
const int  borderSize,
const int  minRegionArea,
const int  mergeRegionArea 
)

Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour. Contours will form simple polygons.

If multiple regions form an area that is smaller than minRegionArea, then all spans will be re-assigned to the zero (null) region.

Watershed partitioning can result in smaller than necessary regions, especially in diagonal corridors. mergeRegionArea helps reduce unecessarily small regions.

See the rcConfig documentation for more information on the configuration parameters.

The region data will be available via the rcCompactHeightfield::maxRegions and rcCompactSpan::reg fields.

Warning
The distance field must be created using rcBuildDistanceField before attempting to build regions.
See also
rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
1534 {
1535  rcAssert(ctx);
1536 
1538 
1539  const int w = chf.width;
1540  const int h = chf.height;
1541 
1542  rcScopedDelete<unsigned short> buf = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount*4, RC_ALLOC_TEMP);
1543  if (!buf)
1544  {
1545  ctx->log(RC_LOG_ERROR, "rcBuildRegions: Out of memory 'tmp' (%d).", chf.spanCount*4);
1546  return false;
1547  }
1548 
1550 
1551  const int LOG_NB_STACKS = 3;
1552  const int NB_STACKS = 1 << LOG_NB_STACKS;
1553  rcIntArray lvlStacks[NB_STACKS];
1554  for (int i=0; i<NB_STACKS; ++i)
1555  lvlStacks[i].resize(1024);
1556 
1557  rcIntArray stack(1024);
1558  rcIntArray visited(1024);
1559 
1560  unsigned short* srcReg = buf;
1561  unsigned short* srcDist = buf+chf.spanCount;
1562  unsigned short* dstReg = buf+chf.spanCount*2;
1563  unsigned short* dstDist = buf+chf.spanCount*3;
1564 
1565  memset(srcReg, 0, sizeof(unsigned short)*chf.spanCount);
1566  memset(srcDist, 0, sizeof(unsigned short)*chf.spanCount);
1567 
1568  unsigned short regionId = 1;
1569  unsigned short level = (chf.maxDistance+1) & ~1;
1570 
1571  // TODO: Figure better formula, expandIters defines how much the
1572  // watershed "overflows" and simplifies the regions. Tying it to
1573  // agent radius was usually good indication how greedy it could be.
1574 // const int expandIters = 4 + walkableRadius * 2;
1575  const int expandIters = 8;
1576 
1577  if (borderSize > 0)
1578  {
1579  // Make sure border will not overflow.
1580  const int bw = rcMin(w, borderSize);
1581  const int bh = rcMin(h, borderSize);
1582  // Paint regions
1583  paintRectRegion(0, bw, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
1584  paintRectRegion(w-bw, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
1585  paintRectRegion(0, w, 0, bh, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
1586  paintRectRegion(0, w, h-bh, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
1587 
1588  chf.borderSize = borderSize;
1589  }
1590 
1591  int sId = -1;
1592  while (level > 0)
1593  {
1594  level = level >= 2 ? level-2 : 0;
1595  sId = (sId+1) & (NB_STACKS-1);
1596 
1597 // ctx->startTimer(RC_TIMER_DIVIDE_TO_LEVELS);
1598 
1599  if (sId == 0)
1600  sortCellsByLevel(level, chf, srcReg, NB_STACKS, lvlStacks, 1);
1601  else
1602  appendStacks(lvlStacks[sId-1], lvlStacks[sId], srcReg); // copy left overs from last level
1603 
1604 // ctx->stopTimer(RC_TIMER_DIVIDE_TO_LEVELS);
1605 
1607 
1608  // Expand current regions until no empty connected cells found.
1609  if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, lvlStacks[sId], false) != srcReg)
1610  {
1611  rcSwap(srcReg, dstReg);
1612  rcSwap(srcDist, dstDist);
1613  }
1614 
1616 
1618 
1619  // Mark new regions with IDs.
1620  for (int j=0; j<lvlStacks[sId].size(); j+=3)
1621  {
1622  int x = lvlStacks[sId][j];
1623  int y = lvlStacks[sId][j+1];
1624  int i = lvlStacks[sId][j+2];
1625  if (i >= 0 && srcReg[i] == 0)
1626  {
1627  if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
1628  regionId++;
1629  }
1630  }
1631 
1633  }
1634 
1635  // Expand current regions until no empty connected cells found.
1636  if (expandRegions(expandIters*8, 0, chf, srcReg, srcDist, dstReg, dstDist, stack, true) != srcReg)
1637  {
1638  rcSwap(srcReg, dstReg);
1639  rcSwap(srcDist, dstDist);
1640  }
1641 
1643 
1645 
1646  // Merge regions and filter out smalle regions.
1647  rcIntArray overlaps;
1648  chf.maxRegions = regionId;
1649  if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
1650  return false;
1651 
1652  // If overlapping regions were found during merging, split those regions.
1653  if (overlaps.size() > 0)
1654  {
1655  ctx->log(RC_LOG_ERROR, "rcBuildRegions: %d overlapping regions.", overlaps.size());
1656  }
1657 
1659 
1660  // Write the result out.
1661  for (int i = 0; i < chf.spanCount; ++i)
1662  chf.spans[i].reg = srcReg[i];
1663 
1665 
1666  return true;
1667 }
int height
The height of the heightfield. (Along the z-axis in cell units.)
Definition: Recast.h:308
#define rcAssert
Definition: RecastAssert.h:30
int borderSize
The AABB border size used during the build of the field. (See: rcConfig::borderSize) ...
Definition: Recast.h:312
unsigned short maxRegions
The maximum region id of any span within the field.
Definition: Recast.h:314
void rcSwap(T &a, T &b)
Definition: Recast.h:560
unsigned short reg
The id of the region the span belongs to. (Or zero if not in a region.)
Definition: Recast.h:298
static bool floodRegion(int x, int y, int i, unsigned short level, unsigned short r, rcCompactHeightfield &chf, unsigned short *srcReg, unsigned short *srcDist, rcIntArray &stack)
Definition: RecastRegion.cpp:244
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
T rcMin(T a, T b)
Definition: Recast.h:566
An error log entry.
Definition: Recast.h:31
Definition: RecastAlloc.h:105
static bool mergeAndFilterRegions(rcContext *ctx, int minRegionArea, int mergeRegionSize, unsigned short &maxRegionId, rcCompactHeightfield &chf, unsigned short *srcReg, rcIntArray &overlaps)
Definition: RecastRegion.cpp:780
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
The total time to apply the watershed algorithm. (See: rcBuildRegions)
Definition: Recast.h:81
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
The total time to build the regions. (See: rcBuildRegions, rcBuildRegionsMonotone) ...
Definition: Recast.h:79
void startTimer(const rcTimerLabel label)
Definition: Recast.h:131
static unsigned short * expandRegions(int maxIter, unsigned short level, rcCompactHeightfield &chf, unsigned short *srcReg, unsigned short *srcDist, unsigned short *dstReg, unsigned short *dstDist, rcIntArray &stack, bool fillStack)
Definition: RecastRegion.cpp:346
int spanCount
The number of spans in the heightfield.
Definition: Recast.h:309
static void paintRectRegion(int minx, int maxx, int miny, int maxy, unsigned short regId, rcCompactHeightfield &chf, unsigned short *srcReg)
Definition: RecastRegion.cpp:1309
The time to flood regions while applying the watershed algorithm. (See: rcBuildRegions) ...
Definition: Recast.h:85
The time to expand regions while applying the watershed algorithm. (See: rcBuildRegions) ...
Definition: Recast.h:83
static void sortCellsByLevel(unsigned short startLevel, rcCompactHeightfield &chf, unsigned short *srcReg, unsigned int nbStacks, rcIntArray *stacks, unsigned short loglevelsPerStack)
Definition: RecastRegion.cpp:459
unsigned short maxDistance
The maximum distance value of any span within the field.
Definition: Recast.h:313
Memory used temporarily within a function.
Definition: RecastAlloc.h:27
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
G3D::int16 x
Definition: Vector2int16.h:37
void stopTimer(const rcTimerLabel label)
Definition: Recast.h:135
static const unsigned short RC_BORDER_REG
Definition: Recast.h:498
A simple dynamic array of integers.
Definition: RecastAlloc.h:61
The time to filter out small regions. (See: rcBuildRegions, rcBuildRegionsMonotone) ...
Definition: Recast.h:87
static void appendStacks(rcIntArray &srcStack, rcIntArray &dstStack, unsigned short *srcReg)
Definition: RecastRegion.cpp:499

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool rcBuildRegionsMonotone ( rcContext ctx,
rcCompactHeightfield chf,
const int  borderSize,
const int  minRegionArea,
const int  mergeRegionArea 
)

Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour. Contours will form simple polygons.

If multiple regions form an area that is smaller than minRegionArea, then all spans will be re-assigned to the zero (null) region.

Partitioning can result in smaller than necessary regions. mergeRegionArea helps reduce unecessarily small regions.

See the rcConfig documentation for more information on the configuration parameters.

The region data will be available via the rcCompactHeightfield::maxRegions and rcCompactSpan::reg fields.

Warning
The distance field must be created using rcBuildDistanceField before attempting to build regions.
See also
rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
1359 {
1360  rcAssert(ctx);
1361 
1363 
1364  const int w = chf.width;
1365  const int h = chf.height;
1366  unsigned short id = 1;
1367 
1368  rcScopedDelete<unsigned short> srcReg = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
1369  if (!srcReg)
1370  {
1371  ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
1372  return false;
1373  }
1374  memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
1375 
1376  const int nsweeps = rcMax(chf.width,chf.height);
1378  if (!sweeps)
1379  {
1380  ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
1381  return false;
1382  }
1383 
1384 
1385  // Mark border regions.
1386  if (borderSize > 0)
1387  {
1388  // Make sure border will not overflow.
1389  const int bw = rcMin(w, borderSize);
1390  const int bh = rcMin(h, borderSize);
1391  // Paint regions
1392  paintRectRegion(0, bw, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
1393  paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
1394  paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++;
1395  paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++;
1396 
1397  chf.borderSize = borderSize;
1398  }
1399 
1400  rcIntArray prev(256);
1401 
1402  // Sweep one line at a time.
1403  for (int y = borderSize; y < h-borderSize; ++y)
1404  {
1405  // Collect spans from this row.
1406  prev.resize(id+1);
1407  memset(&prev[0],0,sizeof(int)*id);
1408  unsigned short rid = 1;
1409 
1410  for (int x = borderSize; x < w-borderSize; ++x)
1411  {
1412  const rcCompactCell& c = chf.cells[x+y*w];
1413 
1414  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1415  {
1416  const rcCompactSpan& s = chf.spans[i];
1417  if (chf.areas[i] == RC_NULL_AREA) continue;
1418 
1419  // -x
1420  unsigned short previd = 0;
1421  if (rcGetCon(s, 0) != RC_NOT_CONNECTED)
1422  {
1423  const int ax = x + rcGetDirOffsetX(0);
1424  const int ay = y + rcGetDirOffsetY(0);
1425  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
1426  if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
1427  previd = srcReg[ai];
1428  }
1429 
1430  if (!previd)
1431  {
1432  previd = rid++;
1433  sweeps[previd].rid = previd;
1434  sweeps[previd].ns = 0;
1435  sweeps[previd].nei = 0;
1436  }
1437 
1438  // -y
1439  if (rcGetCon(s,3) != RC_NOT_CONNECTED)
1440  {
1441  const int ax = x + rcGetDirOffsetX(3);
1442  const int ay = y + rcGetDirOffsetY(3);
1443  const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
1444  if (srcReg[ai] && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
1445  {
1446  unsigned short nr = srcReg[ai];
1447  if (!sweeps[previd].nei || sweeps[previd].nei == nr)
1448  {
1449  sweeps[previd].nei = nr;
1450  sweeps[previd].ns++;
1451  prev[nr]++;
1452  }
1453  else
1454  {
1455  sweeps[previd].nei = RC_NULL_NEI;
1456  }
1457  }
1458  }
1459 
1460  srcReg[i] = previd;
1461  }
1462  }
1463 
1464  // Create unique ID.
1465  for (int i = 1; i < rid; ++i)
1466  {
1467  if (sweeps[i].nei != RC_NULL_NEI && sweeps[i].nei != 0 &&
1468  prev[sweeps[i].nei] == (int)sweeps[i].ns)
1469  {
1470  sweeps[i].id = sweeps[i].nei;
1471  }
1472  else
1473  {
1474  sweeps[i].id = id++;
1475  }
1476  }
1477 
1478  // Remap IDs
1479  for (int x = borderSize; x < w-borderSize; ++x)
1480  {
1481  const rcCompactCell& c = chf.cells[x+y*w];
1482 
1483  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1484  {
1485  if (srcReg[i] > 0 && srcReg[i] < rid)
1486  srcReg[i] = sweeps[srcReg[i]].id;
1487  }
1488  }
1489  }
1490 
1491 
1493 
1494  // Merge regions and filter out small regions.
1495  rcIntArray overlaps;
1496  chf.maxRegions = id;
1497  if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
1498  return false;
1499 
1500  // Monotone partitioning does not generate overlapping regions.
1501 
1503 
1504  // Store the result out.
1505  for (int i = 0; i < chf.spanCount; ++i)
1506  chf.spans[i].reg = srcReg[i];
1507 
1509 
1510  return true;
1511 }
int height
The height of the heightfield. (Along the z-axis in cell units.)
Definition: Recast.h:308
#define rcAssert
Definition: RecastAssert.h:30
int borderSize
The AABB border size used during the build of the field. (See: rcConfig::borderSize) ...
Definition: Recast.h:312
unsigned short maxRegions
The maximum region id of any span within the field.
Definition: Recast.h:314
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
static const unsigned short RC_NULL_NEI
Definition: RecastRegion.cpp:1328
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
unsigned short reg
The id of the region the span belongs to. (Or zero if not in a region.)
Definition: Recast.h:298
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
T rcMin(T a, T b)
Definition: Recast.h:566
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
An error log entry.
Definition: Recast.h:31
Definition: RecastAlloc.h:105
static bool mergeAndFilterRegions(rcContext *ctx, int minRegionArea, int mergeRegionSize, unsigned short &maxRegionId, rcCompactHeightfield &chf, unsigned short *srcReg, rcIntArray &overlaps)
Definition: RecastRegion.cpp:780
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
unsigned char * areas
Array containing area id data. [Size: spanCount].
Definition: Recast.h:322
Definition: RecastRegion.cpp:1330
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
The total time to build the regions. (See: rcBuildRegions, rcBuildRegionsMonotone) ...
Definition: Recast.h:79
void startTimer(const rcTimerLabel label)
Definition: Recast.h:131
int spanCount
The number of spans in the heightfield.
Definition: Recast.h:309
static void paintRectRegion(int minx, int maxx, int miny, int maxy, unsigned short regId, rcCompactHeightfield &chf, unsigned short *srcReg)
Definition: RecastRegion.cpp:1309
int prev(int i, int n)
Definition: RecastContour.cpp:468
static const unsigned char RC_NULL_AREA
Definition: Recast.h:538
Memory used temporarily within a function.
Definition: RecastAlloc.h:27
T rcMax(T a, T b)
Definition: Recast.h:572
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
G3D::int16 x
Definition: Vector2int16.h:37
void stopTimer(const rcTimerLabel label)
Definition: Recast.h:135
static const unsigned short RC_BORDER_REG
Definition: Recast.h:498
A simple dynamic array of integers.
Definition: RecastAlloc.h:61
The time to filter out small regions. (See: rcBuildRegions, rcBuildRegionsMonotone) ...
Definition: Recast.h:87

+ Here is the call graph for this function:

static void removeAdjacentNeighbours ( rcRegion reg)
static
540 {
541  // Remove adjacent duplicates.
542  for (int i = 0; i < reg.connections.size() && reg.connections.size() > 1; )
543  {
544  int ni = (i+1) % reg.connections.size();
545  if (reg.connections[i] == reg.connections[ni])
546  {
547  // Remove duplicate
548  for (int j = i; j < reg.connections.size()-1; ++j)
549  reg.connections[j] = reg.connections[j+1];
550  reg.connections.pop();
551  }
552  else
553  ++i;
554  }
555 }
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
rcIntArray connections
Definition: RecastRegion.cpp:535
int pop()
Definition: RecastAlloc.h:87

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void replaceNeighbour ( rcRegion reg,
unsigned short  oldId,
unsigned short  newId 
)
static
558 {
559  bool neiChanged = false;
560  for (int i = 0; i < reg.connections.size(); ++i)
561  {
562  if (reg.connections[i] == oldId)
563  {
564  reg.connections[i] = newId;
565  neiChanged = true;
566  }
567  }
568  for (int i = 0; i < reg.floors.size(); ++i)
569  {
570  if (reg.floors[i] == oldId)
571  reg.floors[i] = newId;
572  }
573  if (neiChanged)
575 }
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
rcIntArray connections
Definition: RecastRegion.cpp:535
rcIntArray floors
Definition: RecastRegion.cpp:536
static void removeAdjacentNeighbours(rcRegion &reg)
Definition: RecastRegion.cpp:539

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void sortCellsByLevel ( unsigned short  startLevel,
rcCompactHeightfield chf,
unsigned short *  srcReg,
unsigned int  nbStacks,
rcIntArray stacks,
unsigned short  loglevelsPerStack 
)
static
464 {
465  const int w = chf.width;
466  const int h = chf.height;
467  startLevel = startLevel >> loglevelsPerStack;
468 
469  for (unsigned int j=0; j<nbStacks; ++j)
470  stacks[j].resize(0);
471 
472  // put all cells in the level range into the appropriate stacks
473  for (int y = 0; y < h; ++y)
474  {
475  for (int x = 0; x < w; ++x)
476  {
477  const rcCompactCell& c = chf.cells[x+y*w];
478  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
479  {
480  if (chf.areas[i] == RC_NULL_AREA || srcReg[i] != 0)
481  continue;
482 
483  int level = chf.dist[i] >> loglevelsPerStack;
484  int sId = startLevel - level;
485  if (sId >= (int)nbStacks)
486  continue;
487  if (sId < 0)
488  sId = 0;
489 
490  stacks[sId].push(x);
491  stacks[sId].push(y);
492  stacks[sId].push(i);
493  }
494  }
495  }
496 }
int height
The height of the heightfield. (Along the z-axis in cell units.)
Definition: Recast.h:308
unsigned short * dist
Array containing border distance data. [Size: spanCount].
Definition: Recast.h:321
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
unsigned char * areas
Array containing area id data. [Size: spanCount].
Definition: Recast.h:322
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
static const unsigned char RC_NULL_AREA
Definition: Recast.h:538
G3D::int16 x
Definition: Vector2int16.h:37
void push(int item)
Definition: RecastAlloc.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void walkContour ( int  x,
int  y,
int  i,
int  dir,
rcCompactHeightfield chf,
unsigned short *  srcReg,
rcIntArray cont 
)
static
695 {
696  int startDir = dir;
697  int starti = i;
698 
699  const rcCompactSpan& ss = chf.spans[i];
700  unsigned short curReg = 0;
701  if (rcGetCon(ss, dir) != RC_NOT_CONNECTED)
702  {
703  const int ax = x + rcGetDirOffsetX(dir);
704  const int ay = y + rcGetDirOffsetY(dir);
705  const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(ss, dir);
706  curReg = srcReg[ai];
707  }
708  cont.push(curReg);
709 
710  int iter = 0;
711  while (++iter < 40000)
712  {
713  const rcCompactSpan& s = chf.spans[i];
714 
715  if (isSolidEdge(chf, srcReg, x, y, i, dir))
716  {
717  // Choose the edge corner
718  unsigned short r = 0;
719  if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
720  {
721  const int ax = x + rcGetDirOffsetX(dir);
722  const int ay = y + rcGetDirOffsetY(dir);
723  const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
724  r = srcReg[ai];
725  }
726  if (r != curReg)
727  {
728  curReg = r;
729  cont.push(curReg);
730  }
731 
732  dir = (dir+1) & 0x3; // Rotate CW
733  }
734  else
735  {
736  int ni = -1;
737  const int nx = x + rcGetDirOffsetX(dir);
738  const int ny = y + rcGetDirOffsetY(dir);
739  if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
740  {
741  const rcCompactCell& nc = chf.cells[nx+ny*chf.width];
742  ni = (int)nc.index + rcGetCon(s, dir);
743  }
744  if (ni == -1)
745  {
746  // Should not happen.
747  return;
748  }
749  x = nx;
750  y = ny;
751  i = ni;
752  dir = (dir+3) & 0x3; // Rotate CCW
753  }
754 
755  if (starti == i && startDir == dir)
756  {
757  break;
758  }
759  }
760 
761  // Remove adjacent duplicates.
762  if (cont.size() > 1)
763  {
764  for (int j = 0; j < cont.size(); )
765  {
766  int nj = (j+1) % cont.size();
767  if (cont[j] == cont[nj])
768  {
769  for (int k = j; k < cont.size()-1; ++k)
770  cont[k] = cont[k+1];
771  cont.pop();
772  }
773  else
774  ++j;
775  }
776  }
777 }
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
static bool isSolidEdge(rcCompactHeightfield &chf, unsigned short *srcReg, int x, int y, int i, int dir)
Definition: RecastRegion.cpp:674
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
int pop()
Definition: RecastAlloc.h:87
G3D::int16 x
Definition: Vector2int16.h:37
void push(int item)
Definition: RecastAlloc.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

const unsigned short RC_NULL_NEI = 0xffff
static