]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/layout.cpp
Replace various map lookups with functions from maputils.h
[r2c2.git] / source / libr2c2 / layout.cpp
1 #include <algorithm>
2 #include <msp/core/maputils.h>
3 #include <msp/core/refptr.h>
4 #include <msp/datafile/parser.h>
5 #include <msp/datafile/writer.h>
6 #include <msp/io/print.h>
7 #include <msp/time/utils.h>
8 #include "block.h"
9 #include "catalogue.h"
10 #include "driver.h"
11 #include "layout.h"
12 #include "route.h"
13 #include "track.h"
14 #include "tracktype.h"
15 #include "train.h"
16 #include "vehicletype.h"
17 #include "zone.h"
18
19 using namespace std;
20 using namespace Msp;
21
22 namespace {
23
24 bool zone_order(const R2C2::Zone *z1, const R2C2::Zone *z2)
25 {
26         return z1->get_number()<z2->get_number();
27 }
28
29 }
30
31
32 namespace R2C2 {
33
34 Layout::Layout(Catalogue &c, Driver *d):
35         catalogue(c),
36         driver(d),
37         next_turnout_id(0x800)
38 { }
39
40 Layout::~Layout()
41 {
42         delete driver;
43         driver = 0;
44
45         while(!trains.empty())
46                 delete trains.begin()->second;
47         while(!routes.empty())
48                 delete *routes.begin();
49         while(!zones.empty())
50                 delete *zones.begin();
51         while(!tracks.empty())
52                 delete *tracks.begin();
53         while(!blocks.empty())
54                 delete *blocks.begin();
55 }
56
57 Driver &Layout::get_driver() const
58 {
59         if(!driver)
60                 throw InvalidState("No driver");
61         return *driver;
62 }
63
64 void Layout::add_track(Track &t)
65 {
66         if(tracks.insert(&t).second)
67         {
68                 create_blocks();
69                 signal_track_added.emit(t);
70         }
71 }
72
73 void Layout::remove_track(Track &t)
74 {
75         if(tracks.erase(&t))
76         {
77                 create_blocks(t);
78                 signal_track_removed.emit(t);
79         }
80 }
81
82 Track *Layout::pick_track(const Vector &start, const Vector &ray)
83 {
84         for(set<Track *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
85                 if((*i)->collide_ray(start, ray))
86                         return *i;
87
88         return 0;
89 }
90
91 unsigned Layout::allocate_turnout_id()
92 {
93         set<unsigned> used_ids;
94         for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
95                 if((*i)->get_turnout_id())
96                         used_ids.insert((*i)->get_turnout_id());
97
98         unsigned result = next_turnout_id;
99         while(used_ids.count(result))
100                 ++result;
101         next_turnout_id = result+1;
102
103         return result;
104 }
105
106 void Layout::add_block(Block &b)
107 {
108         blocks.insert(&b);
109         b.signal_reserved.connect(sigc::bind<0>(signal_block_reserved, sigc::ref(b)));
110         if(b.get_sensor_id())
111         {
112                 b.signal_state_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Layout::block_state_changed), sigc::ref(b)));
113                 b.signal_state_changed.connect(sigc::bind<0>(signal_block_state_changed, sigc::ref(b)));
114         }
115 }
116
117 Block &Layout::get_block(unsigned id) const
118 {
119         for(set<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
120                 if((*i)->get_id()==id)
121                         return **i;
122
123         throw key_error(id);
124 }
125
126 void Layout::create_blocks()
127 {
128         set<Track *> used_tracks;
129         for(set<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
130         {
131                 const set<Track *> &btracks = (*i)->get_tracks();
132                 used_tracks.insert(btracks.begin(), btracks.end());
133         }
134
135         for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
136                 if(used_tracks.count(*i)==0)
137                 {
138                         Block *block = new Block(*this, **i);
139                         used_tracks.insert(block->get_tracks().begin(), block->get_tracks().end());
140                 }
141
142         for(set<Block *>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
143                 for(set<Block *>::iterator j=i; j!=blocks.end(); ++j)
144                         if(j!=i)
145                                 (*i)->check_link(**j);
146 }
147
148 void Layout::create_blocks(Track &track)
149 {
150         /* Must collect the blocks in a set first while all tracks are still
151         guaranteed to have blocks and to avoid duplicate deletes */
152         set<Block *> del_blocks;
153
154         del_blocks.insert(&track.get_block());
155
156         const vector<Track *> &links = track.get_links();
157         for(vector<Track *>::const_iterator i=links.begin(); i!=links.end(); ++i)
158                 if(*i)
159                         del_blocks.insert(&(*i)->get_block());
160
161         for(set<Block *>::iterator i=del_blocks.begin(); i!=del_blocks.end(); ++i)
162                 delete *i;
163
164         create_blocks();
165 }
166
167 void Layout::remove_block(Block &b)
168 {
169         blocks.erase(&b);
170 }
171
172 void Layout::add_route(Route &r)
173 {
174         if(routes.insert(&r).second)
175                 signal_route_added.emit(r);
176 }
177
178 Route &Layout::get_route(const string &name) const
179 {
180         for(set<Route *>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
181                 if((*i)->get_name()==name)
182                         return **i;
183         throw key_error(name);
184 }
185
186 void Layout::update_routes()
187 {
188         for(set<Route *>::iterator i=routes.begin(); i!=routes.end(); ++i)
189                 (*i)->update_turnouts();
190 }
191
192 void Layout::remove_route(Route &r)
193 {
194         if(routes.erase(&r))
195                 signal_route_removed.emit(r);
196 }
197
198 void Layout::add_zone(Zone &z)
199 {
200         if(zones.insert(&z).second)
201                 signal_zone_added.emit(z);
202 }
203
204 Layout::ZoneArray Layout::get_zones(const string &group) const
205 {
206         ZoneArray result;
207         for(ZoneSet::const_iterator i=zones.begin(); i!=zones.end(); ++i)
208                 if((*i)->get_group()==group)
209                         result.push_back(*i);
210
211         sort(result.begin(), result.end(), zone_order);
212
213         return result;
214 }
215
216 Zone &Layout::get_zone(const string &group, unsigned num) const
217 {
218         for(ZoneSet::const_iterator i=zones.begin(); i!=zones.end(); ++i)
219                 if((*i)->get_group()==group && (*i)->get_number()==num)
220                         return **i;
221
222         throw key_error(format("%s %d", group, num));
223 }
224
225 void Layout::remove_zone(Zone &z)
226 {
227         if(zones.erase(&z))
228                 signal_zone_removed.emit(z);
229 }
230
231 void Layout::add_train(Train &t)
232 {
233         insert_unique(trains, t.get_address(), &t);
234         signal_train_added.emit(t);
235 }
236
237 Train &Layout::get_train(unsigned addr) const
238 {
239         return *get_item(trains, addr);
240 }
241
242 void Layout::remove_train(Train &t)
243 {
244         if(trains.erase(t.get_address()))
245                 signal_train_removed.emit(t);
246 }
247
248 void Layout::add_vehicle(Vehicle &v)
249 {
250         if(vehicles.insert(&v).second)
251                 signal_vehicle_added.emit(v);
252 }
253
254 void Layout::remove_vehicle(Vehicle &v)
255 {
256         if(vehicles.erase(&v))
257                 signal_vehicle_removed.emit(v);
258 }
259
260 void Layout::tick()
261 {
262         if(driver)
263                 driver->tick();
264
265         Time::TimeStamp t = Time::now();
266         Time::TimeDelta dt;
267         if(last_tick)
268                 dt = t-last_tick;
269         last_tick = t;
270
271         for(set<Block *>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
272                 (*i)->tick(dt);
273         for(map<unsigned, Train *>::iterator i=trains.begin(); i!=trains.end(); ++i)
274                 i->second->tick(t, dt);
275 }
276
277 void Layout::emergency(const string &msg)
278 {
279         if(driver)
280                 driver->halt(true);
281         IO::print("Emergency: %s\n", msg);
282         signal_emergency.emit(msg);
283 }
284
285 void Layout::save(const string &fn) const
286 {
287         IO::BufferedFile out(fn, IO::M_WRITE);
288         DataFile::Writer writer(out);
289
290         if(!base.empty())
291                 writer.write((DataFile::Statement("base"), base));
292
293         for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
294         {
295                 DataFile::Statement st("track");
296                 st.append((*i)->get_type().get_article_number());
297                 (*i)->save(st.sub);
298                 writer.write(st);
299         }
300
301         for(set<Route *>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
302         {
303                 if((*i)->is_temporary())
304                         continue;
305
306                 DataFile::Statement st("route");
307                 (*i)->save(st.sub);
308                 writer.write(st);
309         }
310
311         for(ZoneSet::const_iterator i=zones.begin(); i!=zones.end(); ++i)
312         {
313                 DataFile::Statement st("zone");
314                 (*i)->save(st.sub);
315                 writer.write(st);
316         }
317 }
318
319 void Layout::save_dynamic(const string &fn) const
320 {
321         IO::BufferedFile out(fn, IO::M_WRITE);
322         DataFile::Writer writer(out);
323
324         for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
325                 if(unsigned tid = (*i)->get_turnout_id())
326                         writer.write((DataFile::Statement("turnout"), tid, (*i)->get_active_path()));
327
328         for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
329         {
330                 DataFile::Statement st("train");
331                 st.append(i->second->get_locomotive_type().get_article_number());
332                 st.append(i->second->get_address());
333                 st.append(i->second->get_protocol());
334                 i->second->save(st.sub);
335                 writer.write(st);
336         }
337 }
338
339 void Layout::block_state_changed(Block &block, Block::State state)
340 {
341         if(state==Block::ACTIVE && !block.get_train())
342                 emergency(format("Unreserved sensor %d triggered", block.get_sensor_id()));
343 }
344
345
346 Layout::Loader::Loader(Layout &l):
347         DataFile::BasicLoader<Layout>(l),
348         new_tracks(false)
349 {
350         add("base",  &Layout::base);
351         add("route", static_cast<void (Loader::*)()>(&Loader::route));
352         add("track", static_cast<void (Loader::*)(ArticleNumber)>(&Loader::track));
353         add("train", static_cast<void (Loader::*)(ArticleNumber, unsigned, const std::string &)>(&Loader::train));
354         add("turnout", &Loader::turnout);
355         add("zone",  &Loader::zone);
356
357         // Deprecated aliases
358         add("route", static_cast<void (Loader::*)(const string &)>(&Loader::route));
359         add("track", static_cast<void (Loader::*)(unsigned)>(&Loader::track));
360         add("train", static_cast<void (Loader::*)(unsigned, unsigned, const std::string &)>(&Loader::train));
361 }
362
363 void Layout::Loader::finish()
364 {
365         for(set<Track *>::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i)
366                 (*i)->check_slope();
367 }
368
369 void Layout::Loader::route()
370 {
371         Route *rte = new Route(obj);
372         load_sub(*rte);
373 }
374
375 void Layout::Loader::route(const string &n)
376 {
377         Route *rte = new Route(obj);
378         rte->set_name(n);
379         load_sub(*rte);
380 }
381
382 void Layout::Loader::track(unsigned art_nr)
383 {
384         track(ArticleNumber(art_nr));
385 }
386
387 void Layout::Loader::track(ArticleNumber art_nr)
388 {
389         Track *trk = new Track(obj, obj.catalogue.get_track(art_nr));
390         load_sub(*trk);
391         new_tracks = true;
392         for(set<Track *>::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i)
393                 if(*i!=trk)
394                         trk->snap_to(**i, true);
395 }
396
397 void Layout::Loader::train(unsigned art_nr, unsigned addr, const std::string &proto)
398 {
399         train(ArticleNumber(art_nr), addr, proto);
400 }
401
402 void Layout::Loader::train(ArticleNumber art_nr, unsigned addr, const std::string &proto)
403 {
404         Train *trn = new Train(obj, obj.catalogue.get_vehicle(art_nr), addr, proto);
405         load_sub(*trn);
406 }
407
408 void Layout::Loader::turnout(unsigned addr, unsigned path)
409 {
410         if(obj.driver)
411                 obj.driver->set_turnout(addr, path);
412 }
413
414 void Layout::Loader::zone()
415 {
416         Zone *zne = new Zone(obj);
417         load_sub(*zne);
418 }
419
420 } // namespace R2C2