Replace tile area in WaterRegion with x, y
Use non-virtual tile iterator
This commit is contained in:
@@ -39,6 +39,32 @@ static inline uint32_t GetWaterRegionMapSizeY() { return MapSizeY() / WATER_REGI
|
|||||||
static inline TWaterRegionIndex GetWaterRegionIndex(uint32_t region_x, uint32_t region_y) { return GetWaterRegionMapSizeX() * region_y + region_x; }
|
static inline TWaterRegionIndex GetWaterRegionIndex(uint32_t region_x, uint32_t region_y) { return GetWaterRegionMapSizeX() * region_y + region_x; }
|
||||||
static inline TWaterRegionIndex GetWaterRegionIndex(TileIndex tile) { return GetWaterRegionIndex(GetWaterRegionX(tile), GetWaterRegionY(tile)); }
|
static inline TWaterRegionIndex GetWaterRegionIndex(TileIndex tile) { return GetWaterRegionIndex(GetWaterRegionX(tile), GetWaterRegionY(tile)); }
|
||||||
|
|
||||||
|
struct WaterRegionTileIterator {
|
||||||
|
uint32_t x;
|
||||||
|
uint32_t y;
|
||||||
|
|
||||||
|
inline operator TileIndex () const
|
||||||
|
{
|
||||||
|
return TileXY(this->x, this->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TileIndex operator *() const
|
||||||
|
{
|
||||||
|
return TileXY(this->x, this->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
WaterRegionTileIterator& operator ++()
|
||||||
|
{
|
||||||
|
this->x++;
|
||||||
|
if ((this->x & WATER_REGION_EDGE_MASK) == 0) {
|
||||||
|
/* reached end of row */
|
||||||
|
this->x -= WATER_REGION_EDGE_LENGTH;
|
||||||
|
this->y++;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a square section of the map of a fixed size. Within this square individual unconnected patches of water are
|
* Represents a square section of the map of a fixed size. Within this square individual unconnected patches of water are
|
||||||
* identified using a Connected Component Labeling (CCL) algorithm. Note that all information stored in this class applies
|
* identified using a Connected Component Labeling (CCL) algorithm. Note that all information stored in this class applies
|
||||||
@@ -49,12 +75,21 @@ class WaterRegion
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::array<TWaterRegionTraversabilityBits, DIAGDIR_END> edge_traversability_bits{};
|
std::array<TWaterRegionTraversabilityBits, DIAGDIR_END> edge_traversability_bits{};
|
||||||
|
const uint32_t tile_x;
|
||||||
|
const uint32_t tile_y;
|
||||||
bool has_cross_region_aqueducts = false;
|
bool has_cross_region_aqueducts = false;
|
||||||
TWaterRegionPatchLabel number_of_patches = 0; // 0 = no water, 1 = one single patch of water, etc...
|
TWaterRegionPatchLabel number_of_patches = 0; // 0 = no water, 1 = one single patch of water, etc...
|
||||||
const OrthogonalTileArea tile_area;
|
|
||||||
std::array<TWaterRegionPatchLabel, WATER_REGION_NUMBER_OF_TILES> tile_patch_labels{};
|
std::array<TWaterRegionPatchLabel, WATER_REGION_NUMBER_OF_TILES> tile_patch_labels{};
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
||||||
|
inline bool ContainsTile(TileIndex tile) const
|
||||||
|
{
|
||||||
|
const uint32_t x = TileX(tile);
|
||||||
|
const uint32_t y = TileY(tile);
|
||||||
|
return x >= this->tile_x && x < this->tile_x + WATER_REGION_EDGE_LENGTH
|
||||||
|
&& y >= this->tile_y && y < this->tile_y + WATER_REGION_EDGE_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the local index of the tile within the region. The N corner represents 0,
|
* Returns the local index of the tile within the region. The N corner represents 0,
|
||||||
* the x direction is positive in the SW direction, and Y is positive in the SE direction.
|
* the x direction is positive in the SW direction, and Y is positive in the SE direction.
|
||||||
@@ -63,17 +98,17 @@ private:
|
|||||||
*/
|
*/
|
||||||
inline int GetLocalIndex(TileIndex tile) const
|
inline int GetLocalIndex(TileIndex tile) const
|
||||||
{
|
{
|
||||||
assert(this->tile_area.Contains(tile));
|
assert(this->ContainsTile(tile));
|
||||||
return (TileX(tile) - TileX(this->tile_area.tile)) + WATER_REGION_EDGE_LENGTH * (TileY(tile) - TileY(this->tile_area.tile));
|
return (TileX(tile) - this->tile_x) + WATER_REGION_EDGE_LENGTH * (TileY(tile) - this->tile_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WaterRegion(uint32_t region_x, uint32_t region_y)
|
WaterRegion(uint32_t region_x, uint32_t region_y)
|
||||||
: tile_area(TileXY(region_x * WATER_REGION_EDGE_LENGTH, region_y * WATER_REGION_EDGE_LENGTH), WATER_REGION_EDGE_LENGTH, WATER_REGION_EDGE_LENGTH)
|
: tile_x(region_x * WATER_REGION_EDGE_LENGTH), tile_y(region_y * WATER_REGION_EDGE_LENGTH)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
OrthogonalTileIterator begin() const { return this->tile_area.begin(); }
|
WaterRegionTileIterator begin() const { return { this->tile_x, this->tile_y }; }
|
||||||
OrthogonalTileIterator end() const { return this->tile_area.end(); }
|
WaterRegionTileIterator end() const { return { this->tile_x, this->tile_y + WATER_REGION_EDGE_LENGTH }; }
|
||||||
|
|
||||||
bool IsInitialized() const { return this->initialized; }
|
bool IsInitialized() const { return this->initialized; }
|
||||||
|
|
||||||
@@ -106,7 +141,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
TWaterRegionPatchLabel GetLabel(TileIndex tile) const
|
TWaterRegionPatchLabel GetLabel(TileIndex tile) const
|
||||||
{
|
{
|
||||||
assert(this->tile_area.Contains(tile));
|
assert(this->ContainsTile(tile));
|
||||||
return this->tile_patch_labels[GetLocalIndex(tile)];
|
return this->tile_patch_labels[GetLocalIndex(tile)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,26 +155,23 @@ public:
|
|||||||
|
|
||||||
this->tile_patch_labels.fill(INVALID_WATER_REGION_PATCH);
|
this->tile_patch_labels.fill(INVALID_WATER_REGION_PATCH);
|
||||||
|
|
||||||
for (const TileIndex tile : this->tile_area) {
|
|
||||||
if (IsAqueductTile(tile)) {
|
|
||||||
const TileIndex other_aqueduct_end = GetOtherBridgeEnd(tile);
|
|
||||||
if (!tile_area.Contains(other_aqueduct_end)) {
|
|
||||||
this->has_cross_region_aqueducts = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TWaterRegionPatchLabel current_label = 1;
|
TWaterRegionPatchLabel current_label = 1;
|
||||||
TWaterRegionPatchLabel highest_assigned_label = 0;
|
TWaterRegionPatchLabel highest_assigned_label = 0;
|
||||||
|
|
||||||
/* Perform connected component labeling. This uses a flooding algorithm that expands until no
|
/* Perform connected component labeling. This uses a flooding algorithm that expands until no
|
||||||
* additional tiles can be added. Only tiles inside the water region are considered. */
|
* additional tiles can be added. Only tiles inside the water region are considered. */
|
||||||
for (const TileIndex start_tile : tile_area) {
|
for (const TileIndex start_tile : *this) {
|
||||||
static std::vector<TileIndex> tiles_to_check;
|
static std::vector<TileIndex> tiles_to_check;
|
||||||
tiles_to_check.clear();
|
tiles_to_check.clear();
|
||||||
tiles_to_check.push_back(start_tile);
|
tiles_to_check.push_back(start_tile);
|
||||||
|
|
||||||
|
if (!this->has_cross_region_aqueducts && IsAqueductTile(start_tile)) {
|
||||||
|
const TileIndex other_aqueduct_end = GetOtherBridgeEnd(start_tile);
|
||||||
|
if (!this->ContainsTile(other_aqueduct_end)) {
|
||||||
|
this->has_cross_region_aqueducts = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool increase_label = false;
|
bool increase_label = false;
|
||||||
while (!tiles_to_check.empty()) {
|
while (!tiles_to_check.empty()) {
|
||||||
const TileIndex tile = tiles_to_check.back();
|
const TileIndex tile = tiles_to_check.back();
|
||||||
@@ -157,7 +189,7 @@ public:
|
|||||||
for (const Trackdir dir : SetTrackdirBitIterator(valid_dirs)) {
|
for (const Trackdir dir : SetTrackdirBitIterator(valid_dirs)) {
|
||||||
/* By using a TrackFollower we "play by the same rules" as the actual ship pathfinder */
|
/* By using a TrackFollower we "play by the same rules" as the actual ship pathfinder */
|
||||||
CFollowTrackWater ft;
|
CFollowTrackWater ft;
|
||||||
if (ft.Follow(tile, dir) && this->tile_area.Contains(ft.m_new_tile)) tiles_to_check.push_back(ft.m_new_tile);
|
if (ft.Follow(tile, dir) && this->ContainsTile(ft.m_new_tile)) tiles_to_check.push_back(ft.m_new_tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,8 +202,8 @@ public:
|
|||||||
/* Calculate the traversability (whether the tile can be entered / exited) for all edges. Note that
|
/* Calculate the traversability (whether the tile can be entered / exited) for all edges. Note that
|
||||||
* we always follow the same X and Y scanning direction, this is important for comparisons later on! */
|
* we always follow the same X and Y scanning direction, this is important for comparisons later on! */
|
||||||
this->edge_traversability_bits.fill(0);
|
this->edge_traversability_bits.fill(0);
|
||||||
const uint32_t top_x = TileX(tile_area.tile);
|
const uint32_t top_x = this->tile_x;
|
||||||
const uint32_t top_y = TileY(tile_area.tile);
|
const uint32_t top_y = this->tile_y;
|
||||||
for (uint32_t i = 0; i < WATER_REGION_EDGE_LENGTH; ++i) {
|
for (uint32_t i = 0; i < WATER_REGION_EDGE_LENGTH; ++i) {
|
||||||
if (GetWaterTracks(TileXY(top_x + i, top_y)) & TRACK_BIT_3WAY_NW) SetBit(this->edge_traversability_bits[DIAGDIR_NW], i); // NW edge
|
if (GetWaterTracks(TileXY(top_x + i, top_y)) & TRACK_BIT_3WAY_NW) SetBit(this->edge_traversability_bits[DIAGDIR_NW], i); // NW edge
|
||||||
if (GetWaterTracks(TileXY(top_x + i, top_y + WATER_REGION_EDGE_LENGTH - 1)) & TRACK_BIT_3WAY_SE) SetBit(this->edge_traversability_bits[DIAGDIR_SE], i); // SE edge
|
if (GetWaterTracks(TileXY(top_x + i, top_y + WATER_REGION_EDGE_LENGTH - 1)) & TRACK_BIT_3WAY_SE) SetBit(this->edge_traversability_bits[DIAGDIR_SE], i); // SE edge
|
||||||
|
@@ -21,6 +21,8 @@ using TWaterRegionIndex = uint32_t;
|
|||||||
|
|
||||||
constexpr uint32_t WATER_REGION_EDGE_LENGTH = 16;
|
constexpr uint32_t WATER_REGION_EDGE_LENGTH = 16;
|
||||||
constexpr uint32_t WATER_REGION_NUMBER_OF_TILES = WATER_REGION_EDGE_LENGTH * WATER_REGION_EDGE_LENGTH;
|
constexpr uint32_t WATER_REGION_NUMBER_OF_TILES = WATER_REGION_EDGE_LENGTH * WATER_REGION_EDGE_LENGTH;
|
||||||
|
constexpr uint32_t WATER_REGION_EDGE_MASK = WATER_REGION_EDGE_LENGTH - 1;
|
||||||
|
static_assert((WATER_REGION_EDGE_LENGTH & WATER_REGION_EDGE_MASK) == 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes a single interconnected patch of water within a particular water region.
|
* Describes a single interconnected patch of water within a particular water region.
|
||||||
|
Reference in New Issue
Block a user