+#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"