]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/block.cpp
ee0a48cb950498474e0fe7d2b8bc602a5ac77987
[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 <iostream>
9 #include "control.h"
10 #include "block.h"
11 #include "tracktype.h"
12 #include "trafficmanager.h"
13 #include "turnout.h"
14
15 using namespace std;
16 using namespace Msp;
17
18 namespace Marklin {
19
20 Block::Block(TrafficManager &tm, Track &start):
21         trfc_mgr(tm),
22         id(next_id++),
23         sensor_id(start.get_sensor_id()),
24         turnout_id(start.get_turnout_id()),
25         train(0)
26 {
27         tracks.insert(&start);
28
29         list<Track *> queue;
30         queue.push_back(&start);
31
32         while(!queue.empty())
33         {
34                 Track *track=queue.front();
35                 queue.erase(queue.begin());
36
37                 const vector<Track *> &links=track->get_links();
38                 for(unsigned i=0; i<links.size(); ++i)
39                         if(links[i] && !tracks.count(links[i]))
40                         {
41                                 if(links[i]->get_sensor_id()==sensor_id && links[i]->get_turnout_id()==turnout_id)
42                                 {
43                                         queue.push_back(links[i]);
44                                         tracks.insert(links[i]);
45                                 }
46                                 else
47                                         endpoints.push_back(Endpoint(track, i));
48                         }
49         }
50
51         for(unsigned i=0; i<endpoints.size(); ++i)
52         {
53                 unsigned route=1<<i;
54                 endpoints[i].routes|=route;
55                 set<Track *> visited;
56                 find_routes(*endpoints[i].track, endpoints[i].track_ep, route, visited);
57         }
58 }
59
60 int Block::get_endpoint_by_link(const Block &other) const
61 {
62         for(unsigned i=0; i<endpoints.size(); ++i)
63                 if(endpoints[i].link==&other)
64                         return i;
65
66         return -1;
67 }
68
69 int Block::traverse(unsigned epi, float *len) const
70 {
71         if(epi>=endpoints.size())
72                 throw InvalidParameterValue("Endpoint index out of range");
73
74         const Endpoint &ep=endpoints[epi];
75         Track *track=ep.track;
76         unsigned track_ep=ep.track_ep;
77
78         if(len)
79                 *len=0;
80
81         while(1)
82         {
83                 unsigned cur_route=0;
84                 unsigned tid=track->get_turnout_id();
85                 if(tid)
86                 {
87                         Turnout &turnout=trfc_mgr.get_control().get_turnout(tid);
88                         cur_route=turnout.get_route();
89                 }
90
91                 if(len)
92                         *len+=track->get_type().get_route_length(cur_route);
93
94                 int other_ep=track->traverse(track_ep, cur_route);
95                 if(other_ep<0)
96                         return -1;
97
98                 for(unsigned i=0; i<endpoints.size(); ++i)
99                         if(endpoints[i].track==track && endpoints[i].track_ep==static_cast<unsigned>(other_ep))
100                                 return i;
101
102                 Track *next=track->get_link(other_ep);
103                 if(tracks.count(next)==0)
104                         return -1;
105                 track_ep=next->get_endpoint_by_link(*track);
106                 track=next;
107         }
108 }
109
110 void Block::check_link(Block &other)
111 {
112         for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
113         {
114                 if(i->link)
115                         continue;
116
117                 for(vector<Endpoint>::iterator j=other.endpoints.begin(); j!=other.endpoints.end(); ++j)
118                         if(j->track==i->track->get_link(i->track_ep) && j->track->get_link(j->track_ep)==i->track && !j->link)
119                         {
120                                 i->link=&other;
121                                 j->link=this;
122                         }
123         }
124 }
125
126 Block *Block::get_link(unsigned epi) const
127 {
128         if(epi>=endpoints.size())
129                 throw InvalidParameterValue("Endpoint index out of range");
130         return endpoints[epi].link;
131 }
132
133 bool Block::reserve(const Train *t)
134 {
135         if(!t || !train)
136         {
137                 train=t;
138                 trfc_mgr.signal_block_reserved.emit(*this, train);
139                 return true;
140         }
141         else
142                 return false;
143 }
144
145 void Block::print_debug()
146 {
147         cout<<"Block "<<id;
148         if((*tracks.begin())->get_sensor_id())
149                 cout<<", sensor="<<(*tracks.begin())->get_sensor_id();
150         cout<<'\n';
151         for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
152         {
153                 cout<<"  Endpoint, link=";
154                 if(i->link)
155                         cout<<i->link->id;
156                 else
157                         cout<<"none";
158                 cout<<", routes="<<i->routes<<'\n';
159         }
160 }
161
162 void Block::find_routes(Track &track, unsigned track_ep, unsigned route, set<Track *> &visited)
163 {
164         visited.insert(&track);
165
166         const vector<Marklin::Endpoint> &eps=track.get_type().get_endpoints();
167         for(unsigned i=0; i<eps.size(); ++i)
168         {
169                 if(i==track_ep) continue;
170                 Track *link=track.get_link(i);
171                 if(!link) continue;
172                 if(visited.count(link)) continue;
173                 if(!(eps[i].routes&eps[track_ep].routes)) continue;
174
175                 if(tracks.count(link))
176                         find_routes(*link, link->get_endpoint_by_link(track), route, visited);
177                 else
178                 {
179                         for(vector<Endpoint>::iterator j=endpoints.begin(); j!=endpoints.end(); ++j)
180                                 if(j->track==&track && j->track_ep==i)
181                                         j->routes|=route;
182                 }
183         }
184 }
185
186 unsigned Block::next_id=1;
187
188
189 Block::Endpoint::Endpoint(Track *t, unsigned e):
190         track(t),
191         track_ep(e),
192         link(0),
193         routes(0)
194 { }
195
196 } // namespace Marklin