+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <iostream>
#include "control.h"
#include "block.h"
+#include "tracktype.h"
#include "trafficmanager.h"
#include "turnout.h"
-using namespace Msp;
-
-#include <iostream>
using namespace std;
+using namespace Msp;
namespace Marklin {
-Block::Block(TrafficManager &tm, Track *start):
+Block::Block(TrafficManager &tm, Track &start):
trfc_mgr(tm),
id(next_id++),
- sensor_id(0),
+ sensor_id(start.get_sensor_id()),
train(0)
{
- tracks.insert(start);
+ tracks.insert(&start);
- if(start->get_sensor_id())
- {
- sensor_id=start->get_sensor_id();
- const Track::EndpointSeq &eps=start->get_endpoints();
- for(Track::EndpointSeq::const_iterator i=eps.begin(); i!=eps.end(); ++i)
- endpoints.push_back(Endpoint(start, &*i));
- }
- else
- {
- TrackSeq queue;
- queue.push_back(start);
+ list<Track *> queue;
+ queue.push_back(&start);
- while(!queue.empty())
- {
- Track *track=queue.front();
- queue.erase(queue.begin());
+ while(!queue.empty())
+ {
+ Track *track=queue.front();
+ queue.erase(queue.begin());
- const Track::EndpointSeq &eps=track->get_endpoints();
- for(Track::EndpointSeq::const_iterator i=eps.begin(); i!=eps.end(); ++i)
- if(i->link && tracks.count(i->link)==0)
+ const vector<Track *> &links=track->get_links();
+ for(unsigned i=0; i<links.size(); ++i)
+ if(links[i] && !tracks.count(links[i]))
+ {
+ if(links[i]->get_sensor_id()==sensor_id && !links[i]->get_turnout_id() && !track->get_turnout_id())
{
- if(!i->link->get_sensor_id())
- {
- queue.push_back(i->link);
- tracks.insert(i->link);
- }
- else
- endpoints.push_back(Endpoint(track, &*i));
+ queue.push_back(links[i]);
+ tracks.insert(links[i]);
}
- }
+ else
+ endpoints.push_back(Endpoint(track, i));
+ }
}
- unsigned n=0;
- for(EndpointSeq::iterator i=endpoints.begin(); i!=endpoints.end(); ++i, ++n)
+ for(unsigned i=0; i<endpoints.size(); ++i)
{
- unsigned route=1<<n;
- i->routes|=route;
+ unsigned route=1<<i;
+ endpoints[i].routes|=route;
set<Track *> visited;
- find_routes(i->track, i->track_ep, route, visited);
+ find_routes(*endpoints[i].track, endpoints[i].track_ep, route, visited);
}
}
-const Block::Endpoint *Block::get_endpoint_by_link(const Block *other) const
+int Block::get_endpoint_by_link(const Block &other) const
{
- for(EndpointSeq::const_iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
- if(i->link==other)
- return &*i;
+ for(unsigned i=0; i<endpoints.size(); ++i)
+ if(endpoints[i].link==&other)
+ return i;
- return 0;
+ return -1;
}
-const Block::Endpoint *Block::traverse(const Endpoint *ep) const
+int Block::traverse(unsigned epi, float *len) const
{
- Track *track=ep->track;
- const Track::Endpoint *track_ep=ep->track_ep;
+ if(epi>=endpoints.size())
+ throw InvalidParameterValue("Endpoint index out of range");
+
+ const Endpoint &ep=endpoints[epi];
+ Track *track=ep.track;
+ unsigned track_ep=ep.track_ep;
+
+ if(len)
+ *len=0;
while(1)
{
unsigned tid=track->get_turnout_id();
if(tid)
{
- Turnout *turnout=trfc_mgr.get_control().get_turnout(tid);
- if(turnout)
- cur_route=turnout->get_route();
+ Turnout &turnout=trfc_mgr.get_control().get_turnout(tid);
+ cur_route=turnout.get_route();
}
- const Track::Endpoint *other_ep=track->traverse(track_ep, cur_route);
- if(!other_ep)
- return 0;
+ if(len)
+ *len+=track->get_type().get_route_length(cur_route);
- for(EndpointSeq::const_iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
- if(i->track==track && i->track_ep==other_ep)
- return &*i;
+ int other_ep=track->traverse(track_ep, cur_route);
+ if(other_ep<0)
+ return -1;
- track_ep=track->get_endpoint_by_link(other_ep->link);
- track=other_ep->link;
+ for(unsigned i=0; i<endpoints.size(); ++i)
+ if(endpoints[i].track==track && endpoints[i].track_ep==static_cast<unsigned>(other_ep))
+ return i;
- if(tracks.count(track)==0)
- return 0;
+ Track *next=track->get_link(other_ep);
+ if(tracks.count(next)==0)
+ return -1;
+ track_ep=next->get_endpoint_by_link(*track);
+ track=next;
}
}
void Block::check_link(Block &other)
{
- for(EndpointSeq::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
+ for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
{
if(i->link)
continue;
- for(EndpointSeq::iterator j=other.endpoints.begin(); j!=other.endpoints.end(); ++j)
- if(j->track==i->track_ep->link && j->track_ep->link==i->track && !j->link)
+ for(vector<Endpoint>::iterator j=other.endpoints.begin(); j!=other.endpoints.end(); ++j)
+ if(j->track==i->track->get_link(i->track_ep) && j->track->get_link(j->track_ep)==i->track && !j->link)
{
i->link=&other;
j->link=this;
}
}
+Block *Block::get_link(unsigned epi) const
+{
+ if(epi>=endpoints.size())
+ throw InvalidParameterValue("Endpoint index out of range");
+ return endpoints[epi].link;
+}
+
bool Block::reserve(const Train *t)
{
if(!t || !train)
{
train=t;
+ trfc_mgr.signal_block_reserved.emit(*this, train);
return true;
}
else
if((*tracks.begin())->get_sensor_id())
cout<<", sensor="<<(*tracks.begin())->get_sensor_id();
cout<<'\n';
- for(EndpointSeq::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
+ for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
{
cout<<" Endpoint, link=";
if(i->link)
}
}
-void Block::find_routes(Track *track, const Track::Endpoint *track_ep, unsigned route, std::set<Marklin::Track *> &visited)
+void Block::find_routes(Track &track, unsigned track_ep, unsigned route, set<Track *> &visited)
{
- visited.insert(track);
+ visited.insert(&track);
- const Track::EndpointSeq &eps=track->get_endpoints();
- for(Track::EndpointSeq::const_iterator i=eps.begin(); i!=eps.end(); ++i)
+ const vector<Marklin::Endpoint> &eps=track.get_type().get_endpoints();
+ for(unsigned i=0; i<eps.size(); ++i)
{
- if(&*i==track_ep) continue;
- if(!i->link) continue;
- if(!(i->routes&track_ep->routes)) continue;
- if(visited.count(i->link)) continue;
-
- if(tracks.count(i->link))
- find_routes(i->link, i->link->get_endpoint_by_link(track), route, visited);
+ if(i==track_ep) continue;
+ Track *link=track.get_link(i);
+ if(!link) continue;
+ if(visited.count(link)) continue;
+ if(!(eps[i].routes&eps[track_ep].routes)) continue;
+
+ if(tracks.count(link))
+ find_routes(*link, link->get_endpoint_by_link(track), route, visited);
else
{
- for(EndpointSeq::iterator j=endpoints.begin(); j!=endpoints.end(); ++j)
- if(j->track==track && j->track_ep==&*i)
+ for(vector<Endpoint>::iterator j=endpoints.begin(); j!=endpoints.end(); ++j)
+ if(j->track==&track && j->track_ep==i)
j->routes|=route;
}
}
-
- visited.erase(--visited.end());
}
unsigned Block::next_id=1;
-Block::Endpoint::Endpoint(Track *t, const Track::Endpoint *e):
+Block::Endpoint::Endpoint(Track *t, unsigned e):
track(t),
track_ep(e),
link(0),