]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/trainroutemetric.cpp
Allow direction to be specified for routing waypoints
[r2c2.git] / source / libr2c2 / trainroutemetric.cpp
1 #include <list>
2 #include "track.h"
3 #include "trackchain.h"
4 #include "trainroutemetric.h"
5
6 using namespace std;
7
8 namespace R2C2 {
9
10 TrainRouteMetric::TrainRouteMetric(const TrackChain &tc, TrackChain::Direction dir)
11 {
12         const TrackChain::TrackSet &ctracks = tc.get_tracks();
13         for(TrackChain::TrackSet::const_iterator i=ctracks.begin(); i!=ctracks.end(); ++i)
14         {
15                 if(dir==TrackChain::UNSPECIFIED)
16                 {
17                         unsigned nls = (*i)->get_n_link_slots();
18                         for(unsigned j=0; j<nls; ++j)
19                                 if(Track *link = (*i)->get_link(j))
20                                         if(!ctracks.count(link))
21                                                 goals.push_back(TrackIter(*i, j));
22                 }
23                 else if(TrackIter iter = tc.iter_for(**i, reverse_dir))
24                         goals.push_back(iter);
25         }
26
27         list<TrackIter> queue;
28         for(vector<Goal>::iterator i=goals.begin(); i!=goals.end(); ++i)
29         {
30                 tracks[Key(i->track.track(), i->track.entry())] = Data(0, &*i);
31                 queue.push_back(i->track);
32         }
33
34         while(!queue.empty())
35         {
36                 TrackIter track = queue.front();
37                 queue.pop_front();
38                 const Data &data = tracks[Key(track.track(), track.entry())];
39
40                 const TrackType::Endpoint &ep = track.endpoint();
41                 for(unsigned i=0; ep.paths>>i; ++i)
42                         if(ep.has_path(i))
43                         {
44                                 TrackIter next = track.next(i);
45                                 if(!next)
46                                         continue;
47
48                                 Data &target = tracks[Key(next.track(), next.entry())];
49                                 float dist = data.distance+track->get_type().get_path_length(i);
50                                 if(target.distance<0 || target.distance>dist)
51                                 {
52                                         target = Data(dist, data.goal);
53                                         queue.push_back(next);
54                                 }
55                         }
56         }
57 }
58
59 void TrainRouteMetric::chain_to(const TrainRouteMetric &metric)
60 {
61         for(vector<Goal>::iterator i=goals.begin(); i!=goals.end(); ++i)
62                 i->base_distance = metric.get_distance_from(*i->track.track(), i->track.entry());
63 }
64
65 float TrainRouteMetric::get_distance_from(const Track &track, unsigned exit) const
66 {
67         map<Key, Data>::const_iterator i = tracks.find(Key(&track, exit));
68         if(i==tracks.end())
69                 return -1;
70
71         return i->second.distance+i->second.goal->base_distance;
72 }
73
74
75 TrainRouteMetric::Goal::Goal():
76         base_distance(0)
77 { }
78
79 TrainRouteMetric::Goal::Goal(const TrackIter &t):
80         track(t),
81         base_distance(0)
82 { }
83
84
85 TrainRouteMetric::Data::Data():
86         distance(-1),
87         goal(0)
88 { }
89
90 TrainRouteMetric::Data::Data(float d, const Goal *g):
91         distance(d),
92         goal(g)
93 { }
94
95 } // namespace R2C2