Go to the documentation of this file.00001
00003 #include "../stdafx.h"
00004 #include "../station_base.h"
00005 #include "../settings_type.h"
00006 #include "../newgrf_cargo.h"
00007 #include "../cargotype.h"
00008 #include "../core/math_func.hpp"
00009 #include "demands.h"
00010 #include <list>
00011
00012 typedef std::list<NodeID> NodeList;
00013
00022 void SymmetricScaler::SetDemands(LinkGraphJob *job, NodeID from_id, NodeID to_id, uint demand_forw)
00023 {
00024 if (job->Graph().GetNode(from_id).demand > 0) {
00025 uint demand_back = demand_forw * this->mod_size / 100;
00026 uint undelivered = job->GetNode(to_id).undelivered_supply;
00027 if (demand_back > undelivered) {
00028 demand_back = undelivered;
00029 demand_forw = max(1U, demand_back * 100 / this->mod_size);
00030 }
00031 this->Scaler::SetDemands(job, to_id, from_id, demand_back);
00032 }
00033
00034 this->Scaler::SetDemands(job, from_id, to_id, demand_forw);
00035 }
00036
00045 inline void Scaler::SetDemands(LinkGraphJob *job, NodeID from_id, NodeID to_id, uint demand_forw)
00046 {
00047 EdgeAnnotation &forward = job->GetEdge(from_id, to_id);
00048 forward.demand += demand_forw;
00049 forward.unsatisfied_demand += demand_forw;
00050 job->GetNode(from_id).undelivered_supply -= demand_forw;
00051 }
00052
00058 template<class Tscaler>
00059 void DemandCalculator::CalcDemand(LinkGraphJob *job, Tscaler scaler)
00060 {
00061 NodeList supplies;
00062 NodeList demands;
00063 uint num_supplies = 0;
00064 uint num_demands = 0;
00065
00066 LinkGraph *graph = &job->Graph();
00067 for (NodeID node = 0; node < graph->GetSize(); node++) {
00068 Node &n = graph->GetNode(node);
00069 scaler.AddNode(n);
00070 if (n.supply > 0) {
00071 supplies.push_back(node);
00072 num_supplies++;
00073 }
00074 if (n.demand > 0) {
00075 demands.push_back(node);
00076 num_demands++;
00077 }
00078 }
00079
00080 if (num_supplies == 0 || num_demands == 0) return;
00081
00082
00083
00084
00085 scaler.SetDemandPerNode(num_demands);
00086 uint chance = 0;
00087
00088 while (!supplies.empty() && !demands.empty()) {
00089 NodeID from_id = supplies.front();
00090 supplies.pop_front();
00091
00092 Node &from = graph->GetNode(from_id);
00093 NodeAnnotation &from_anno = job->GetNode(from_id);
00094
00095 for (uint i = 0; i < num_demands; ++i) {
00096 assert(!demands.empty());
00097 NodeID to_id = demands.front();
00098 demands.pop_front();
00099 if (from_id == to_id) {
00100
00101 if (demands.empty() && supplies.empty()) return;
00102
00103 demands.push_back(to_id);
00104 continue;
00105 }
00106 Node &to = graph->GetNode(to_id);
00107
00108 int32 supply = scaler.EffectiveSupply(from, to);
00109 assert(supply > 0);
00110
00111
00112 int32 distance = this->max_distance - (this->max_distance -
00113 (int32)graph->GetEdge(from_id, to_id).distance) * this->mod_dist / 100;
00114
00115
00116 int32 divisor = this->accuracy * (this->mod_dist - 50) / 100 +
00117 this->accuracy * distance / this->max_distance + 1;
00118
00119 assert(divisor > 0);
00120
00121 uint demand_forw = 0;
00122 if (divisor <= supply) {
00123
00124
00125
00126 demand_forw = supply / divisor;
00127 } else if (++chance > this->accuracy * num_demands * num_supplies) {
00128
00129
00130 demand_forw = 1;
00131 }
00132
00133 demand_forw = min(demand_forw, from_anno.undelivered_supply);
00134
00135 scaler.SetDemands(job, from_id, to_id, demand_forw);
00136
00137 if (scaler.HasDemandLeft(to, job->GetNode(to_id))) {
00138 demands.push_back(to_id);
00139 } else {
00140 num_demands--;
00141 }
00142
00143 if (from_anno.undelivered_supply == 0) break;
00144 }
00145
00146 if (from_anno.undelivered_supply != 0) {
00147 supplies.push_back(from_id);
00148 } else {
00149 num_supplies--;
00150 }
00151 }
00152 }
00153
00158 DemandCalculator::DemandCalculator(LinkGraphJob *job) :
00159 max_distance(MapSizeX() + MapSizeY() - 2)
00160 {
00161 const LinkGraphSettings &settings = job->Settings();
00162 CargoID cargo = job->Graph().GetCargo();
00163
00164 this->accuracy = settings.accuracy;
00165 this->mod_dist = settings.demand_distance;
00166 if (this->mod_dist > 100) {
00167
00168 int over100 = this->mod_dist - 100;
00169 this->mod_dist = 100 + over100 * over100;
00170 }
00171
00172 switch (settings.GetDistributionType(cargo)) {
00173 case DT_SYMMETRIC:
00174 this->CalcDemand<SymmetricScaler>(job, SymmetricScaler(settings.demand_size));
00175 break;
00176 case DT_ASYMMETRIC:
00177 this->CalcDemand<AsymmetricScaler>(job, AsymmetricScaler());
00178 break;
00179 default:
00180
00181 break;
00182 }
00183 }