linkgraph.cpp

Go to the documentation of this file.
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 "../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_update = INVALID_DATE;
00043   this->next_edge = INVALID_NODE;
00044 }
00045 
00051 void LinkGraph::ShiftDates(int interval)
00052 {
00053   this->last_compression += interval;
00054   for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
00055     BaseNode &source = this->nodes[node1];
00056     if (source.last_update != INVALID_DATE) source.last_update += interval;
00057     for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
00058       BaseEdge &edge = this->edges[node1][node2];
00059       if (edge.last_update != INVALID_DATE) edge.last_update += interval;
00060     }
00061   }
00062 }
00063 
00064 void LinkGraph::Compress()
00065 {
00066   this->last_compression = (_date + this->last_compression) / 2;
00067   for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
00068     this->nodes[node1].supply /= 2;
00069     for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
00070       BaseEdge &edge = this->edges[node1][node2];
00071       if (edge.capacity > 0) {
00072         edge.capacity = max(1U, edge.capacity / 2);
00073         edge.usage /= 2;
00074       }
00075     }
00076   }
00077 }
00078 
00083 void LinkGraph::Merge(LinkGraph *other)
00084 {
00085   Date age = _date - this->last_compression + 1;
00086   Date other_age = _date - other->last_compression + 1;
00087   NodeID first = this->Size();
00088   for (NodeID node1 = 0; node1 < other->Size(); ++node1) {
00089     Station *st = Station::Get(other->nodes[node1].station);
00090     NodeID new_node = this->AddNode(st);
00091     this->nodes[new_node].supply = LinkGraph::Scale(other->nodes[node1].supply, age, other_age);
00092     st->goods[this->cargo].link_graph = this->index;
00093     st->goods[this->cargo].node = new_node;
00094     for (NodeID node2 = 0; node2 < node1; ++node2) {
00095       BaseEdge &forward = this->edges[new_node][first + node2];
00096       BaseEdge &backward = this->edges[first + node2][new_node];
00097       forward = other->edges[node1][node2];
00098       backward = other->edges[node2][node1];
00099       forward.capacity = LinkGraph::Scale(forward.capacity, age, other_age);
00100       forward.usage = LinkGraph::Scale(forward.usage, age, other_age);
00101       if (forward.next_edge != INVALID_NODE) forward.next_edge += first;
00102       backward.capacity = LinkGraph::Scale(backward.capacity, age, other_age);
00103       backward.usage = LinkGraph::Scale(backward.usage, age, other_age);
00104       if (backward.next_edge != INVALID_NODE) backward.next_edge += first;
00105     }
00106     BaseEdge &new_start = this->edges[new_node][new_node];
00107     new_start = other->edges[node1][node1];
00108     if (new_start.next_edge != INVALID_NODE) new_start.next_edge += first;
00109   }
00110   delete other;
00111 }
00112 
00117 void LinkGraph::RemoveNode(NodeID id)
00118 {
00119   assert(id < this->Size());
00120 
00121   NodeID last_node = this->Size() - 1;
00122   for (NodeID i = 0; i <= last_node; ++i) {
00123     (*this)[i].RemoveEdge(id);
00124     BaseEdge *node_edges = this->edges[i];
00125     NodeID prev = i;
00126     NodeID next = node_edges[i].next_edge;
00127     while (next != INVALID_NODE) {
00128       if (next == last_node) {
00129         node_edges[prev].next_edge = id;
00130         break;
00131       }
00132       prev = next;
00133       next = node_edges[prev].next_edge;
00134     }
00135     node_edges[id] = node_edges[last_node];
00136   }
00137   Station::Get(this->nodes[last_node].station)->goods[this->cargo].node = id;
00138   this->nodes.Erase(this->nodes.Get(id));
00139   this->edges.EraseColumn(id);
00140   /* Not doing EraseRow here, as having the extra invalid row doesn't hurt
00141    * and removing it would trigger a lot of memmove. The data has already
00142    * been copied around in the loop above. */
00143 }
00144 
00153 NodeID LinkGraph::AddNode(const Station *st)
00154 {
00155   const GoodsEntry &good = st->goods[this->cargo];
00156 
00157   NodeID new_node = this->Size();
00158   this->nodes.Append();
00159   /* Avoid reducing the height of the matrix as that is expensive and we
00160    * most likely will increase it again later which is again expensive. */
00161   this->edges.Resize(new_node + 1U,
00162       max(new_node + 1U, this->edges.Height()));
00163 
00164   this->nodes[new_node].Init(st->index,
00165       HasBit(good.acceptance_pickup, GoodsEntry::GES_ACCEPTANCE));
00166 
00167   BaseEdge *new_edges = this->edges[new_node];
00168 
00169   /* Reset the first edge starting at the new node */
00170   new_edges[new_node].next_edge = INVALID_NODE;
00171 
00172   for (NodeID i = 0; i <= new_node; ++i) {
00173     uint distance = DistanceManhattan(st->xy, Station::Get(this->nodes[i].station)->xy);
00174     new_edges[i].Init(distance);
00175     this->edges[i][new_node].Init(distance);
00176   }
00177   return new_node;
00178 }
00179 
00185 void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage)
00186 {
00187   assert(this->index != to);
00188   BaseEdge &edge = this->edges[to];
00189   BaseEdge &first = this->edges[this->index];
00190   edge.capacity = capacity;
00191   edge.usage = usage == UINT_MAX ? 0 : usage;
00192   edge.next_edge = first.next_edge;
00193   first.next_edge = to;
00194   edge.last_update = _date;
00195 }
00196 
00197 void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage)
00198 {
00199   assert(capacity > 0);
00200   assert(usage <= capacity || usage == UINT_MAX);
00201   if (this->edges[to].last_update == INVALID_DATE) {
00202     this->AddEdge(to, capacity, usage);
00203   } else {
00204     (*this)[to].Update(capacity, usage);
00205   }
00206 }
00207 
00212 void LinkGraph::Node::RemoveEdge(NodeID to)
00213 {
00214   if (this->index == to) return;
00215   BaseEdge &edge = this->edges[to];
00216   edge.capacity = 0;
00217   edge.last_update = INVALID_DATE;
00218   edge.usage = 0;
00219 
00220   NodeID prev = this->index;
00221   NodeID next = this->edges[this->index].next_edge;
00222   while (next != INVALID_NODE) {
00223     if (next == to) {
00224       /* Will be removed, skip it. */
00225       this->edges[prev].next_edge = edge.next_edge;
00226       edge.next_edge = INVALID_NODE;
00227       break;
00228     } else {
00229       prev = next;
00230       next = this->edges[next].next_edge;
00231     }
00232   }
00233 }
00234 
00243 void LinkGraph::Edge::Update(uint capacity, uint usage)
00244 {
00245   assert(this->edge.capacity > 0);
00246   if (usage == UINT_MAX) {
00247     this->edge.capacity = max(this->edge.capacity, capacity);
00248   } else {
00249     assert(capacity >= usage);
00250     this->edge.capacity += capacity;
00251     this->edge.usage += usage;
00252   }
00253   this->edge.last_update = _date;
00254 }
00255 
00261 void LinkGraph::Init(uint size)
00262 {
00263   assert(this->Size() == 0);
00264   this->edges.Resize(size, size);
00265   this->nodes.Resize(size);
00266 
00267   for (uint i = 0; i < size; ++i) {
00268     this->nodes[i].Init();
00269     BaseEdge *column = this->edges[i];
00270     for (uint j = 0; j < size; ++j) column[j].Init();
00271   }
00272 }