# HG changeset patch # User dP # Date 2020-05-11 22:36:28 # Node ID cc815a8a161516ba0d44d4c3927aa6fa76c2ae2f # Parent 9bd51161d653f0686972a02d5c3a624f7359e807 Codechange: Refactor FindStationsAroundTiles to avoid code duplication diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -1697,20 +1697,10 @@ static void PopulateStationsNearby(Indus return; } - /* Get our list of nearby stations. */ - FindStationsAroundTiles(ind->location, &ind->stations_near, false); - - /* Test if industry can accept cargo */ - uint cargo_index; - for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) { - if (ind->accepts_cargo[cargo_index] != CT_INVALID) break; - } - if (cargo_index >= lengthof(ind->accepts_cargo)) return; - - /* Cargo is accepted, add industry to nearby stations nearby industry list. */ - for (Station *st : ind->stations_near) { - st->industries_near.insert(ind); - } + ForAllStationsAroundTiles(ind->location, [ind](Station *st) { + ind->stations_near.insert(st); + st->AddIndustryToDeliver(ind); + }); } /** diff --git a/src/station.cpp b/src/station.cpp --- a/src/station.cpp +++ b/src/station.cpp @@ -359,12 +359,11 @@ Rect Station::GetCatchmentRect() const /** * Add nearby industry to station's industries_near list if it accepts cargo. * @param ind Industry - * @param st Station */ -static void AddIndustryToDeliver(Industry *ind, Station *st) +void Station::AddIndustryToDeliver(Industry *ind) { /* Don't check further if this industry is already in the list */ - if (st->industries_near.find(ind) != st->industries_near.end()) return; + if (this->industries_near.find(ind) != this->industries_near.end()) return; /* Include only industries that can accept cargo */ uint cargo_index; @@ -373,7 +372,7 @@ static void AddIndustryToDeliver(Industr } if (cargo_index >= lengthof(ind->accepts_cargo)) return; - st->industries_near.insert(ind); + this->industries_near.insert(ind); } /** @@ -464,7 +463,7 @@ void Station::RecomputeCatchment() i->stations_near.insert(this); /* Add if we can deliver to this industry as well */ - AddIndustryToDeliver(i, this); + this->AddIndustryToDeliver(i); } } } diff --git a/src/station_base.h b/src/station_base.h --- a/src/station_base.h +++ b/src/station_base.h @@ -503,6 +503,7 @@ public: uint GetCatchmentRadius() const; Rect GetCatchmentRect() const; bool CatchmentCoversTown(TownID t) const; + void AddIndustryToDeliver(Industry *ind); void RemoveFromAllNearbyLists(); inline bool TileIsInCatchment(TileIndex tile) const @@ -557,4 +558,39 @@ public: void RebuildStationKdtree(); +/** + * Call a function on all stations that have any part of the requested area within their catchment. + * @param area The tile area to check + */ +template +void ForAllStationsAroundTiles(const TileArea &ta, Func func) +{ + /* Not using, or don't have a nearby stations list, so we need to scan. */ + std::set seen_stations; + + /* Scan an area around the building covering the maximum possible station + * to find the possible nearby stations. */ + uint max_c = _settings_game.station.modified_catchment ? MAX_CATCHMENT : CA_UNMODIFIED; + TileArea ta_ext = TileArea(ta).Expand(max_c); + TILE_AREA_LOOP(tile, ta_ext) { + if (IsTileType(tile, MP_STATION)) seen_stations.insert(GetStationIndex(tile)); + } + + for (StationID stationid : seen_stations) { + Station *st = Station::GetIfValid(stationid); + if (st == nullptr) continue; /* Waypoint */ + + /* Check if station is attached to an industry */ + if (!_settings_game.station.serve_neutral_industries && st->industry != nullptr) continue; + + /* Test if the tile is within the station's catchment */ + TILE_AREA_LOOP(tile, ta) { + if (st->TileIsInCatchment(tile)) { + func(st); + break; + } + } + } +} + #endif /* STATION_BASE_H */ diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -36,6 +36,7 @@ #include "animated_tile_func.h" #include "elrail_func.h" #include "station_base.h" +#include "station_func.h" #include "station_kdtree.h" #include "roadstop_base.h" #include "newgrf_railtype.h" @@ -3966,69 +3967,27 @@ static void AddNearbyStationsByCatchment } /** - * Find all stations around a rectangular producer (industry, house, headquarter, ...) - * - * @param location The location/area of the producer - * @param[out] stations The list to store the stations in - * @param use_nearby Use nearby station list of industry/town associated with location.tile - */ -void FindStationsAroundTiles(const TileArea &location, StationList * const stations, bool use_nearby) -{ - if (use_nearby) { - /* Industries and towns maintain a list of nearby stations */ - if (IsTileType(location.tile, MP_INDUSTRY)) { - /* Industry nearby stations are already filtered by catchment. */ - *stations = Industry::GetByTile(location.tile)->stations_near; - return; - } else if (IsTileType(location.tile, MP_HOUSE)) { - /* Town nearby stations need to be filtered per tile. */ - assert(location.w == 1 && location.h == 1); - AddNearbyStationsByCatchment(location.tile, stations, Town::GetByTile(location.tile)->stations_near); - return; - } - } - - /* Not using, or don't have a nearby stations list, so we need to scan. */ - std::set seen_stations; - - /* Scan an area around the building covering the maximum possible station - * to find the possible nearby stations. */ - uint max_c = _settings_game.station.modified_catchment ? MAX_CATCHMENT : CA_UNMODIFIED; - TileArea ta = TileArea(location).Expand(max_c); - TILE_AREA_LOOP(tile, ta) { - if (IsTileType(tile, MP_STATION)) seen_stations.insert(GetStationIndex(tile)); - } - - for (StationID stationid : seen_stations) { - Station *st = Station::GetIfValid(stationid); - if (st == nullptr) continue; /* Waypoint */ - - /* Check if station is attached to an industry */ - if (!_settings_game.station.serve_neutral_industries && st->industry != nullptr) continue; - - /* Test if the tile is within the station's catchment */ - TILE_AREA_LOOP(tile, location) { - if (st->TileIsInCatchment(tile)) { - stations->insert(st); - break; - } - } - } -} - -/** * Run a tile loop to find stations around a tile, on demand. Cache the result for further requests * @return pointer to a StationList containing all stations found */ const StationList *StationFinder::GetStations() { if (this->tile != INVALID_TILE) { - FindStationsAroundTiles(*this, &this->stations); + if (IsTileType(this->tile, MP_HOUSE)) { + /* Town nearby stations need to be filtered per tile. */ + assert(this->w == 1 && this->h == 1); + AddNearbyStationsByCatchment(this->tile, &this->stations, Town::GetByTile(this->tile)->stations_near); + } else { + ForAllStationsAroundTiles(*this, [this](Station *st) { + this->stations.insert(st); + }); + } this->tile = INVALID_TILE; } return &this->stations; } + static bool CanMoveGoodsToStation(const Station *st, CargoID type) { /* Is the station reserved exclusively for somebody else? */ diff --git a/src/station_func.h b/src/station_func.h --- a/src/station_func.h +++ b/src/station_func.h @@ -22,8 +22,6 @@ void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius); -void FindStationsAroundTiles(const TileArea &location, StationList *stations, bool use_nearby = true); - void ShowStationViewWindow(StationID station); void UpdateAllStationVirtCoords(); void ClearAllStationCachedNames(); diff --git a/src/station_gui.cpp b/src/station_gui.cpp --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -102,7 +102,7 @@ static void FindStationsAroundSelection( Station *adjacent = nullptr; - /* Direct loop instead of FindStationsAroundTiles as we are not interested in catchment area */ + /* Direct loop instead of ForAllStationsAroundTiles as we are not interested in catchment area */ TILE_AREA_LOOP(tile, ta) { if (IsTileType(tile, MP_STATION) && GetTileOwner(tile) == _local_company) { Station *st = Station::GetByTile(tile); diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -2249,7 +2249,11 @@ static void MakeTownHouse(TileIndex t, T if (size & BUILDING_2_TILES_X) ClearMakeHouseTile(t + TileDiffXY(1, 0), town, counter, stage, ++type, random_bits); if (size & BUILDING_HAS_4_TILES) ClearMakeHouseTile(t + TileDiffXY(1, 1), town, counter, stage, ++type, random_bits); - if (!_generating_world) FindStationsAroundTiles(TileArea(t, (size & BUILDING_2_TILES_X) ? 2 : 1, (size & BUILDING_2_TILES_Y) ? 2 : 1), &town->stations_near, false); + if (!_generating_world) { + ForAllStationsAroundTiles(TileArea(t, (size & BUILDING_2_TILES_X) ? 2 : 1, (size & BUILDING_2_TILES_Y) ? 2 : 1), [town](Station *st) { + town->stations_near.insert(st); + }); + } }