Changeset - r24193:cc815a8a1615
[Not reviewed]
master
0 7 0
dP - 4 years ago 2020-05-11 22:36:28
dp@dpointer.org
Codechange: Refactor FindStationsAroundTiles to avoid code duplication
7 files changed with 61 insertions and 75 deletions:
0 comments (0 inline, 0 general)
src/industry_cmd.cpp
Show inline comments
 
@@ -1688,38 +1688,28 @@ static void AdvertiseIndustryOpening(con
 
 * @param ind Industry
 
 */
 
static void PopulateStationsNearby(Industry *ind)
 
{
 
	if (ind->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) {
 
		/* Industry has a neutral station. Use it and ignore any other nearby stations. */
 
		ind->stations_near.insert(ind->neutral_station);
 
		ind->neutral_station->industries_near.clear();
 
		ind->neutral_station->industries_near.insert(ind);
 
		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);
 
	});
 
}
 

	
 
/**
 
 * Put an industry on the map.
 
 * @param i                   Just allocated poolitem, mostly empty.
 
 * @param tile                North tile of the industry.
 
 * @param type                Type of the industry.
 
 * @param layout              Industrylayout to build.
 
 * @param layout_index        Number of the industry layout.
 
 * @param t                   Nearest town.
 
 * @param founder             Founder of the industry; OWNER_NONE in case of random construction.
 
 * @param initial_random_bits Random bits for the industry.
src/station.cpp
Show inline comments
 
@@ -350,39 +350,38 @@ Rect Station::GetCatchmentRect() const
 
		max<int>(this->rect.left   - catchment_radius, 0),
 
		max<int>(this->rect.top    - catchment_radius, 0),
 
		min<int>(this->rect.right  + catchment_radius, MapMaxX()),
 
		min<int>(this->rect.bottom + catchment_radius, MapMaxY())
 
	};
 

	
 
	return ret;
 
}
 

	
 
/**
 
 * 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;
 
	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;
 

	
 
	st->industries_near.insert(ind);
 
	this->industries_near.insert(ind);
 
}
 

	
 
/**
 
 * Remove this station from the nearby stations lists of all towns and industries.
 
 */
 
void Station::RemoveFromAllNearbyLists()
 
{
 
	for (Town *t : Town::Iterate()) { t->stations_near.erase(this); }
 
	for (Industry *i : Industry::Iterate()) { i->stations_near.erase(this); }
 
}
 

	
 
/**
 
@@ -455,25 +454,25 @@ void Station::RecomputeCatchment()
 
			Town *t = Town::GetByTile(tile);
 
			t->stations_near.insert(this);
 
		}
 
		if (IsTileType(tile, MP_INDUSTRY)) {
 
			Industry *i = Industry::GetByTile(tile);
 

	
 
			/* Ignore industry if it has a neutral station. It already can't be this station. */
 
			if (!_settings_game.station.serve_neutral_industries && i->neutral_station != nullptr) continue;
 

	
 
			i->stations_near.insert(this);
 

	
 
			/* Add if we can deliver to this industry as well */
 
			AddIndustryToDeliver(i, this);
 
			this->AddIndustryToDeliver(i);
 
		}
 
	}
 
}
 

	
 
/**
 
 * Recomputes catchment of all stations.
 
 * This will additionally recompute nearby stations for all towns and industries.
 
 */
 
/* static */ void Station::RecomputeCatchmentForAll()
 
{
 
	for (Station *st : Station::Iterate()) { st->RecomputeCatchment(); }
 
}
src/station_base.h
Show inline comments
 
@@ -494,24 +494,25 @@ public:
 
	void MoveSign(TileIndex new_xy) override;
 

	
 
	void AfterStationTileSetChange(bool adding, StationType type);
 

	
 
	uint GetPlatformLength(TileIndex tile, DiagDirection dir) const override;
 
	uint GetPlatformLength(TileIndex tile) const override;
 
	void RecomputeCatchment();
 
	static void RecomputeCatchmentForAll();
 

	
 
	uint GetCatchmentRadius() const;
 
	Rect GetCatchmentRect() const;
 
	bool CatchmentCoversTown(TownID t) const;
 
	void AddIndustryToDeliver(Industry *ind);
 
	void RemoveFromAllNearbyLists();
 

	
 
	inline bool TileIsInCatchment(TileIndex tile) const
 
	{
 
		return this->catchment_tiles.HasTile(tile);
 
	}
 

	
 
	inline bool TileBelongsToRailStation(TileIndex tile) const override
 
	{
 
		return IsRailStationTile(tile) && GetStationIndex(tile) == this->index;
 
	}
 

	
 
@@ -548,13 +549,48 @@ public:
 
		}
 
		return *this;
 
	}
 

	
 
	virtual TileIterator *Clone() const
 
	{
 
		return new AirportTileIterator(*this);
 
	}
 
};
 

	
 
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<typename Func>
 
void ForAllStationsAroundTiles(const TileArea &ta, Func func)
 
