1 /* $Id: linkgraph.cpp 26411 2014-03-17 20:33:26Z fonsinchen $ */
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/>.
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
)
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
)
32 this->demand
= demand
;
34 this->last_update
= INVALID_DATE
;
40 inline void LinkGraph::BaseEdge::Init()
44 this->last_unrestricted_update
= INVALID_DATE
;
45 this->last_restricted_update
= INVALID_DATE
;
46 this->next_edge
= INVALID_NODE
;
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);
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
;
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
];
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
;
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
) {
178 this->edges
[i
][new_node
].Init();
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
;
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
);
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
];
231 edge
.last_unrestricted_update
= INVALID_DATE
;
232 edge
.last_restricted_update
= INVALID_DATE
;
235 NodeID prev
= this->index
;
236 NodeID next
= this->edges
[this->index
].next_edge
;
237 while (next
!= INVALID_NODE
) {
239 /* Will be removed, skip it. */
240 this->edges
[prev
].next_edge
= edge
.next_edge
;
241 edge
.next_edge
= INVALID_NODE
;
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
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();