@par 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 @p 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. @p mergeRegionAr
| 1523 | /// |
| 1524 | /// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig |
| 1525 | bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, |
| 1526 | const int borderSize, const int minRegionArea, const int mergeRegionArea) |
| 1527 | { |
| 1528 | rcAssert(ctx); |
| 1529 | |
| 1530 | rcScopedTimer timer(ctx, RC_TIMER_BUILD_REGIONS); |
| 1531 | |
| 1532 | const int w = chf.width; |
| 1533 | const int h = chf.height; |
| 1534 | |
| 1535 | rcScopedDelete<unsigned short> buf((unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount*2, RC_ALLOC_TEMP)); |
| 1536 | if (!buf) |
| 1537 | { |
| 1538 | ctx->log(RC_LOG_ERROR, "rcBuildRegions: Out of memory 'tmp' (%d).", chf.spanCount*4); |
| 1539 | return false; |
| 1540 | } |
| 1541 | |
| 1542 | ctx->startTimer(RC_TIMER_BUILD_REGIONS_WATERSHED); |
| 1543 | |
| 1544 | const int LOG_NB_STACKS = 3; |
| 1545 | const int NB_STACKS = 1 << LOG_NB_STACKS; |
| 1546 | rcTempVector<LevelStackEntry> lvlStacks[NB_STACKS]; |
| 1547 | for (int i=0; i<NB_STACKS; ++i) |
| 1548 | lvlStacks[i].reserve(256); |
| 1549 | |
| 1550 | rcTempVector<LevelStackEntry> stack; |
| 1551 | stack.reserve(256); |
| 1552 | |
| 1553 | unsigned short* srcReg = buf; |
| 1554 | unsigned short* srcDist = buf+chf.spanCount; |
| 1555 | |
| 1556 | memset(srcReg, 0, sizeof(unsigned short)*chf.spanCount); |
| 1557 | memset(srcDist, 0, sizeof(unsigned short)*chf.spanCount); |
| 1558 | |
| 1559 | unsigned short regionId = 1; |
| 1560 | unsigned short level = (chf.maxDistance+1) & ~1; |
| 1561 | |
| 1562 | // TODO: Figure better formula, expandIters defines how much the |
| 1563 | // watershed "overflows" and simplifies the regions. Tying it to |
| 1564 | // agent radius was usually good indication how greedy it could be. |
| 1565 | // const int expandIters = 4 + walkableRadius * 2; |
| 1566 | const int expandIters = 8; |
| 1567 | |
| 1568 | if (borderSize > 0) |
| 1569 | { |
| 1570 | // Make sure border will not overflow. |
| 1571 | const int bw = rcMin(w, borderSize); |
| 1572 | const int bh = rcMin(h, borderSize); |
| 1573 | |
| 1574 | // Paint regions |
| 1575 | paintRectRegion(0, bw, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; |
| 1576 | paintRectRegion(w-bw, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; |
| 1577 | paintRectRegion(0, w, 0, bh, regionId|RC_BORDER_REG, chf, srcReg); regionId++; |
| 1578 | paintRectRegion(0, w, h-bh, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; |
| 1579 | } |
| 1580 | |
| 1581 | chf.borderSize = borderSize; |
| 1582 |
no test coverage detected