23 using TWaterRegionTraversabilityBits = uint16_t;
24 constexpr TWaterRegionPatchLabel FIRST_REGION_LABEL = 1;
25 constexpr TWaterRegionPatchLabel INVALID_WATER_REGION_PATCH = 0;
27 static_assert(
sizeof(TWaterRegionTraversabilityBits) * 8 == WATER_REGION_EDGE_LENGTH);
28 static_assert(
sizeof(TWaterRegionPatchLabel) ==
sizeof(
byte));
33 static inline int GetWaterRegionX(
TileIndex tile) {
return TileX(tile) / WATER_REGION_EDGE_LENGTH; }
34 static inline int GetWaterRegionY(
TileIndex tile) {
return TileY(tile) / WATER_REGION_EDGE_LENGTH; }
36 static inline int GetWaterRegionMapSizeX() {
return Map::SizeX() / WATER_REGION_EDGE_LENGTH; }
37 static inline int GetWaterRegionMapSizeY() {
return Map::SizeY() / WATER_REGION_EDGE_LENGTH; }
39 static inline TWaterRegionIndex
GetWaterRegionIndex(
int region_x,
int region_y) {
return GetWaterRegionMapSizeX() * region_y + region_x; }
51 std::array<TWaterRegionTraversabilityBits, DIAGDIR_END> edge_traversability_bits{};
52 bool has_cross_region_aqueducts =
false;
53 TWaterRegionPatchLabel number_of_patches = 0;
55 std::array<TWaterRegionPatchLabel, WATER_REGION_NUMBER_OF_TILES> tile_patch_labels{};
56 bool initialized =
false;
66 assert(this->tile_area.
Contains(tile));
72 : tile_area(
TileXY(region_x * WATER_REGION_EDGE_LENGTH, region_y * WATER_REGION_EDGE_LENGTH), WATER_REGION_EDGE_LENGTH, WATER_REGION_EDGE_LENGTH)
78 bool IsInitialized()
const {
return this->initialized; }
80 void Invalidate() { this->initialized =
false; }
109 assert(this->tile_area.
Contains(tile));
119 Debug(map, 3,
"Updating water region ({},{})", GetWaterRegionX(this->tile_area.
tile), GetWaterRegionY(this->tile_area.
tile));
120 this->has_cross_region_aqueducts =
false;
122 this->tile_patch_labels.fill(INVALID_WATER_REGION_PATCH);
124 for (
const TileIndex tile : this->tile_area) {
125 if (IsAqueductTile(tile)) {
127 if (!tile_area.Contains(other_aqueduct_end)) {
128 this->has_cross_region_aqueducts =
true;
134 TWaterRegionPatchLabel current_label = 1;
135 TWaterRegionPatchLabel highest_assigned_label = 0;
139 for (
const TileIndex start_tile : tile_area) {
140 static std::vector<TileIndex> tiles_to_check;
141 tiles_to_check.clear();
142 tiles_to_check.push_back(start_tile);
144 bool increase_label =
false;
145 while (!tiles_to_check.empty()) {
146 const TileIndex tile = tiles_to_check.back();
147 tiles_to_check.pop_back();
152 if (this->tile_patch_labels[
GetLocalIndex(tile)] != INVALID_WATER_REGION_PATCH)
continue;
154 this->tile_patch_labels[
GetLocalIndex(tile)] = current_label;
155 highest_assigned_label = current_label;
156 increase_label =
true;
165 if (increase_label) current_label++;
168 this->number_of_patches = highest_assigned_label;
169 this->initialized =
true;
173 this->edge_traversability_bits.fill(0);
174 const int top_x =
TileX(tile_area.tile);
175 const int top_y =
TileY(tile_area.tile);
176 for (
int i = 0; i < WATER_REGION_EDGE_LENGTH; ++i) {
193 std::vector<WaterRegion> _water_regions;
195 TileIndex GetTileIndexFromLocalCoordinate(
int region_x,
int region_y,
int local_x,
int local_y)
197 assert(local_x >= 0 && local_x < WATER_REGION_EDGE_LENGTH);
198 assert(local_y >= 0 && local_y < WATER_REGION_EDGE_LENGTH);
199 return TileXY(WATER_REGION_EDGE_LENGTH * region_x + local_x, WATER_REGION_EDGE_LENGTH * region_y + local_y);
204 assert(x_or_y >= 0 && x_or_y < WATER_REGION_EDGE_LENGTH);
206 case DIAGDIR_NE:
return GetTileIndexFromLocalCoordinate(region_x, region_y, 0, x_or_y);
207 case DIAGDIR_SW:
return GetTileIndexFromLocalCoordinate(region_x, region_y, WATER_REGION_EDGE_LENGTH - 1, x_or_y);
208 case DIAGDIR_NW:
return GetTileIndexFromLocalCoordinate(region_x, region_y, x_or_y, 0);
209 case DIAGDIR_SE:
return GetTileIndexFromLocalCoordinate(region_x, region_y, x_or_y, WATER_REGION_EDGE_LENGTH - 1);
210 default: NOT_REACHED();
214 WaterRegion &GetUpdatedWaterRegion(uint16_t region_x, uint16_t region_y)
217 result.UpdateIfNotInitialized();
224 result.UpdateIfNotInitialized();
253 return TileXY(water_region.
x * WATER_REGION_EDGE_LENGTH + (WATER_REGION_EDGE_LENGTH / 2), water_region.
y * WATER_REGION_EDGE_LENGTH + (WATER_REGION_EDGE_LENGTH / 2));
262 return WaterRegionDesc{ GetWaterRegionX(tile), GetWaterRegionY(tile) };
282 _water_regions[index].Invalidate();
284 Debug(map, 3,
"Invalidated water region ({},{})", GetWaterRegionX(tile), GetWaterRegionY(tile));
296 const WaterRegion ¤t_region = GetUpdatedWaterRegion(water_region_patch.
x, water_region_patch.
y);
299 const int nx = water_region_patch.
x + offset.
x;
300 const int ny = water_region_patch.
y + offset.
y;
302 if (nx < 0 || ny < 0 || nx >= GetWaterRegionMapSizeX() || ny >= GetWaterRegionMapSizeY())
return;
304 const WaterRegion &neighboring_region = GetUpdatedWaterRegion(nx, ny);
310 if (traversability_bits == 0)
return;
318 static std::vector<TWaterRegionPatchLabel> unique_labels;
319 unique_labels.clear();
320 for (
int x_or_y = 0; x_or_y < WATER_REGION_EDGE_LENGTH; ++x_or_y) {
321 if (!
HasBit(traversability_bits, x_or_y))
continue;
323 const TileIndex current_edge_tile = GetEdgeTileCoordinate(water_region_patch.
x, water_region_patch.
y, side, x_or_y);
324 const TWaterRegionPatchLabel current_label = current_region.
GetLabel(current_edge_tile);
325 if (current_label != water_region_patch.
label)
continue;
327 const TileIndex neighbor_edge_tile = GetEdgeTileCoordinate(nx, ny, opposite_side, x_or_y);
328 const TWaterRegionPatchLabel neighbor_label = neighboring_region.
GetLabel(neighbor_edge_tile);
329 if (std::find(unique_labels.begin(), unique_labels.end(), neighbor_label) == unique_labels.end()) unique_labels.push_back(neighbor_label);
331 for (TWaterRegionPatchLabel unique_label : unique_labels) func(
WaterRegionPatchDesc{ nx, ny, unique_label });
342 const WaterRegion ¤t_region = GetUpdatedWaterRegion(water_region_patch.
x, water_region_patch.
y);
349 for (
const TileIndex tile : current_region) {
363 _water_regions.clear();
364 _water_regions.reserve(
static_cast<size_t>(GetWaterRegionMapSizeX()) * GetWaterRegionMapSizeY());
366 Debug(map, 2,
"Allocating {} x {} water regions", GetWaterRegionMapSizeX(), GetWaterRegionMapSizeY());
368 for (
int region_y = 0; region_y < GetWaterRegionMapSizeY(); region_y++) {
369 for (
int region_x = 0; region_x < GetWaterRegionMapSizeX(); region_x++) {
370 _water_regions.emplace_back(region_x, region_y);