# demands.cpp

    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    */
    00084   scaler.SetDemandPerNode(num_demands);
    00085   uint chance = 0;
    00086
    00087   while (!supplies.empty() && !demands.empty()) {
    00088     NodeID node1 = supplies.front();
    00089     supplies.pop_front();
    00090
    00091     Node &from = graph->GetNode(node1);
    00092
    00093     for (uint i = 0; i < num_demands; ++i) {
    00094       assert(!demands.empty());
    00095       NodeID node2 = demands.front();
    00096       demands.pop_front();
    00097       if (node1 == node2) {
    00098         if (demands.empty() && supplies.empty()) {
    00099           /* only one node with supply and demand left */
    00100           return;
    00101         } else {
    00102           demands.push_back(node2);
    00103           continue;
    00104         }
    00105       }
    00106       Node &to = graph->GetNode(node2);
    00107
    00108       int32 supply = scaler.EffectiveSupply(from, to);
    00109       assert(supply > 0);
    00110
    00111       /* scale the distance by mod_dist around max_distance */
    00112       int32 distance = this->max_distance - (this->max_distance -
    00113           (int32)graph->GetEdge(node1, node2).distance) * this->mod_dist / 100;
    00114
    00115       /* scale the accuracy by distance around accuracy / 2 */
    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         /* at first only distribute demand if
    00124          * effective supply / accuracy divisor >= 1
    00125          * Others are too small or too far away to be considered.
    00126          */
    00127         demand_forw = supply / divisor;
    00128       } else if (++chance > this->accuracy * num_demands * num_supplies) {
    00129         /* After some trying, if there is still supply left, distribute
    00130          * demand also to other nodes.
    00131          */
    00132         demand_forw = 1;
    00133       }
    00134
    00135       demand_forw = min(demand_forw, from.undelivered_supply);
    00136
    00137       scaler.SetDemands(graph, node1, node2, demand_forw);
    00138
    00139       if (scaler.DemandLeft(to)) {
    00140         demands.push_back(node2);
    00141       } else {
    00142         num_demands--;
    00143       }
    00144
    00145       if (from.undelivered_supply == 0) break;
    00146
    00147     }
    00148     if (from.undelivered_supply != 0) {
    00149       supplies.push_back(node1);
    00150     } else {
    00151       num_supplies--;
    00152     }
    00153   }
    00154 }
    00155
    00160 DemandCalculator::DemandCalculator(LinkGraphComponent *graph) :
    00161   max_distance(MapSizeX() + MapSizeY() + 1)
    00162 {
    00163   CargoID cargo = graph->GetCargo();
    00164   const LinkGraphSettings &settings = graph->GetSettings();
    00165
    00166   this->accuracy = settings.accuracy;
    00167   this->mod_dist = settings.demand_distance;
    00168   if (this->mod_dist > 100) {
    00169     /* increase effect of mod_dist > 100 */
    00170     int over100 = this->mod_dist - 100;
    00171     this->mod_dist = 100 + over100 * over100;
    00172   }
    00173
    00174   switch (settings.GetDistributionType(cargo)) {
    00175     case DT_SYMMETRIC:
    00176       this->CalcDemand<SymmetricScaler>(graph, SymmetricScaler(settings.demand_size));
    00177       break;
    00178     case DT_ASYMMETRIC:
    00179       this->CalcDemand<AsymmetricScaler>(graph, AsymmetricScaler());
    00180       break;
    00181     default:
    00182       NOT_REACHED();
    00183       break;
    00184   }
    00185 }