# demands.cpp

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(LinkGraphComponent *graph, NodeID from_id, NodeID to_id, uint demand_forw)
    00023 {
    00024   if (graph->GetNode(from_id).demand > 0) {
    00025     uint demand_back = demand_forw * this->mod_size / 100;
    00026     uint undelivered = graph->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(graph, to_id, from_id, demand_back);
    00032   }
    00033
    00034   this->Scaler::SetDemands(graph, from_id, to_id, demand_forw);
    00035 }
    00036
    00045 inline void Scaler::SetDemands(LinkGraphComponent *graph, NodeID from_id, NodeID to_id, uint demand_forw)
    00046 {
    00047   Edge &forward = graph->GetEdge(from_id, to_id);
    00048   forward.demand += demand_forw;
    00049   forward.unsatisfied_demand += demand_forw;
    00050   graph->GetNode(from_id).undelivered_supply -= demand_forw;
    00051 }
    00052
    00057 template<class Tscaler>
    00058 void DemandCalculator::CalcDemand(LinkGraphComponent *graph, Tscaler scaler)
    00059 {
    00060   NodeList supplies;
    00061   NodeList demands;
    00062   uint num_supplies = 0;
    00063   uint num_demands = 0;
    00064
    00065   for (NodeID node = 0; node < graph->GetSize(); node++) {
    00066     Node &n = graph->GetNode(node);
    00067     scaler.AddNode(n);
    00068     if (n.supply > 0) {
    00069       supplies.push_back(node);
    00070       num_supplies++;
    00071     }
    00072     if (n.demand > 0) {
    00073       demands.push_back(node);
    00074       num_demands++;
    00075     }
    00076   }
    00077
    00078   if (num_supplies == 0 || num_demands == 0) return;
    00079
    00080   /* Mean acceptance attributed to each node. If the distribution is
    00081    * symmetric this is relative to remote supply, otherwise it is
    00082    * relative to remote demand. */
    00083   scaler.SetDemandPerNode(num_demands);
    00084   uint chance = 0;
    00085
    00086   while (!supplies.empty() && !demands.empty()) {
    00087     NodeID from_id = supplies.front();
    00088     supplies.pop_front();
    00089
    00090     Node &from = graph->GetNode(from_id);
    00091
    00092     for (uint i = 0; i < num_demands; ++i) {
    00093       assert(!demands.empty());
    00094       NodeID to_id = demands.front();
    00095       demands.pop_front();
    00096       if (from_id == to_id) {
    00097         /* Only one node with supply and demand left */
    00098         if (demands.empty() && supplies.empty()) return;
    00099
    00100         demands.push_back(to_id);
    00101         continue;
    00102       }
    00103       Node &to = graph->GetNode(to_id);
    00104
    00105       int32 supply = scaler.EffectiveSupply(from, to);
    00106       assert(supply > 0);
    00107
    00108       /* Scale the distance by mod_dist around max_distance */
    00109       int32 distance = this->max_distance - (this->max_distance -
    00110           (int32)graph->GetEdge(from_id, to_id).distance) * this->mod_dist / 100;
    00111
    00112       /* Scale the accuracy by distance around accuracy / 2 */
    00113       int32 divisor = this->accuracy * (this->mod_dist - 50) / 100 +
    00114           this->accuracy * distance / this->max_distance + 1;
    00115
    00116       assert(divisor > 0);
    00117
    00118       uint demand_forw = 0;
    00119       if (divisor <= supply) {
    00120         /* At first only distribute demand if
    00121          * effective supply / accuracy divisor >= 1
    00122          * Others are too small or too far away to be considered. */
    00123         demand_forw = supply / divisor;
    00124       } else if (++chance > this->accuracy * num_demands * num_supplies) {
    00125         /* After some trying, if there is still supply left, distribute
    00126          * demand also to other nodes. */
    00127         demand_forw = 1;
    00128       }
    00129
    00130       demand_forw = min(demand_forw, from.undelivered_supply);
    00131
    00132       scaler.SetDemands(graph, from_id, to_id, demand_forw);
    00133
    00134       if (scaler.HasDemandLeft(to)) {
    00135         demands.push_back(to_id);
    00136       } else {
    00137         num_demands--;
    00138       }
    00139
    00140       if (from.undelivered_supply == 0) break;
    00141     }
    00142
    00143     if (from.undelivered_supply != 0) {
    00144       supplies.push_back(from_id);
    00145     } else {
    00146       num_supplies--;
    00147     }
    00148   }
    00149 }
    00150
    00155 DemandCalculator::DemandCalculator(LinkGraphComponent *graph) :
    00156   max_distance(MapSizeX() + MapSizeY() - 2)
    00157 {
    00158   CargoID cargo = graph->GetCargo();
    00159   const LinkGraphSettings &settings = graph->GetSettings();
    00160
    00161   this->accuracy = settings.accuracy;
    00162   this->mod_dist = settings.demand_distance;
    00163   if (this->mod_dist > 100) {
    00164     /* Increase effect of mod_dist > 100 */
    00165     int over100 = this->mod_dist - 100;
    00166     this->mod_dist = 100 + over100 * over100;
    00167   }
    00168
    00169   switch (settings.GetDistributionType(cargo)) {
    00170     case DT_SYMMETRIC:
    00171       this->CalcDemand<SymmetricScaler>(graph, SymmetricScaler(settings.demand_size));
    00172       break;
    00173     case DT_ASYMMETRIC:
    00174       this->CalcDemand<AsymmetricScaler>(graph, AsymmetricScaler());
    00175       break;
    00176     default:
    00177       NOT_REACHED();
    00178       break;
    00179   }
    00180 }