# demands.cpp

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    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   /* mean acceptance attributed to each node. If the distribution is
    00089    * symmetric this is relative to remote supply, otherwise it is
    00090    * relative to remote demand.
    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           /* only one node with supply and demand left */
    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       /* scale the distance by mod_dist around max_distance */
    00120       int32 distance = this->max_distance - (this->max_distance -
    00121           (int32)graph->GetEdge(node1, node2).distance) * this->mod_dist / 100;
    00122
    00123       /* scale the accuracy by distance around accuracy / 2 */
    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         /* at first only distribute demand if
    00132          * effective supply / accuracy divisor >= 1
    00133          * Others are too small or too far away to be considered.
    00134          */
    00135         demand_forw = supply / divisor;
    00136       } else if (++chance > this->accuracy * num_demands * num_supplies) {
    00137         /* After some trying, if there is still supply left, distribute
    00138          * demand also to other nodes.
    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     /* increase effect of mod_dist > 100 */
    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 }