]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/trackattachment.cpp
Add an abstraction for things that are attached to tracks
[r2c2.git] / source / libr2c2 / trackattachment.cpp
diff --git a/source/libr2c2/trackattachment.cpp b/source/libr2c2/trackattachment.cpp
new file mode 100644 (file)
index 0000000..bed7db8
--- /dev/null
@@ -0,0 +1,95 @@
+#include "catalogue.h"
+#include "layout.h"
+#include "track.h"
+#include "trackattachment.h"
+
+using namespace std;
+
+namespace R2C2 {
+
+TrackAttachment::TrackAttachment(Layout &l):
+       Object(l),
+       offset(0)
+{ }
+
+TrackAttachment::~TrackAttachment()
+{
+       if(track)
+               track->remove_attachment(*this);
+}
+
+void TrackAttachment::attach_to(const TrackIter &t, float o)
+{
+       if(track)
+               track->remove_attachment(*this);
+
+       track = t;
+       offset = o;
+
+       if(track)
+               track->add_attachment(*this);
+}
+
+void TrackAttachment::attach_to_closest(float limit)
+{
+       const set<Track *> &tracks = layout.get_all<Track>();
+       float dist = -1;
+       Track *trk = 0;
+       Vector closest;
+       for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
+               if(!(*i)->get_type().is_turnout())
+               {
+                       Snap sn;
+                       sn.position = position;
+                       sn.rotation = rotation;
+                       if((*i)->snap(sn, limit, SNAP_SEGMENT))
+                       {
+                               float d = distance(position, sn.position);
+                               if(d<dist || dist<0)
+                               {
+                                       trk = *i;
+                                       closest = sn.position;
+                                       dist = d;
+                               }
+                       }
+               }
+
+       if(trk)
+       {
+               unsigned nsn = trk->get_n_snap_nodes();
+               for(unsigned i=0; i<nsn; ++i)
+               {
+                       Snap sn = trk->get_snap_node(i);
+                       Angle adiff = abs(wrap_balanced(sn.rotation-rotation));
+                       if(adiff<Angle::quarter_turn())
+                       {
+                               TrackIter iter(trk, i);
+                               attach_to(iter, find_offset(iter, closest));
+                               break;
+                       }
+               }
+       }
+       else
+               attach_to(TrackIter(), 0);
+}
+
+float TrackAttachment::find_offset(const TrackIter &trk, const Vector &point)
+{
+       float margin = 0.01*layout.get_catalogue().get_scale();
+       Vector epp = trk->get_snap_node(trk.entry()).position;
+
+       float dist = distance(epp, point);
+       float offs = dist;
+       while(1)
+       {
+               TrackPoint tp = trk->get_point(trk.entry(), offs);
+               float diff = dist-distance(epp, tp.pos);
+               if(abs(diff)<margin)
+                       break;
+               offs += diff;
+       }
+
+       return offs;
+}
+
+} // namespace R2C"