00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "demands.h"
00013 #include "../station_base.h"
00014 #include "../settings_type.h"
00015 #include "../newgrf_cargo.h"
00016 #include "../cargotype.h"
00017 #include "../core/math_func.hpp"
00018 #include <list>
00019
00020 typedef std::list<NodeID> NodeList;
00021
00030 void SymmetricScaler::SetDemands(LinkGraphComponent * graph, NodeID from_id, NodeID to_id, uint demand_forw)
00031 {
00032 if (graph->GetNode(from_id).demand > 0) {
00033 uint demand_back = demand_forw * this->mod_size / 100;
00034 uint undelivered = graph->GetNode(to_id).undelivered_supply;
00035 if (demand_back > undelivered) {
00036 demand_back = undelivered;
00037 demand_forw = max(1U, demand_back * 100 / this->mod_size);
00038 }
00039 this->Scaler::SetDemands(graph, to_id, from_id, demand_back);
00040 }
00041
00042 this->Scaler::SetDemands(graph, from_id, to_id, demand_forw);
00043 }
00044
00053 FORCEINLINE void Scaler::SetDemands(LinkGraphComponent * graph, NodeID from_id, NodeID to_id, uint demand_forw)
00054 {
00055 Edge &forward = graph->GetEdge(from_id, to_id);
00056 forward.demand += demand_forw;
00057 forward.unsatisfied_demand += demand_forw;
00058 graph->GetNode(from_id).undelivered_supply -= demand_forw;
00059 }
00060
00065 template<class Tscaler>
00066 void DemandCalculator::CalcDemand(LinkGraphComponent *graph, Tscaler scaler)
00067 {
00068 NodeList supplies;
00069 NodeList demands;
00070 uint num_supplies = 0;
00071 uint num_demands = 0;
00072
00073 for(NodeID node = 0; node < graph->GetSize(); node++) {
00074 Node &n = graph->GetNode(node);
00075 scaler.AddNode(n);
00076 if (n.supply > 0) {
00077 supplies.push_back(node);
00078 num_supplies++;
00079 }
00080 if (n.demand > 0) {
00081 demands.push_back(node);
00082 num_demands++;
00083 }
00084 }
00085
00086 if (num_supplies == 0 || num_demands == 0) return;
00087
00088
00089
00090
00091
00092 scaler.SetDemandPerNode(num_demands);
00093 uint chance = 0;
00094
00095 while(!supplies.empty() && !demands.empty()) {
00096 NodeID node1 = supplies.front();
00097 supplies.pop_front();
00098
00099 Node &from = graph->GetNode(node1);
00100
00101 for(uint i = 0; i < num_demands; ++i) {
00102 assert(!demands.empty());
00103 NodeID node2 = demands.front();
00104 demands.pop_front();
00105 if (node1 == node2) {
00106 if (demands.empty() && supplies.empty()) {
00107
00108 return;
00109 } else {
00110 demands.push_back(node2);
00111 continue;
00112 }
00113 }
00114 Node &to = graph->GetNode(node2);
00115
00116 int32 supply = scaler.EffectiveSupply(from, to);
00117 assert(supply > 0);
00118
00119
00120 int32 distance = this->max_distance - (this->max_distance -
00121 (int32)graph->GetEdge(node1, node2).distance) * this->mod_dist / 100;
00122
00123
00124 int32 divisor = this->accuracy * (this->mod_dist - 50) / 100 +
00125 this->accuracy * distance / this->max_distance + 1;
00126
00127 assert(divisor > 0);
00128
00129 uint demand_forw = 0;
00130 if (divisor <= supply) {
00131
00132
00133
00134
00135 demand_forw = supply / divisor;
00136 } else if (++chance > this->accuracy * num_demands * num_supplies) {
00137
00138
00139
00140 demand_forw = 1;
00141 }
00142
00143 demand_forw = min(demand_forw, from.undelivered_supply);
00144
00145 scaler.SetDemands(graph, node1, node2, demand_forw);
00146
00147 if (scaler.DemandLeft(to)) {
00148 demands.push_back(node2);
00149 } else {
00150 num_demands--;
00151 }
00152
00153 if (from.undelivered_supply == 0) break;
00154
00155 }
00156 if (from.undelivered_supply != 0) {
00157 supplies.push_back(node1);
00158 } else {
00159 num_supplies--;
00160 }
00161 }
00162 }
00163
00168 DemandCalculator::DemandCalculator(LinkGraphComponent *graph) :
00169 max_distance(MapSizeX() + MapSizeY() + 1)
00170 {
00171 CargoID cargo = graph->GetCargo();
00172 const LinkGraphSettings &settings = graph->GetSettings();
00173
00174 this->accuracy = settings.accuracy;
00175 this->mod_dist = settings.demand_distance;
00176 if (this->mod_dist > 100) {
00177
00178 int over100 = this->mod_dist - 100;
00179 this->mod_dist = 100 + over100 * over100;
00180 }
00181
00182 switch (settings.GetDistributionType(cargo)) {
00183 case DT_SYMMETRIC:
00184 this->CalcDemand<SymmetricScaler>(graph, SymmetricScaler(settings.demand_size));
00185 break;
00186 case DT_ASYMMETRIC:
00187 this->CalcDemand<AsymmetricScaler>(graph, AsymmetricScaler());
00188 break;
00189 default:
00190 NOT_REACHED();
00191 }
00192 }