diff --git a/src/linkgraph/demands.cpp b/src/linkgraph/demands.cpp index b164f46ae6..851d82f82a 100644 --- a/src/linkgraph/demands.cpp +++ b/src/linkgraph/demands.cpp @@ -2,6 +2,7 @@ #include "../stdafx.h" #include "demands.h" +#include "../core/math_func.hpp" #include #include "../safeguards.h" @@ -207,23 +208,26 @@ void DemandCalculator::CalcDemand(LinkGraphJob &job, Tscaler scaler) int32_t supply = scaler.EffectiveSupply(job[from_id], job[to_id]); assert(supply > 0); - /* Scale the distance by mod_dist around max_distance */ - int32_t distance = this->max_distance - (this->max_distance - - (int32_t)DistanceMaxPlusManhattan(job[from_id].base.xy, job[to_id].base.xy)) * - this->mod_dist / 100; + constexpr int32_t divisor_scale = 16; + + int32_t scaled_distance = this->base_distance; + if (this->mod_dist > 0) { + const int32_t distance = DistanceMaxPlusManhattan(job[from_id].base.xy, job[to_id].base.xy); + /* Scale distance around base_distance by (mod_dist * (100 / 1024)). + * mod_dist may be > 1024, so clamp result to be non-negative */ + scaled_distance = std::max(0, this->base_distance + (((distance - this->base_distance) * this->mod_dist) / 1024)); + } /* Scale the accuracy by distance around accuracy / 2 */ - int32_t divisor = this->accuracy * (this->mod_dist - 50) / 100 + - this->accuracy * distance / this->max_distance + 1; - - assert(divisor > 0); + const int32_t divisor = divisor_scale + ((this->accuracy * scaled_distance * divisor_scale) / (this->base_distance * 2)); + assert(divisor >= divisor_scale); uint demand_forw = 0; - if (divisor <= supply) { + if (divisor <= (supply * divisor_scale)) { /* At first only distribute demand if * effective supply / accuracy divisor >= 1 * Others are too small or too far away to be considered. */ - demand_forw = supply / divisor; + demand_forw = (supply * divisor_scale) / divisor; } else if (++chance > this->accuracy * num_demands * num_supplies) { /* After some trying, if there is still supply left, distribute * demand also to other nodes. */ @@ -256,7 +260,7 @@ void DemandCalculator::CalcDemand(LinkGraphJob &job, Tscaler scaler) * @param job Job to calculate the demands for. */ DemandCalculator::DemandCalculator(LinkGraphJob &job) : - max_distance(DistanceMaxPlusManhattan(TileXY(0,0), TileXY(Map::MaxX(), Map::MaxY()))) + base_distance(IntSqrt(DistanceMaxPlusManhattan(TileXY(0,0), TileXY(Map::MaxX(), Map::MaxY())))) { const LinkGraphSettings &settings = job.Settings(); CargoID cargo = job.Cargo(); @@ -264,9 +268,15 @@ DemandCalculator::DemandCalculator(LinkGraphJob &job) : this->accuracy = settings.accuracy; this->mod_dist = settings.demand_distance; if (this->mod_dist > 100) { - /* Increase effect of mod_dist > 100 */ + /* Increase effect of mod_dist > 100. + * Quadratic: + * 100 --> 100 + * 150 --> 308 + * 200 --> 933 + * 255 --> 2102 + */ int over100 = this->mod_dist - 100; - this->mod_dist = 100 + over100 * over100; + this->mod_dist = 100 + ((over100 * over100) / 12); } switch (settings.GetDistributionType(cargo)) { diff --git a/src/linkgraph/demands.h b/src/linkgraph/demands.h index 7de853a674..52dd5cb097 100644 --- a/src/linkgraph/demands.h +++ b/src/linkgraph/demands.h @@ -14,9 +14,9 @@ public: DemandCalculator(LinkGraphJob &job); private: - int32_t max_distance; ///< Maximum distance possible on the map. - int32_t mod_dist; ///< Distance modifier, determines how much demands decrease with distance. - int32_t accuracy; ///< Accuracy of the calculation. + int32_t base_distance; ///< Base distance for scaling purposes. + int32_t mod_dist; ///< Distance modifier, determines how much demands decrease with distance. + int32_t accuracy; ///< Accuracy of the calculation. template void CalcDemand(LinkGraphJob &job, Tscaler scaler);