]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/tracktype.cpp
Move path coercion to TrackType
[r2c2.git] / source / libr2c2 / tracktype.cpp
index 29bf47be5409d42eb79fbd9644fbf1a62e08e1bc..59b8f9ca275b4fe508b94fe77c32ec220ab83472 100644 (file)
@@ -1,4 +1,5 @@
 #include <cmath>
+#include <msp/geometry/union.h>
 #include "tracktype.h"
 
 using namespace std;
@@ -6,8 +7,9 @@ using namespace Msp;
 
 namespace R2C2 {
 
-TrackType::TrackType(const ArticleNumber &an):
-       art_nr(an),
+TrackType::TrackType(const ArticleNumber &an, const TrackAppearance &ta):
+       ObjectType(an),
+       appearance(ta),
        state_bits(0),
        autofit_preference(1)
 { }
@@ -42,6 +44,36 @@ unsigned TrackType::get_n_paths() const
        return n;
 }
 
+unsigned TrackType::coerce_path(unsigned entry, unsigned path) const
+{
+       const Endpoint &ep = get_endpoint(entry);
+       if(ep.has_path(path))
+               return path;
+
+       unsigned paths = get_paths();
+       if(paths>>(1<<state_bits))
+       {
+               /* There are more paths than can be expressed with state_bits, so
+               multiple paths are set at once.  See if one of the alternatives fits. */
+               unsigned step = 1<<state_bits;
+               for(unsigned p=path+step; paths>>p; p+=step)
+                       if(ep.has_path(p))
+                               return p;
+       }
+
+       // Find an endpoint that's connected to the entry and has the requested path
+       for(vector<Endpoint>::const_iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
+               if(i->has_path(path) && i->has_common_paths(ep))
+               {
+                       unsigned p = 1;
+                       for(unsigned m=i->paths&ep.paths; m>>p; ++p) ;
+                       return p-1;
+               }
+
+       // TODO crossings fall here
+       throw logic_error("TrackType::coerce_path");
+}
+
 bool TrackType::is_turnout() const
 {
        return endpoints.size()>2;
@@ -60,7 +92,7 @@ const TrackType::Endpoint &TrackType::get_endpoint(unsigned i) const
        return endpoints[i];
 }
 
-TrackPoint TrackType::get_point(unsigned epi, unsigned path, float d) const
+OrientedPoint TrackType::get_point(unsigned epi, unsigned path, float d) const
 {
        if(epi>=endpoints.size())
                throw out_of_range("TrackType::get_point");
@@ -69,16 +101,15 @@ TrackPoint TrackType::get_point(unsigned epi, unsigned path, float d) const
        unsigned part_ep = 0;
        for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
        {
-               if((endpoints[epi].paths&(1<<path)) && i->get_path()!=path)
+               if(endpoints[epi].has_path(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)
                {
-                       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)
+                       OrientedPoint p = i->get_point(j ? i->get_length() : 0);
+                       Vector span = p.position-endpoints[epi].pos;
+                       if(dot(span, span)<1e-6)
                        {
                                part = &*i;
                                part_ep = j;
@@ -96,9 +127,9 @@ TrackPoint TrackType::get_point(unsigned epi, unsigned path, float d) const
                {
                        if(part_ep==1)
                                d = plen-d;
-                       TrackPoint p = part->get_point(d);
+                       OrientedPoint p = part->get_point(d);
                        if(part_ep==1)
-                               p.dir += M_PI;
+                               p.rotation += Angle::half_turn();
                        return p;
                }
                else
@@ -113,13 +144,23 @@ TrackPoint TrackType::get_point(unsigned epi, unsigned path, float d) const
        }
 }
 
-bool TrackType::collide_ray(const Vector &start, const Vector &dir, float width) const
+OrientedPoint TrackType::get_nearest_point(const Vector &p) const
 {
+       OrientedPoint result;
+       float dist = -1;
+
        for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
-               if(i->collide_ray(start, dir, width))
-                       return true;
+       {
+               OrientedPoint n = i->get_nearest_point(p);
+               float d = distance(n.position, p);
+               if(d<dist || dist<0)
+               {
+                       result = n;
+                       dist = d;
+               }
+       }
 
-       return false;
+       return result;
 }
 
 void TrackType::collect_endpoints()
@@ -135,23 +176,18 @@ void TrackType::collect_endpoints()
                for(unsigned j=0; j<n_part_eps; ++j)
                        if(!i->get_link(j))
                        {
-                               TrackPoint p = i->get_point(j ? i->get_length() : 0);
+                               OrientedPoint p = i->get_point(j ? i->get_length() : 0);
                                if(j==0)
-                                       p.dir += M_PI;
+                                       p.rotation += Angle::half_turn();
 
                                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;
+                                       Vector d = k->pos-p.position;
 
-                                       float da = k->dir-p.dir;
-                                       while(da>M_PI)
-                                               da -= M_PI*2;
-                                       while(da<-M_PI)
-                                               da += M_PI*2;
+                                       Angle da = wrap_balanced(k->dir-p.rotation);
 
-                                       if(dx*dx+dy*dy<1e-6 && da>-0.01 && da<0.01)
+                                       if(dot(d, d)<1e-6 && abs(da).radians()<0.01)
                                        {
                                                k->paths |= 1<<i->get_path();
                                                found = true;
@@ -160,24 +196,23 @@ void TrackType::collect_endpoints()
                                }
 
                                if(!found)
-                                       endpoints.push_back(Endpoint(p.pos.x, p.pos.y, p.dir, 1<<i->get_path()));
+                                       endpoints.push_back(Endpoint(p.position.x, p.position.y, p.rotation, 1<<i->get_path()));
                        }
        }
 }
 
-TrackType::Endpoint::Endpoint(float x, float y, float d, unsigned p):
-       pos(x, y),
+TrackType::Endpoint::Endpoint(float x, float y, const Angle &d, unsigned p):
+       pos(x, y, 0),
        dir(d),
        paths(p)
 { }
 
 
 TrackType::Loader::Loader(TrackType &t):
-       Msp::DataFile::ObjectLoader<TrackType>(t),
+       DataFile::DerivedObjectLoader<TrackType, ObjectType::Loader>(t),
        state_bits_set(false)
 {
        add("autofit_preference", &TrackType::autofit_preference);
-       add("description", &TrackType::description);
        add("object",      &TrackType::object);
        add("state_bits",  &Loader::state_bits);
        add("part",        &Loader::part);
@@ -186,6 +221,13 @@ TrackType::Loader::Loader(TrackType &t):
 void TrackType::Loader::finish()
 {
        obj.collect_endpoints();
+       vector<const Shape *> shapes;
+       for(vector<TrackPart>::iterator i=obj.parts.begin(); i!=obj.parts.end(); ++i)
+       {
+               i->create_shape();
+               shapes.push_back(&i->get_shape());
+       }
+       obj.shape = Geometry::Union<float, 3>::from_iterator_range(shapes.begin(), shapes.end()).clone();
 }
 
 void TrackType::Loader::part()