-#include "control.h"
-#include "block.h"
-#include "trafficmanager.h"
-#include "turnout.h"
+/* $Id$
-using namespace Msp;
+This file is part of the MSP Märklin suite
+Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <algorithm>
+#include "block.h"
+#include "layout.h"
+#include "route.h"
+#include "tracktype.h"
-#include <iostream>
using namespace std;
+using namespace Msp;
namespace Marklin {
-Block::Block(TrafficManager &tm, Track *start):
- trfc_mgr(tm),
- id(next_id++),
- sensor_id(0),
+Block::Block(Layout &l, Track &start):
+ layout(l),
+ id(0),
+ sensor_id(start.get_sensor_id()),
+ turnout_id(start.get_turnout_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()==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)
+ determine_id();
+
+ for(unsigned i=0; i<endpoints.size(); ++i)
{
- unsigned route=1<<n;
- i->routes|=route;
+ unsigned path = 1<<i;
+ endpoints[i].paths |= path;
set<Track *> visited;
- find_routes(i->track, i->track_ep, route, visited);
+ find_paths(*endpoints[i].track, endpoints[i].track_ep, path, visited);
}
+
+ layout.add_block(*this);
}
-const Block::Endpoint *Block::get_endpoint_by_link(const Block *other) const
+Block::~Block()
{
- for(EndpointSeq::const_iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
- if(i->link==other)
- return &*i;
+ for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
+ if(Block *blk = i->link)
+ {
+ i->link = 0;
+ blk->break_link(*this);
+ }
- return 0;
+ layout.remove_block(*this);
}
-const Block::Endpoint *Block::traverse(const Endpoint *ep) const
+bool Block::has_track(Track &t) const
{
- Track *track=ep->track;
- const Track::Endpoint *track_ep=ep->track_ep;
+ return tracks.count(&t);
+}
- while(1)
- {
- unsigned cur_route=0;
- unsigned tid=track->get_turnout_id();
- if(tid)
- {
- Turnout *turnout=trfc_mgr.get_control().get_turnout(tid);
- if(turnout)
- cur_route=turnout->get_route();
- }
+int Block::get_endpoint_by_link(Block &other) const
+{
+ for(unsigned i=0; i<endpoints.size(); ++i)
+ if(endpoints[i].link==&other)
+ return i;
+
+ return -1;
+}
+
+unsigned Block::traverse(unsigned epi, float *len) const
+{
+ return traverse(epi, 0, len);
+}
- const Track::Endpoint *other_ep=track->traverse(track_ep, cur_route);
- if(!other_ep)
- return 0;
+unsigned Block::traverse(unsigned epi, const Route *route, float *len) const
+{
+ if(epi>=endpoints.size())
+ throw InvalidParameterValue("Endpoint index out of range");
- for(EndpointSeq::const_iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
- if(i->track==track && i->track_ep==other_ep)
- return &*i;
+ const Endpoint &ep = endpoints[epi];
+ Track *track = ep.track;
+ unsigned track_ep = ep.track_ep;
- track_ep=track->get_endpoint_by_link(other_ep->link);
- track=other_ep->link;
+ if(len)
+ *len = 0;
- if(tracks.count(track)==0)
- return 0;
+ while(1)
+ {
+ int cur_path = -1;
+ if(track->get_turnout_id() && route)
+ cur_path = route->get_turnout(track->get_turnout_id());
+ if(cur_path==-1)
+ cur_path = track->get_active_path();
+
+ if(len)
+ *len += track->get_type().get_path_length(cur_path);
+
+ unsigned other_ep = track->traverse(track_ep, cur_path);
+ for(unsigned i=0; i<endpoints.size(); ++i)
+ if(endpoints[i].track==track && endpoints[i].track_ep==static_cast<unsigned>(other_ep))
+ return i;
+
+ Track *next = track->get_link(other_ep);
+ if(!tracks.count(next))
+ throw LogicError("Block traversal strayed out of the block");
+ 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;
+ i->link = &other;
+ j->link = this;
+
+ determine_id();
+ other.determine_id();
}
}
}
-bool Block::reserve(const Train *t)
+void Block::break_link(Block &other)
+{
+ for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
+ if(i->link==&other)
+ {
+ i->link = 0;
+ other.break_link(*this);
+ determine_id();
+ }
+}
+
+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(Train *t)
{
if(!t || !train)
{
- train=t;
+ train = t;
+ layout.signal_block_reserved.emit(*this, train);
return true;
}
else
return false;
}
-void Block::print_debug()
+void Block::find_paths(Track &track, unsigned track_ep, unsigned path, set<Track *> &visited)
{
- cout<<"Block "<<id;
- 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)
+ visited.insert(&track);
+
+ const vector<Marklin::Endpoint> &eps = track.get_type().get_endpoints();
+ for(unsigned i=0; i<eps.size(); ++i)
{
- cout<<" Endpoint, link=";
- if(i->link)
- cout<<i->link->id;
+ if(i==track_ep) continue;
+ Track *link = track.get_link(i);
+ if(!link) continue;
+ if(visited.count(link)) continue;
+ if(!(eps[i].paths&eps[track_ep].paths)) continue;
+
+ if(tracks.count(link))
+ find_paths(*link, link->get_endpoint_by_link(track), path, visited);
else
- cout<<"none";
- cout<<", routes="<<i->routes<<'\n';
+ {
+ for(vector<Endpoint>::iterator j=endpoints.begin(); j!=endpoints.end(); ++j)
+ if(j->track==&track && j->track_ep==i)
+ j->paths |= path;
+ }
}
}
-void Block::find_routes(Track *track, const Track::Endpoint *track_ep, unsigned route, std::set<Marklin::Track *> &visited)
+void Block::determine_id()
{
- visited.insert(track);
-
- const Track::EndpointSeq &eps=track->get_endpoints();
- for(Track::EndpointSeq::const_iterator i=eps.begin(); i!=eps.end(); ++i)
+ if(sensor_id)
+ id = 0x1000|sensor_id;
+ else if(turnout_id)
+ id = 0x2000|turnout_id;
+ else if(endpoints.size()==2)
{
- 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);
- else
- {
- for(EndpointSeq::iterator j=endpoints.begin(); j!=endpoints.end(); ++j)
- if(j->track==track && j->track_ep==&*i)
- j->routes|=route;
- }
+ unsigned id1 = endpoints[0].link ? endpoints[0].link->get_id() : 1;
+ unsigned id2 = endpoints[1].link ? endpoints[1].link->get_id() : 1;
+ if(id2<id1)
+ swap(id1, id2);
+ id = (id1<<16)|id2;
+ }
+ else if(endpoints.size()==1)
+ {
+ unsigned id1 = endpoints[0].link ? endpoints[0].link->get_id() : 1;
+ id = 0x10000 | id1;
}
-
- 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),
- routes(0)
+ paths(0)
{ }
} // namespace Marklin