# 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
    00046 void LinkGraph::Compress()
    00047 {
    00048   this->last_compression = (_date + this->last_compression) / 2;
    00049   for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
    00050     this->nodes[node1].supply /= 2;
    00051     for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
    00052       BaseEdge &edge = this->edges[node1][node2];
    00053       if (edge.capacity > 0) {
    00054         edge.capacity = max(1U, edge.capacity / 2);
    00055         edge.usage /= 2;
    00056       }
    00057     }
    00058   }
    00059 }
    00060
    00065 void LinkGraph::Merge(LinkGraph *other)
    00066 {
    00067   Date age = _date - this->last_compression + 1;
    00068   Date other_age = _date - other->last_compression + 1;
    00069   NodeID first = this->Size();
    00070   for (NodeID node1 = 0; node1 < other->Size(); ++node1) {
    00071     Station *st = Station::Get(other->nodes[node1].station);
    00072     NodeID new_node = this->AddNode(st);
    00073     this->nodes[new_node].supply = LinkGraph::Scale(other->nodes[node1].supply, age, other_age);
    00074     st->goods[this->cargo].link_graph = this->index;
    00075     st->goods[this->cargo].node = new_node;
    00076     for (NodeID node2 = 0; node2 < node1; ++node2) {
    00077       BaseEdge &forward = this->edges[new_node][first + node2];
    00078       BaseEdge &backward = this->edges[first + node2][new_node];
    00079       forward = other->edges[node1][node2];
    00080       backward = other->edges[node2][node1];
    00081       forward.capacity = LinkGraph::Scale(forward.capacity, age, other_age);
    00082       forward.usage = LinkGraph::Scale(forward.usage, age, other_age);
    00083       if (forward.next_edge != INVALID_NODE) forward.next_edge += first;
    00084       backward.capacity = LinkGraph::Scale(backward.capacity, age, other_age);
    00085       backward.usage = LinkGraph::Scale(backward.usage, age, other_age);
    00086       if (backward.next_edge != INVALID_NODE) backward.next_edge += first;
    00087     }
    00088     BaseEdge &new_start = this->edges[new_node][new_node];
    00089     new_start = other->edges[node1][node1];
    00090     if (new_start.next_edge != INVALID_NODE) new_start.next_edge += first;
    00091   }
    00092   delete other;
    00093 }
    00094
    00099 void LinkGraph::RemoveNode(NodeID id)
    00100 {
    00101   assert(id < this->Size());
    00102
    00103   NodeID last_node = this->Size() - 1;
    00104   for (NodeID i = 0; i <= last_node; ++i) {
    00105     (*this)[i].RemoveEdge(id);
    00106     BaseEdge *node_edges = this->edges[i];
    00107     NodeID prev = i;
    00108     NodeID next = node_edges[i].next_edge;
    00109     while (next != INVALID_NODE) {
    00110       if (next == last_node) {
    00111         node_edges[prev].next_edge = id;
    00112         break;
    00113       }
    00114       prev = next;
    00115       next = node_edges[prev].next_edge;
    00116     }
    00117     node_edges[id] = node_edges[last_node];
    00118   }
    00119   Station::Get(this->nodes[last_node].station)->goods[this->cargo].node = id;
    00120   this->nodes.Erase(this->nodes.Get(id));
    00121   this->edges.EraseColumn(id);
    00122   /* Not doing EraseRow here, as having the extra invalid row doesn't hurt
    00123    * and removing it would trigger a lot of memmove. The data has already
    00124    * been copied around in the loop above. */
    00125 }
    00126
    00135 NodeID LinkGraph::AddNode(const Station *st)
    00136 {
    00137   const GoodsEntry &good = st->goods[this->cargo];
    00138
    00139   NodeID new_node = this->Size();
    00140   this->nodes.Append();
    00141   /* Avoid reducing the height of the matrix as that is expensive and we
    00142    * most likely will increase it again later which is again expensive. */
    00143   this->edges.Resize(new_node + 1U,
    00144       max(new_node + 1U, this->edges.Height()));
    00145
    00146   this->nodes[new_node].Init(st->index,
    00147       HasBit(good.acceptance_pickup, GoodsEntry::GES_ACCEPTANCE));
    00148
    00149   BaseEdge *new_edges = this->edges[new_node];
    00150
    00151   /* Reset the first edge starting at the new node */
    00152   new_edges[new_node].next_edge = INVALID_NODE;
    00153
    00154   for (NodeID i = 0; i <= new_node; ++i) {
    00155     uint distance = DistanceManhattan(st->xy, Station::Get(this->nodes[i].station)->xy);
    00156     new_edges[i].Init(distance);
    00157     this->edges[i][new_node].Init(distance);
    00158   }
    00159   return new_node;
    00160 }
    00161
    00167 void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage)
    00168 {
    00169   assert(this->index != to);
    00170   BaseEdge &edge = this->edges[to];
    00171   BaseEdge &first = this->edges[this->index];
    00172   edge.capacity = capacity;
    00173   edge.usage = usage == UINT_MAX ? 0 : usage;
    00174   edge.next_edge = first.next_edge;
    00175   first.next_edge = to;
    00176   edge.last_update = _date;
    00177 }
    00178
    00179 void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage)
    00180 {
    00181   assert(capacity > 0);
    00182   assert(usage <= capacity || usage == UINT_MAX);
    00183   if (this->edges[to].last_update == INVALID_DATE) {
    00184     this->AddEdge(to, capacity, usage);
    00185   } else {
    00186     (*this)[to].Update(capacity, usage);
    00187   }
    00188 }
    00189
    00194 void LinkGraph::Node::RemoveEdge(NodeID to)
    00195 {
    00196   if (this->index == to) return;
    00197   BaseEdge &edge = this->edges[to];
    00198   edge.capacity = 0;
    00199   edge.last_update = INVALID_DATE;
    00200   edge.usage = 0;
    00201
    00202   NodeID prev = this->index;
    00203   NodeID next = this->edges[this->index].next_edge;
    00204   while (next != INVALID_NODE) {
    00205     if (next == to) {
    00206       /* Will be removed, skip it. */
    00207       next = this->edges[prev].next_edge = edge.next_edge;
    00208       break;
    00209     } else {
    00210       prev = next;
    00211       next = this->edges[next].next_edge;
    00212     }
    00213   }
    00214 }
    00215
    00224 void LinkGraph::Edge::Update(uint capacity, uint usage)
    00225 {
    00226   assert(this->edge.capacity > 0);
    00227   if (usage == UINT_MAX) {
    00228     this->edge.capacity = max(this->edge.capacity, capacity);
    00229   } else {
    00230     assert(capacity >= usage);
    00231     this->edge.capacity += capacity;
    00232     this->edge.usage += usage;
    00233   }
    00234   this->edge.last_update = _date;
    00235 }
    00236
    00242 void LinkGraph::Init(uint size)
    00243 {
    00244   assert(this->Size() == 0);
    00245   this->edges.Resize(size, size);
    00246   this->nodes.Resize(size);
    00247
    00248   for (uint i = 0; i < size; ++i) {
    00249     this->nodes[i].Init();
    00250     BaseEdge *column = this->edges[i];
    00251     for (uint j = 0; j < size; ++j) column[j].Init();
    00252   }
    00253 }