/* $Id$
This file is part of the MSP Märklin suite
-Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa
+Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa
Distributed under the GPL
*/
#include "tracktype.h"
using namespace std;
+using namespace Msp;
namespace Marklin {
-TrackType::TrackType(unsigned a):
- art_nr(a)
+TrackType::TrackType(const ArticleNumber &an):
+ art_nr(an),
+ double_address(false),
+ autofit_preference(1)
{ }
float TrackType::get_total_length() const
{
- return get_route_length(-1);
+ return get_path_length(-1);
}
-float TrackType::get_route_length(int r) const
+float TrackType::get_path_length(int p) const
{
- float len=0;
+ float len = 0;
for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
- if(r<0 || i->route==static_cast<unsigned>(r))
- {
- float l=i->length;
- if(i->radius)
- l*=abs(i->radius);
- len+=l;
- }
+ if(p<0 || i->get_path()==static_cast<unsigned>(p))
+ len += i->get_length();
return len;
}
-unsigned TrackType::get_n_routes() const
+unsigned TrackType::get_paths() const
{
- unsigned n=1;
+ unsigned mask = 0;
for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
- if(i->route>=n)
- n=i->route+1;
+ mask |= 1<<i->get_path();
+ return mask;
+}
+
+unsigned TrackType::get_n_paths() const
+{
+ unsigned n = 0;
+ for(unsigned mask = get_paths(); mask; ++n)
+ mask &= mask-1;
return n;
}
-void TrackType::collect_endpoints()
+bool TrackType::is_turnout() const
{
- endpoints.clear();
+ return endpoints.size()>2;
+}
- for(vector<TrackPart>::iterator i=parts.begin(); i!=parts.end(); ++i)
- i->collect_endpoints(endpoints);
+bool TrackType::is_dead_end() const
+{
+ return endpoints.size()<2;
+}
+
+const TrackType::Endpoint &TrackType::get_endpoint(unsigned i) const
+{
+ if(i>=endpoints.size())
+ throw InvalidParameterValue("Endpoint index out of range");
+
+ return endpoints[i];
+}
- for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end();)
+TrackPoint TrackType::get_point(unsigned epi, unsigned path, float d) const
+{
+ if(epi>=endpoints.size())
+ throw InvalidParameterValue("Endpoint index out of range");
+
+ const TrackPart *part = 0;
+ unsigned part_ep = 0;
+ for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
{
- bool rm=false;
- for(vector<Endpoint>::iterator j=i+1; j!=endpoints.end();)
+ if((endpoints[epi].paths&(1<<path)) && i->get_path()!=path)
+ continue;
+
+ unsigned n_part_eps = (i->is_dead_end() ? 1 : 2);
+ for(unsigned j=0; j<n_part_eps; ++j)
{
- float dx=i->x-j->x;
- float dy=i->y-j->y;
- if(dx*dx+dy*dy<0.0001)
+ TrackPoint p = i->get_point(j ? i->get_length() : 0);
+ float dx = p.pos.x-endpoints[epi].pos.x;
+ float dy = p.pos.y-endpoints[epi].pos.y;
+ if(dx*dx+dy*dy<1e-6)
{
- float da=i->dir-j->dir;
- if(da<-M_PI)
- da+=M_PI*2;
- if(da>M_PI)
- da-=M_PI*2;
- if(da<-3.1 || da>3.1)
- rm=true;
- i->routes|=j->routes;
- j=endpoints.erase(j);
+ part = &*i;
+ part_ep = j;
}
- else
- ++j;
}
+ }
- if(rm)
- i=endpoints.erase(i);
+ if(!part)
+ throw Exception("Internal error (endpoint does not match any part)");
+
+ while(1)
+ {
+ float plen = part->get_length();
+ if(d<=plen)
+ {
+ if(part_ep==1)
+ d = plen-d;
+ TrackPoint p = part->get_point(d);
+ if(part_ep==1)
+ p.dir += M_PI;
+ return p;
+ }
else
- ++i;
+ {
+ d -= plen;
+ TrackPart *next = part->get_link(1-part_ep);
+ if(!next)
+ throw InvalidParameterValue("Distance out of range");
+ part_ep = (next->get_link(0)==part ? 0 : 1);
+ part = next;
+ }
+ }
+}
+
+void TrackType::collect_endpoints()
+{
+ endpoints.clear();
+
+ for(vector<TrackPart>::iterator i=parts.begin(); i!=parts.end(); ++i)
+ {
+ for(vector<TrackPart>::iterator j=i; ++j!=parts.end();)
+ i->check_link(*j);
+
+ unsigned n_part_eps = (i->is_dead_end() ? 1 : 2);
+ for(unsigned j=0; j<n_part_eps; ++j)
+ if(!i->get_link(j))
+ {
+ TrackPoint p = i->get_point(j ? i->get_length() : 0);
+ if(j==0)
+ p.dir += M_PI;
+
+ bool found = false;
+ for(vector<Endpoint>::iterator k=endpoints.begin(); k!=endpoints.end(); ++k)
+ {
+ float dx = k->pos.x-p.pos.x;
+ float dy = k->pos.y-p.pos.y;
+
+ float da = k->dir-p.dir;
+ while(da>M_PI)
+ da -= M_PI*2;
+ while(da<-M_PI)
+ da += M_PI*2;
+
+ if(dx*dx+dy*dy<1e-6 && da>-0.01 && da<0.01)
+ {
+ k->paths |= 1<<i->get_path();
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)
+ endpoints.push_back(Endpoint(p.pos.x, p.pos.y, p.dir, 1<<i->get_path()));
+ }
}
}
+TrackType::Endpoint::Endpoint(float x, float y, float d, unsigned p):
+ pos(x, y),
+ dir(d),
+ paths(p)
+{ }
+
TrackType::Loader::Loader(TrackType &t):
- ttype(t)
+ Msp::DataFile::BasicLoader<TrackType>(t)
{
+ add("autofit_preference", &TrackType::autofit_preference);
add("description", &TrackType::description);
+ add("double_address", &TrackType::double_address);
add("part", &Loader::part);
}
void TrackType::Loader::finish()
{
- ttype.collect_endpoints();
+ obj.collect_endpoints();
}
void TrackType::Loader::part()
{
TrackPart p;
load_sub(p);
- ttype.parts.push_back(p);
+ obj.parts.push_back(p);
}
} // namespace Marklin