]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/route.cpp
Convert designer to use mspgltk for UI
[r2c2.git] / source / libmarklin / route.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2007-2009  Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include "track.h"
9 #include "tracktype.h"
10 #include "route.h"
11
12 using namespace std;
13 using namespace Msp;
14
15 namespace Marklin {
16
17 Route::Route(const string &n):
18         name(n)
19 { }
20
21 int Route::get_turnout(unsigned id) const
22 {
23         map<unsigned, int>::const_iterator i = turnouts.find(id);
24         if(i!=turnouts.end())
25                 return i->second;
26         return -1;
27 }
28
29 void Route::add_track(const Track &trk)
30 {
31         if(tracks.count(&trk))
32                 return;
33
34         if(!tracks.empty())
35         {
36                 unsigned valid = check_validity(trk);
37                 if(!(valid&1))
38                         throw Exception("Not linked to existing tracks");
39                 else if(!(valid&2))
40                         throw Exception("Branching routes not allowed");
41                 else if(!(valid&4))
42                         throw Exception("Route must be smooth");
43         }
44
45         tracks.insert(&trk);
46         update_turnouts();
47 }
48
49 void Route::add_tracks(const set<const Track *> &trks)
50 {
51         set<const Track *> pending;
52         for(set<const Track *>::const_iterator i=trks.begin(); i!=trks.end(); ++i)
53                 if(!tracks.count(*i))
54                         pending.insert(*i);
55
56         while(!pending.empty())
57         {
58                 bool found = false;
59                 for(set<const Track *>::const_iterator i=pending.begin(); i!=pending.end(); ++i)
60                         if(tracks.empty() || check_validity(**i)==7)
61                         {
62                                 tracks.insert(*i);
63                                 pending.erase(*i);
64                                 found = true;
65                                 break;
66                         }
67
68                 if(!found)
69                         throw Exception("Could not add all tracks to route");
70         }
71
72         update_turnouts();
73 }
74
75 void Route::save(list<DataFile::Statement> &st) const
76 {
77         for(map<unsigned, int>::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
78                 st.push_back((DataFile::Statement("turnout"), i->first, i->second));
79 }
80
81 void Route::update_turnouts()
82 {
83         set<unsigned> found;
84         for(set<const Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
85                 if(unsigned tid=(*i)->get_turnout_id())
86                 {
87                         found.insert(tid);
88
89                         const vector<Endpoint> &endpoints = (*i)->get_type().get_endpoints();
90                         const vector<Track *> &links = (*i)->get_links();
91
92                         unsigned mask = 15;
93                         for(unsigned j=0; j<endpoints.size(); ++j)
94                         {
95                                 if(!tracks.count(links[j]))
96                                         continue;
97                                 if(unsigned tid2=links[j]->get_turnout_id())
98                                 {
99                                         const Endpoint &ep = links[j]->get_type().get_endpoints()[links[j]->get_endpoint_by_link(**i)];
100                                         int r = get_turnout(tid2);
101                                         if(r>=0 && !(ep.routes&(1<<r)))
102                                         {
103                                                 mask &= ~endpoints[j].routes;
104                                                 continue;
105                                         }
106                                 }
107                                 mask &= endpoints[j].routes;
108                         }
109
110                         if(!(mask&(mask-1)))
111                         {
112                                 unsigned route = 0;
113                                 for(; (mask && !(mask&1)); mask>>=1, ++route) ;
114                                 turnouts[tid] = route;
115                         }
116                         else
117                                 turnouts[tid] = -1;
118                 }
119
120         for(map<unsigned, int>::iterator i=turnouts.begin(); i!=turnouts.end();)
121         {
122                 if(!found.count(i->first))
123                         turnouts.erase(i++);
124                 else
125                         ++i;
126         }
127 }
128
129 unsigned Route::check_validity(const Track &trk) const
130 {
131         unsigned result = 4;
132         for(set<const Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
133         {
134                 int epi=(*i)->get_endpoint_by_link(trk);
135                 if(epi>=0)
136                 {
137                         result |= 1;
138                         const vector<Endpoint> &endpoints = (*i)->get_type().get_endpoints();
139                         if(unsigned tid=(*i)->get_turnout_id())
140                         {
141                                 int r = get_turnout(tid);
142                                 if(r>=0)
143                                 {
144                                         if(endpoints[epi].routes&(1<<r))
145                                                 result |= 2;
146                                 }
147                                 else
148                                 {
149                                         unsigned count = 0;
150                                         const vector<Track *> &links = (*i)->get_links();
151                                         int epj = -1;
152                                         for(unsigned k=0; k<endpoints.size(); ++k)
153                                                 if(tracks.count(links[k]))
154                                                 {
155                                                         ++count;
156                                                         epj = k;
157                                                 }
158                                         if(count<=1)
159                                         {
160                                                 result |= 2;
161                                                 if(epj>=0 && !(endpoints[epi].routes&endpoints[epj].routes))
162                                                         result &= 3;
163                                         }
164                                 }
165                         }
166                         else
167                                 result |= 2;
168                 }
169         }
170
171         return result;
172 }
173
174
175 Route::Loader::Loader(Route &r):
176         DataFile::BasicLoader<Route>(r)
177 {
178         add("turnout", &Loader::turnout);
179 }
180
181 void Route::Loader::turnout(unsigned id, unsigned route)
182 {
183         obj.turnouts[id] = route;
184 }
185
186 } // namespace Marklin