Fix incorrect tile and trackdir in reserve through program execution
[openttd-joker.git] / src / linkgraph / linkgraph.cpp
blob47ceef76ea290ded0a565c67f671d5badd7fa772
1 /* $Id: linkgraph.cpp 26411 2014-03-17 20:33:26Z fonsinchen $ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file linkgraph.cpp Definition of link graph classes used for cargo distribution. */
12 #include "../stdafx.h"
13 #include "../core/pool_func.hpp"
14 #include "linkgraph.h"
16 #include "../safeguards.h"
18 /* Initialize the link-graph-pool */
19 LinkGraphPool _link_graph_pool("LinkGraph");
20 INSTANTIATE_POOL_METHODS(LinkGraph)
22 /**
23 * Create a node or clear it.
24 * @param xy Location of the associated station.
25 * @param st ID of the associated station.
26 * @param demand Demand for cargo at the station.
28 inline void LinkGraph::BaseNode::Init(TileIndex xy, StationID st, uint demand)
30 this->xy = xy;
31 this->supply = 0;
32 this->demand = demand;
33 this->station = st;
34 this->last_update = INVALID_DATE;
37 /**
38 * Create an edge.
40 inline void LinkGraph::BaseEdge::Init()
42 this->capacity = 0;
43 this->usage = 0;
44 this->last_unrestricted_update = INVALID_DATE;
45 this->last_restricted_update = INVALID_DATE;
46 this->next_edge = INVALID_NODE;
49 /**
50 * Shift all dates by given interval.
51 * This is useful if the date has been modified with the cheat menu.
52 * @param interval Number of days to be added or subtracted.
54 void LinkGraph::ShiftDates(int interval)
56 this->last_compression += interval;
57 for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
58 BaseNode &source = this->nodes[node1];
59 if (source.last_update != INVALID_DATE) source.last_update += interval;
60 for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
61 BaseEdge &edge = this->edges[node1][node2];
62 if (edge.last_unrestricted_update != INVALID_DATE) edge.last_unrestricted_update += interval;
63 if (edge.last_restricted_update != INVALID_DATE) edge.last_restricted_update += interval;
68 void LinkGraph::Compress()
70 this->last_compression = (_date + this->last_compression) / 2;
71 for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
72 this->nodes[node1].supply /= 2;
73 for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
74 BaseEdge &edge = this->edges[node1][node2];
75 if (edge.capacity > 0) {
76 edge.capacity = max(1U, edge.capacity / 2);
77 edge.usage /= 2;
83 /**
84 * Merge a link graph with another one.
85 * @param other LinkGraph to be merged into this one.
87 void LinkGraph::Merge(LinkGraph *other)
89 Date age = _date - this->last_compression + 1;
90 Date other_age = _date - other->last_compression + 1;
91 NodeID first = this->Size();
92 for (NodeID node1 = 0; node1 < other->Size(); ++node1) {
93 Station *st = Station::Get(other->nodes[node1].station);
94 NodeID new_node = this->AddNode(st);
95 this->nodes[new_node].supply = LinkGraph::Scale(other->nodes[node1].supply, age, other_age);
96 st->goods[this->cargo].link_graph = this->index;
97 st->goods[this->cargo].node = new_node;
98 for (NodeID node2 = 0; node2 < node1; ++node2) {
99 BaseEdge &forward = this->edges[new_node][first + node2];
100 BaseEdge &backward = this->edges[first + node2][new_node];
101 forward = other->edges[node1][node2];
102 backward = other->edges[node2][node1];
103 forward.capacity = LinkGraph::Scale(forward.capacity, age, other_age);
104 forward.usage = LinkGraph::Scale(forward.usage, age, other_age);
105 if (forward.next_edge != INVALID_NODE) forward.next_edge += first;
106 backward.capacity = LinkGraph::Scale(backward.capacity, age, other_age);
107 backward.usage = LinkGraph::Scale(backward.usage, age, other_age);
108 if (backward.next_edge != INVALID_NODE) backward.next_edge += first;
110 BaseEdge &new_start = this->edges[new_node][new_node];
111 new_start = other->edges[node1][node1];
112 if (new_start.next_edge != INVALID_NODE) new_start.next_edge += first;
114 delete other;
118 * Remove a node from the link graph by overwriting it with the last node.
119 * @param id ID of the node to be removed.
121 void LinkGraph::RemoveNode(NodeID id)
123 assert(id < this->Size());
125 NodeID last_node = this->Size() - 1;
126 for (NodeID i = 0; i <= last_node; ++i) {
127 (*this)[i].RemoveEdge(id);
128 BaseEdge *node_edges = this->edges[i];
129 NodeID prev = i;
130 NodeID next = node_edges[i].next_edge;
131 while (next != INVALID_NODE) {
132 if (next == last_node) {
133 node_edges[prev].next_edge = id;
134 break;
136 prev = next;
137 next = node_edges[prev].next_edge;
139 node_edges[id] = node_edges[last_node];
141 Station::Get(this->nodes[last_node].station)->goods[this->cargo].node = id;
142 this->nodes.Erase(this->nodes.Get(id));
143 this->edges.EraseColumn(id);
144 /* Not doing EraseRow here, as having the extra invalid row doesn't hurt
145 * and removing it would trigger a lot of memmove. The data has already
146 * been copied around in the loop above. */
150 * Add a node to the component and create empty edges associated with it. Set
151 * the station's last_component to this component. Calculate the distances to all
152 * other nodes. The distances to _all_ nodes are important as the demand
153 * calculator relies on their availability.
154 * @param st New node's station.
155 * @return New node's ID.
157 NodeID LinkGraph::AddNode(const Station *st)
159 const GoodsEntry &good = st->goods[this->cargo];
161 NodeID new_node = this->Size();
162 this->nodes.Append();
163 /* Avoid reducing the height of the matrix as that is expensive and we
164 * most likely will increase it again later which is again expensive. */
165 this->edges.Resize(new_node + 1U,
166 max(new_node + 1U, this->edges.Height()));
168 this->nodes[new_node].Init(st->xy, st->index,
169 HasBit(good.status, GoodsEntry::GES_ACCEPTANCE));
171 BaseEdge *new_edges = this->edges[new_node];
173 /* Reset the first edge starting at the new node */
174 new_edges[new_node].next_edge = INVALID_NODE;
176 for (NodeID i = 0; i <= new_node; ++i) {
177 new_edges[i].Init();
178 this->edges[i][new_node].Init();
180 return new_node;
184 * Fill an edge with values from a link. Set the restricted or unrestricted
185 * update timestamp according to the given update mode.
186 * @param to Destination node of the link.
187 * @param capacity Capacity of the link.
188 * @param usage Usage to be added.
189 * @param mode Update mode to be used.
191 void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode)
193 assert(this->index != to);
194 BaseEdge &edge = this->edges[to];
195 BaseEdge &first = this->edges[this->index];
196 edge.capacity = capacity;
197 edge.usage = usage;
198 edge.next_edge = first.next_edge;
199 first.next_edge = to;
200 if (mode & EUM_UNRESTRICTED) edge.last_unrestricted_update = _date;
201 if (mode & EUM_RESTRICTED) edge.last_restricted_update = _date;
205 * Creates an edge if none exists yet or updates an existing edge.
206 * @param to Target node.
207 * @param capacity Capacity of the link.
208 * @param usage Usage to be added.
209 * @param mode Update mode to be used.
211 void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode)
213 assert(capacity > 0);
214 assert(usage <= capacity);
215 if (this->edges[to].capacity == 0) {
216 this->AddEdge(to, capacity, usage, mode);
217 } else {
218 (*this)[to].Update(capacity, usage, mode);
223 * Remove an outgoing edge from this node.
224 * @param to ID of destination node.
226 void LinkGraph::Node::RemoveEdge(NodeID to)
228 if (this->index == to) return;
229 BaseEdge &edge = this->edges[to];
230 edge.capacity = 0;
231 edge.last_unrestricted_update = INVALID_DATE;
232 edge.last_restricted_update = INVALID_DATE;
233 edge.usage = 0;
235 NodeID prev = this->index;
236 NodeID next = this->edges[this->index].next_edge;
237 while (next != INVALID_NODE) {
238 if (next == to) {
239 /* Will be removed, skip it. */
240 this->edges[prev].next_edge = edge.next_edge;
241 edge.next_edge = INVALID_NODE;
242 break;
243 } else {
244 prev = next;
245 next = this->edges[next].next_edge;
251 * Update an edge. If mode contains UM_REFRESH refresh the edge to have at
252 * least the given capacity and usage, otherwise add the capacity and usage.
253 * In any case set the respective update timestamp(s), according to the given
254 * mode.
255 * @param from Start node of the edge.
256 * @param to End node of the edge.
257 * @param capacity Capacity to be added/updated.
258 * @param usage Usage to be added.
259 * @param mode Update mode to be applied.
261 void LinkGraph::Edge::Update(uint capacity, uint usage, EdgeUpdateMode mode)
263 assert(this->edge.capacity > 0);
264 assert(capacity >= usage);
266 if (mode & EUM_INCREASE) {
267 this->edge.capacity += capacity;
268 this->edge.usage += usage;
269 } else if (mode & EUM_REFRESH) {
270 this->edge.capacity = max(this->edge.capacity, capacity);
271 this->edge.usage = max(this->edge.usage, usage);
273 if (mode & EUM_UNRESTRICTED) this->edge.last_unrestricted_update = _date;
274 if (mode & EUM_RESTRICTED) this->edge.last_restricted_update = _date;
278 * Resize the component and fill it with empty nodes and edges. Used when
279 * loading from save games. The component is expected to be empty before.
280 * @param size New size of the component.
282 void LinkGraph::Init(uint size)
284 assert(this->Size() == 0);
285 this->edges.Resize(size, size);
286 this->nodes.Resize(size);
288 for (uint i = 0; i < size; ++i) {
289 this->nodes[i].Init();
290 BaseEdge *column = this->edges[i];
291 for (uint j = 0; j < size; ++j) column[j].Init();