linkgraph.cpp

Go to the documentation of this file.
00001 /* $Id: linkgraph.cpp 26460 2014-04-13 10:47:39Z frosch $ */
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 "../stdafx.h"
00013 #include "../core/pool_func.hpp"
00014 #include "linkgraph.h"
00015 
00016 /* Initialize the link-graph-pool */
00017 LinkGraphPool _link_graph_pool("LinkGraph");
00018 INSTANTIATE_POOL_METHODS(LinkGraph)
00019 
00020 
00025 inline void LinkGraph::BaseNode::Init(StationID st, uint demand)
00026 {
00027   this->supply = 0;
00028   this->demand = demand;
00029   this->station = st;
00030   this->last_update = INVALID_DATE;
00031 }
00032 
00037 inline void LinkGraph::BaseEdge::Init(uint distance)
00038 {
00039   this->distance = distance;
00040   this->capacity = 0;
00041   this->usage = 0;
00042   this->last_unrestricted_update = INVALID_DATE;
00043   this->last_restricted_update = INVALID_DATE;
00044   this->next_edge = INVALID_NODE;
00045 }
00046 
00052 void LinkGraph::ShiftDates(int interval)
00053 {
00054   this->last_compression += interval;
00055   for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
00056     BaseNode &source = this->nodes[node1];
00057     if (source.last_update != INVALID_DATE) source.last_update += interval;
00058     for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
00059       BaseEdge &edge = this->edges[node1][node2];
00060       if (edge.last_unrestricted_update != INVALID_DATE) edge.last_unrestricted_update += interval;
00061       if (edge.last_restricted_update != INVALID_DATE) edge.last_restricted_update += interval;
00062     }
00063   }
00064 }
00065 
00066 void LinkGraph::Compress()
00067 {
00068   this->last_compression = (_date + this->last_compression) / 2;
00069   for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
00070     this->nodes[node1].supply /= 2;
00071     for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
00072       BaseEdge &edge = this->edges[node1][node2];
00073       if (edge.capacity > 0) {
00074         edge.capacity = max(1U, edge.capacity / 2);
00075         edge.usage /= 2;
00076       }
00077     }
00078   }
00079 }
00080 
00085 void LinkGraph::Merge(LinkGraph *other)
00086 {
00087   Date age = _date - this->last_compression + 1;
00088   Date other_age = _date - other->last_compression + 1;
00089   NodeID first = this->Size();
00090   for (NodeID node1 = 0; node1 < other->Size(); ++node1) {
00091     Station *st = Station::Get(other->nodes[node1].station);
00092     NodeID new_node = this->AddNode(st);
00093     this->nodes[new_node].supply = LinkGraph::Scale(other->nodes[node1].supply, age, other_age);
00094     st->goods[this->cargo].link_graph = this->index;
00095     st->goods[this->cargo].node = new_node;
00096     for (NodeID node2 = 0; node2 < node1; ++node2) {
00097       BaseEdge &forward = this->edges[new_node][first + node2];
00098       BaseEdge &backward = this->edges[first + node2][new_node];
00099       forward = other->edges[node1][node2];
00100       backward = other->edges[node2][node1];
00101       forward.capacity = LinkGraph::Scale(forward.capacity, age, other_age);
00102       forward.usage = LinkGraph::Scale(forward.usage, age, other_age);
00103       if (forward.next_edge != INVALID_NODE) forward.next_edge += first;
00104       backward.capacity = LinkGraph::Scale(backward.capacity, age, other_age);
00105       backward.usage = LinkGraph::Scale(backward.usage, age, other_age);
00106       if (backward.next_edge != INVALID_NODE) backward.next_edge += first;
00107     }
00108     BaseEdge &new_start = this->edges[new_node][new_node];
00109     new_start = other->edges[node1][node1];
00110     if (new_start.next_edge != INVALID_NODE) new_start.next_edge += first;
00111   }
00112   delete other;
00113 }
00114 
00119 void LinkGraph::RemoveNode(NodeID id)
00120 {
00121   assert(id < this->Size());
00122 
00123   NodeID last_node = this->Size() - 1;
00124   for (NodeID i = 0; i <= last_node; ++i) {
00125     (*this)[i].RemoveEdge(id);
00126     BaseEdge *node_edges = this->edges[i];
00127     NodeID prev = i;
00128     NodeID next = node_edges[i].next_edge;
00129     while (next != INVALID_NODE) {
00130       if (next == last_node) {
00131         node_edges[prev].next_edge = id;
00132         break;
00133       }
00134       prev = next;
00135       next = node_edges[prev].next_edge;
00136     }
00137     node_edges[id] = node_edges[last_node];
00138   }
00139   Station::Get(this->nodes[last_node].station)->goods[this->cargo].node = id;
00140   this->nodes.Erase(this->nodes.Get(id));
00141   this->edges.EraseColumn(id);
00142   /* Not doing EraseRow here, as having the extra invalid row doesn't hurt
00143    * and removing it would trigger a lot of memmove. The data has already
00144    * been copied around in the loop above. */
00145 }
00146 
00152 void LinkGraph::UpdateDistances(NodeID id, TileIndex xy)
00153 {
00154   assert(id < this->Size());
00155   for (NodeID other = 0; other < this->Size(); ++other) {
00156     if (other == id) continue;
00157     this->edges[id][other].distance = this->edges[other][id].distance =
00158         DistanceMaxPlusManhattan(xy, Station::Get(this->nodes[other].station)->xy);
00159   }
00160 }
00161 
00170 NodeID LinkGraph::AddNode(const Station *st)
00171 {
00172   const GoodsEntry &good = st->goods[this->cargo];
00173 
00174   NodeID new_node = this->Size();
00175   this->nodes.Append();
00176   /* Avoid reducing the height of the matrix as that is expensive and we
00177    * most likely will increase it again later which is again expensive. */
00178   this->edges.Resize(new_node + 1U,
00179       max(new_node + 1U, this->edges.Height()));
00180 
00181   this->nodes[new_node].Init(st->index,
00182       HasBit(good.acceptance_pickup, GoodsEntry::GES_ACCEPTANCE));
00183 
00184   BaseEdge *new_edges = this->edges[new_node];
00185 
00186   /* Reset the first edge starting at the new node */
00187   new_edges[new_node].next_edge = INVALID_NODE;
00188 
00189   for (NodeID i = 0; i <= new_node; ++i) {
00190     uint distance = DistanceMaxPlusManhattan(st->xy, Station::Get(this->nodes[i].station)->xy);
00191     new_edges[i].Init(distance);
00192     this->edges[i][new_node].Init(distance);
00193   }
00194   return new_node;
00195 }
00196 
00204 void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage)
00205 {
00206   assert(this->index != to);
00207   BaseEdge &edge = this->edges[to];
00208   BaseEdge &first = this->edges[this->index];
00209   edge.capacity = capacity;
00210   edge.next_edge = first.next_edge;
00211   first.next_edge = to;
00212   switch (usage) {
00213     case REFRESH_UNRESTRICTED:
00214       edge.last_unrestricted_update = _date;
00215       break;
00216     case REFRESH_RESTRICTED:
00217       edge.last_restricted_update = _date;
00218       break;
00219     default:
00220       edge.usage = usage;
00221       break;
00222   }
00223 }
00224 
00231 void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage)
00232 {
00233   assert(capacity > 0);
00234   assert(usage <= capacity || usage == REFRESH_RESTRICTED || usage == REFRESH_UNRESTRICTED);
00235   if (this->edges[to].capacity == 0) {
00236     this->AddEdge(to, capacity, usage);
00237   } else {
00238     (*this)[to].Update(capacity, usage);
00239   }
00240 }
00241 
00246 void LinkGraph::Node::RemoveEdge(NodeID to)
00247 {
00248   if (this->index == to) return;
00249   BaseEdge &edge = this->edges[to];
00250   edge.capacity = 0;
00251   edge.last_unrestricted_update = INVALID_DATE;
00252   edge.last_restricted_update = INVALID_DATE;
00253   edge.usage = 0;
00254 
00255   NodeID prev = this->index;
00256   NodeID next = this->edges[this->index].next_edge;
00257   while (next != INVALID_NODE) {
00258     if (next == to) {
00259       /* Will be removed, skip it. */
00260       this->edges[prev].next_edge = edge.next_edge;
00261       edge.next_edge = INVALID_NODE;
00262       break;
00263     } else {
00264       prev = next;
00265       next = this->edges[next].next_edge;
00266     }
00267   }
00268 }
00269 
00279 void LinkGraph::Edge::Update(uint capacity, uint usage)
00280 {
00281   assert(this->edge.capacity > 0);
00282   if (usage > capacity) {
00283     this->edge.capacity = max(this->edge.capacity, capacity);
00284     switch (usage) {
00285       case REFRESH_UNRESTRICTED:
00286         this->edge.last_unrestricted_update = _date;
00287         break;
00288       case REFRESH_RESTRICTED:
00289         this->edge.last_restricted_update = _date;
00290         break;
00291       default:
00292         NOT_REACHED();
00293         break;
00294     }
00295   } else {
00296     this->edge.capacity += capacity;
00297     this->edge.usage += usage;
00298   }
00299 }
00300 
00306 void LinkGraph::Init(uint size)
00307 {
00308   assert(this->Size() == 0);
00309   this->edges.Resize(size, size);
00310   this->nodes.Resize(size);
00311 
00312   for (uint i = 0; i < size; ++i) {
00313     this->nodes[i].Init();
00314     BaseEdge *column = this->edges[i];
00315     for (uint j = 0; j < size; ++j) column[j].Init();
00316   }
00317 }