]> git.tdb.fi Git - r2c2.git/blobdiff - source/libmarklin/tracktype.cpp
Make LCD output selectable at runtime through an extra I/O pin
[r2c2.git] / source / libmarklin / tracktype.cpp
index cd832eb1997140e95c9e68eca7910c4d1c90dc6c..9f2979bebff80ca4112eb2c3013d6a4209da1ddf 100644 (file)
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2006-2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
 #include <cmath>
 #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");
 
-       for(vector<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end();)
+       return endpoints[i];
+}
+
+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(!part)
+               throw Exception("Internal error (endpoint does not match any part)");
 
-               if(rm)
-                       i=endpoints.erase(i);
+       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