]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/block.cpp
Use Msp::IO::print instead of std::cout
[r2c2.git] / source / libmarklin / block.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include "control.h"
9 #include "block.h"
10 #include "tracktype.h"
11 #include "trafficmanager.h"
12 #include "turnout.h"
13
14 using namespace std;
15 using namespace Msp;
16
17 namespace Marklin {
18
19 unsigned Block::next_id = 1;
20
21 Block::Block(TrafficManager &tm, Track &start):
22         trfc_mgr(tm),
23         id(next_id++),
24         sensor_id(start.get_sensor_id()),
25         turnout_id(start.get_turnout_id()),
26         train(0)
27 {
28         tracks.insert(&start);
29
30         list<Track *> queue;
31         queue.push_back(&start);
32
33         while(!queue.empty())
34         {
35                 Track *track = queue.front();
36                 queue.erase(queue.begin());
37
38                 const vector<Track *> &links = track->get_links();
39                 for(unsigned i=0; i<links.size(); ++i)
40                         if(links[i] && !tracks.count(links[i]))
41                         {
42                                 if(links[i]->get_sensor_id()==sensor_id && links[i]->get_turnout_id()==turnout_id)
43                                 {
44                                         queue.push_back(links[i]);
45                                         tracks.insert(links[i]);
46                                 }
47                                 else
48                                         endpoints.push_back(Endpoint(track, i));
49                         }
50         }
51
52         for(unsigned i=0; i<endpoints.size(); ++i)
53         {
54                 unsigned path = 1<<i;
55                 endpoints[i].paths |= path;
56                 set<Track *> visited;
57                 find_paths(*endpoints[i].track, endpoints[i].track_ep, path, visited);
58         }
59 }
60
61 int Block::get_endpoint_by_link(const Block &other) const
62 {
63         for(unsigned i=0; i<endpoints.size(); ++i)
64                 if(endpoints[i].link==&other)
65                         return i;
66
67         return -1;
68 }
69
70 unsigned Block::traverse(unsigned epi, float *len) const
71 {
72         if(epi>=endpoints.size())
73                 throw InvalidParameterValue("Endpoint index out of range");
74
75         const Endpoint &ep = endpoints[epi];
76         Track *track = ep.track;
77         unsigned track_ep = ep.track_ep;
78
79         if(len)
80                 *len = 0;
81
82         while(1)
83         {
84                 unsigned cur_path = 0;
85                 unsigned tid = track->get_turnout_id();
86                 if(tid)
87                 {
88                         Turnout &turnout = trfc_mgr.get_control().get_turnout(tid);
89                         cur_path = turnout.get_path();
90                 }
91
92                 if(len)
93                         *len += track->get_type().get_path_length(cur_path);
94
95                 unsigned other_ep = track->traverse(track_ep, cur_path);
96                 for(unsigned i=0; i<endpoints.size(); ++i)
97                         if(endpoints[i].track==track && endpoints[i].track_ep==static_cast<unsigned>(other_ep))
98                                 return i;
99
100                 Track *next = track->get_link(other_ep);
101                 if(!tracks.count(next))
102                         throw LogicError("Block traversal strayed out of the block");
103                 track_ep = next->get_endpoint_by_link(*track);
104                 track = next;
105         }
106 }
107
108 void Block::check_link(Block &other)
109 {
110         for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
111         {
112                 if(i->link)
113                         continue;
114
115                 for(vector<Endpoint>::iterator j=other.endpoints.begin(); j!=other.endpoints.end(); ++j)
116                         if(j->track==i->track->get_link(i->track_ep) && j->track->get_link(j->track_ep)==i->track && !j->link)
117                         {
118                                 i->link = &other;
119                                 j->link = this;
120                         }
121         }
122 }
123
124 Block *Block::get_link(unsigned epi) const
125 {
126         if(epi>=endpoints.size())
127                 throw InvalidParameterValue("Endpoint index out of range");
128         return endpoints[epi].link;
129 }
130
131 bool Block::reserve(const Train *t)
132 {
133         if(!t || !train)
134         {
135                 train = t;
136                 trfc_mgr.signal_block_reserved.emit(*this, train);
137                 return true;
138         }
139         else
140                 return false;
141 }
142
143 void Block::find_paths(Track &track, unsigned track_ep, unsigned path, set<Track *> &visited)
144 {
145         visited.insert(&track);
146
147         const vector<Marklin::Endpoint> &eps = track.get_type().get_endpoints();
148         for(unsigned i=0; i<eps.size(); ++i)
149         {
150                 if(i==track_ep) continue;
151                 Track *link = track.get_link(i);
152                 if(!link) continue;
153                 if(visited.count(link)) continue;
154                 if(!(eps[i].paths&eps[track_ep].paths)) continue;
155
156                 if(tracks.count(link))
157                         find_paths(*link, link->get_endpoint_by_link(track), path, visited);
158                 else
159                 {
160                         for(vector<Endpoint>::iterator j=endpoints.begin(); j!=endpoints.end(); ++j)
161                                 if(j->track==&track && j->track_ep==i)
162                                         j->paths |= path;
163                 }
164         }
165 }
166
167
168 Block::Endpoint::Endpoint(Track *t, unsigned e):
169         track(t),
170         track_ep(e),
171         link(0),
172         paths(0)
173 { }
174
175 } // namespace Marklin