{
 
	/* Not using, or don't have a nearby stations list, so we need to scan. */
 
	std::set<StationID> 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 */
src/station_cmd.cpp
Show inline comments
 
@@ -27,24 +27,25 @@
 
#include "pathfinder/yapf/yapf_cache.h"
 
#include "road_internal.h" /* For drawing catenary/checking road removal */
 
#include "autoslope.h"
 
#include "water.h"
 
#include "strings_func.h"
 
#include "clear_func.h"
 
#include "date_func.h"
 
#include "vehicle_func.h"
 
#include "string_func.h"
 
#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"
 
#include "newgrf_roadtype.h"
 
#include "waypoint_base.h"
 
#include "waypoint_func.h"
 
#include "pbs.h"
 
#include "debug.h"
 
#include "core/random_func.hpp"
 
#include "company_base.h"
 
#include "table/airporttile_ids.h"
 
#include "newgrf_airporttiles.h"
 
@@ -3957,87 +3958,45 @@ CommandCost CmdRenameStation(TileIndex t
 

	
 
	return CommandCost();
 
}
 

	
 
static void AddNearbyStationsByCatchment(TileIndex tile, StationList *stations, StationList &nearby)
 
{
 
	for (Station *st : nearby) {
 
		if (st->TileIsInCatchment(tile)) stations->insert(st);
 
	}
 
}
 

	
 
/**
 
 * 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<StationID> 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? */
 
	if (st->owner != OWNER_NONE && st->town->exclusive_counter > 0 && st->town->exclusivity != st->owner) return false;
 

	
 
	/* Lowest possible rating, better not to give cargo anymore. */
 
	if (st->goods[type].rating == 0) return false;
 

	
 
	/* Selectively servicing stations, and not this one. */
 
	if (_settings_game.order.selectgoods && !st->goods[type].HasVehicleEverTriedLoading()) return false;
 

	
 
	if (IsCargoInClass(type, CC_PASSENGERS)) {
src/station_func.h
Show inline comments
 
@@ -13,26 +13,24 @@
 
#include "sprite.h"
 
#include "rail_type.h"
 
#include "road_type.h"
 
#include "vehicle_type.h"
 
#include "economy_func.h"
 
#include "rail.h"
 
#include "road.h"
 
#include "linkgraph/linkgraph_type.h"
 
#include "industry_type.h"
 

	
 
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();
 

	
 
CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad);
 
CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, CargoTypes *always_accepted = nullptr);
 

	
 
void UpdateStationAcceptance(Station *st, bool show_msg);
 

	
 
const DrawTileSprites *GetStationTileLayout(StationType st, byte gfx);
 
void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, RoadType roadtype, int image);
 

	
src/station_gui.cpp
Show inline comments
 
@@ -93,25 +93,25 @@ static void FindStationsAroundSelection(
 
	/* Tile area for TileHighlightData */
 
	TileArea location(TileVirtXY(_thd.pos.x, _thd.pos.y), _thd.size.x / TILE_SIZE - 1, _thd.size.y / TILE_SIZE - 1);
 

	
 
	/* Extended area by one tile */
 
	uint x = TileX(location.tile);
 
	uint y = TileY(location.tile);
 

	
 
	int max_c = 1;
 
	TileArea ta(TileXY(max<int>(0, x - max_c), max<int>(0, y - max_c)), TileXY(min<int>(MapMaxX(), x + location.w + max_c), min<int>(MapMaxY(), y + location.h + max_c)));
 

	
 
	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);
 
			if (st == nullptr) continue;
 
			if (adjacent != nullptr && st != adjacent) {
 
				/* Multiple nearby, distant join is required. */
 
				adjacent = nullptr;
 
				break;
 
			}
 
			adjacent = st;
 
		}
 
	}
src/town_cmd.cpp
Show inline comments
 
@@ -2240,25 +2240,29 @@ static inline void ClearMakeHouseTile(Ti
 
 * @param random_bits required for newgrf houses
 
 * @pre house can be built here
 
 */
 
static void MakeTownHouse(TileIndex t, Town *town, byte counter, byte stage, HouseID type, byte random_bits)
 
{
 
	BuildingFlags size = HouseSpec::Get(type)->building_flags;
 

	
 
	ClearMakeHouseTile(t, town, counter, stage, type, random_bits);
 
	if (size & BUILDING_2_TILES_Y)   ClearMakeHouseTile(t + TileDiffXY(0, 1), town, counter, stage, ++type, random_bits);
 
	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);
 
		});
 
	}
 
}
 

	
 

	
 
/**
 
 * Checks if a house can be built here. Important is slope, bridge above
 
 * and ability to clear the land.
 
 * @param tile tile to check
 
 * @param noslope are slopes (foundations) allowed?
 
 * @return true iff house can be built here
 
 */
 
static inline bool CanBuildHouseHere(TileIndex tile, bool noslope)
 
{
0 comments (0 inline, 0 general)