]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/trackiter.cpp
Add a function to get a BlockIter from a TrackIter
[r2c2.git] / source / libr2c2 / trackiter.cpp
1 #include <algorithm>
2 #include "blockiter.h"
3 #include "track.h"
4 #include "trackiter.h"
5 #include "tracktype.h"
6
7 using namespace std;
8 using namespace Msp;
9
10 namespace R2C2 {
11
12 TrackIter::TrackIter():
13         _track(0),
14         _entry(0)
15 { }
16
17 TrackIter::TrackIter(Track *t, unsigned e):
18         _track(t),
19         _entry(t ? e : 0)
20 {
21         if(_track && _entry>_track->get_type().get_endpoints().size())
22                 throw out_of_range("TrackIter::TrackIter");
23 }
24
25 BlockIter TrackIter::block_iter() const
26 {
27         if(!_track)
28                 return BlockIter();
29
30         Block &block = _track->get_block();
31         const vector<Block::Endpoint> &beps = block.get_endpoints();
32
33         if(_track->get_type().is_turnout())
34         {
35                 /* A turnouts is the only track in its block.  Go ahead and find the
36                 matching endpoint in the block. */
37                 for(unsigned i=0; i<beps.size(); ++i)
38                         if(beps[i].track==_track && beps[i].track_ep==_entry)
39                                 return BlockIter(&block, i);
40         }
41         else
42         {
43                 TrackIter rev = reverse();
44                 while(rev && &rev.track()->get_block()==&block)
45                 {
46                         TrackIter fwd = rev.reverse();
47
48                         for(unsigned i=0; i<beps.size(); ++i)
49                                 if(beps[i].track==fwd.track() && beps[i].track_ep==fwd.entry())
50                                         return BlockIter(&block, i);
51
52                         rev = rev.next();
53                 }
54         }
55
56         throw logic_error("internal error (didn't find block entry endpoint)");
57 }
58
59 const TrackType::Endpoint &TrackIter::endpoint() const
60 {
61         if(!_track)
62                 throw logic_error("null track");
63
64         return _track->get_type().get_endpoint(_entry);
65 }
66
67 int TrackIter::get_exit(unsigned path) const
68 {
69         const vector<TrackType::Endpoint> &eps = _track->get_type().get_endpoints();
70         
71         // Find an endpoint that's connected to the entry and has the requested path
72         for(unsigned i=0; i<eps.size(); ++i)
73                 if(i!=_entry && (eps[i].paths&(1<<path)) && (eps[i].paths&eps[_entry].paths))
74                         return i;
75
76         return -1;
77 }
78
79 TrackIter TrackIter::next() const
80 {
81         if(!_track)
82                 return TrackIter();
83
84         return next(_track->get_active_path());
85 }
86
87 TrackIter TrackIter::next(unsigned path) const
88 {
89         if(!_track)
90                 return TrackIter();
91
92         int exit = get_exit(path);
93         if(exit<0)
94                 return TrackIter();
95
96         TrackIter result;
97         result._track = _track->get_link(exit);
98         result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0);
99
100         return result;
101 }
102
103 TrackIter TrackIter::reverse() const
104 {
105         if(!_track)
106                 return TrackIter();
107
108         return reverse(_track->get_active_path());
109 }
110
111 TrackIter TrackIter::reverse(unsigned path) const
112 {
113         if(!_track)
114                 return TrackIter();
115
116         int exit = get_exit(path);
117         if(exit<0)
118                 return TrackIter();
119
120         return TrackIter(_track, exit);
121 }
122
123 TrackIter TrackIter::flip() const
124 {
125         if(!_track)
126                 return TrackIter();
127
128         TrackIter result;
129         result._track = _track->get_link(_entry);
130         result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0);
131
132         return result;
133 }
134
135 Track &TrackIter::operator*() const
136 {
137         if(!_track)
138                 throw logic_error("null track");
139
140         return *_track;
141 }
142
143 bool TrackIter::operator==(const TrackIter &other) const
144 {
145         return _track==other._track && _entry==other._entry;
146 }
147
148
149 TrackLoopIter::TrackLoopIter():
150         _looped(false)
151 { }
152
153 TrackLoopIter::TrackLoopIter(Track *t, unsigned e):
154         TrackIter(t, e),
155         _visited(new TrackList()),
156         _last(_visited->insert(_visited->end(), track())),
157         _looped(false)
158 { }
159
160 TrackLoopIter::TrackLoopIter(const TrackIter &i):
161         TrackIter(i),
162         _visited(new TrackList()),
163         _last(_visited->insert(_visited->end(), track())),
164         _looped(false)
165 { }
166
167 TrackLoopIter::TrackLoopIter(const TrackIter &i, RefPtr<TrackList> v, const TrackList::iterator &l):
168         TrackIter(i),
169         _looped(false)
170 {
171         if(track())
172         {
173                 _visited = v;
174                 _last = l;
175                 _looped = (_visited && find(_visited->begin(), _last, track())!=_last);
176
177                 ++_last;
178                 if(_last!=_visited->end())
179                 {
180                         _visited = new TrackList(_visited->begin(), _last);
181                         _last = _visited->end();
182                 }
183                 _visited->push_back(track());
184                 --_last;
185         }
186 }
187
188 TrackLoopIter TrackLoopIter::next() const
189 {
190         return TrackLoopIter(TrackIter::next(), _visited, _last);
191 }
192
193 TrackLoopIter TrackLoopIter::next(unsigned path) const
194 {
195         return TrackLoopIter(TrackIter::next(path), _visited, _last);
196 }
197
198 } // namespace R2C2