diff --git a/src/pathfinder/water_regions.cpp b/src/pathfinder/water_regions.cpp index df4da633df..e34f3ad47e 100644 --- a/src/pathfinder/water_regions.cpp +++ b/src/pathfinder/water_regions.cpp @@ -38,6 +38,8 @@ static inline int GetWaterRegionMapSizeY() { return Map::SizeY() / WATER_REGION_ static inline TWaterRegionIndex GetWaterRegionIndex(int region_x, int region_y) { return GetWaterRegionMapSizeX() * region_y + region_x; } static inline TWaterRegionIndex GetWaterRegionIndex(TileIndex tile) { return GetWaterRegionIndex(GetWaterRegionX(tile), GetWaterRegionY(tile)); } +using TWaterRegionPatchLabelArray = std::array; + /** * 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 @@ -49,10 +51,10 @@ class WaterRegion private: std::array edge_traversability_bits{}; bool has_cross_region_aqueducts = false; + bool initialized = false; TWaterRegionPatchLabel number_of_patches = 0; // 0 = no water, 1 = one single patch of water, etc... const OrthogonalTileArea tile_area; - std::array tile_patch_labels{}; - bool initialized = false; + std::unique_ptr tile_patch_labels; ///< Tile patch labels, this may be nullptr in the following trivial cases: region is invalid, region is only land (0 patches), region is only water (1 patch) /** * Returns the local index of the tile within the region. The N corner represents 0, @@ -110,7 +112,10 @@ public: TWaterRegionPatchLabel GetLabel(TileIndex tile) const { assert(this->tile_area.Contains(tile)); - return this->tile_patch_labels[GetLocalIndex(tile)]; + if (this->tile_patch_labels == nullptr) { + return this->NumberOfPatches() == 0 ? INVALID_WATER_REGION_PATCH : 1; + } + return (*this->tile_patch_labels)[GetLocalIndex(tile)]; } /** @@ -122,7 +127,12 @@ public: Debug(map, 3, "Updating water region ({},{})", GetWaterRegionX(this->tile_area.tile), GetWaterRegionY(this->tile_area.tile)); this->has_cross_region_aqueducts = false; - this->tile_patch_labels.fill(INVALID_WATER_REGION_PATCH); + /* Acquire a tile patch label array if this region does not already have one */ + if (this->tile_patch_labels == nullptr) { + this->tile_patch_labels = std::make_unique(); + } + + this->tile_patch_labels->fill(INVALID_WATER_REGION_PATCH); this->edge_traversability_bits.fill(0); TWaterRegionPatchLabel current_label = 1; @@ -143,9 +153,10 @@ public: const TrackdirBits valid_dirs = TrackBitsToTrackdirBits(GetWaterTracks(tile)); if (valid_dirs == TRACKDIR_BIT_NONE) continue; - if (this->tile_patch_labels[GetLocalIndex(tile)] != INVALID_WATER_REGION_PATCH) continue; + TWaterRegionPatchLabel &tile_patch = (*this->tile_patch_labels)[GetLocalIndex(tile)]; + if (tile_patch != INVALID_WATER_REGION_PATCH) continue; - this->tile_patch_labels[GetLocalIndex(tile)] = current_label; + tile_patch = current_label; highest_assigned_label = current_label; increase_label = true; @@ -172,6 +183,12 @@ public: this->number_of_patches = highest_assigned_label; this->initialized = true; + + if (this->number_of_patches == 0 || (this->number_of_patches == 1 && + std::all_of(this->tile_patch_labels->begin(), this->tile_patch_labels->end(), [](TWaterRegionPatchLabel label) { return label == 1; }))) { + /* No need for patch storage: trivial cases */ + this->tile_patch_labels.reset(); + } } /** @@ -196,7 +213,7 @@ public: for (int y = 0; y < WATER_REGION_EDGE_LENGTH; ++y) { std::string line{}; for (int x = 0; x < WATER_REGION_EDGE_LENGTH; ++x) { - const auto label = this->tile_patch_labels[x + y * WATER_REGION_EDGE_LENGTH]; + const auto label = this->GetLabel(TileAddXY(tile_area.tile, x, y)); const std::string label_str = label == INVALID_WATER_REGION_PATCH ? "." : std::to_string(label); line = fmt::format("{:{}}", label_str, max_element_width) + " " + line; }