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