]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/trackattachment.cpp
Keep TrackAttachment offset within allowed limits
[r2c2.git] / source / libr2c2 / trackattachment.cpp
1 #include "catalogue.h"
2 #include "layout.h"
3 #include "track.h"
4 #include "trackattachment.h"
5
6 using namespace std;
7
8 namespace R2C2 {
9
10 TrackAttachment::TrackAttachment(Layout &l):
11         Object(l),
12         offset(0)
13 {
14         layout.signal_object_removed.connect(sigc::mem_fun(this, &TrackAttachment::object_removed));
15 }
16
17 TrackAttachment::~TrackAttachment()
18 {
19         if(track)
20                 track->remove_attachment(*this);
21 }
22
23 void TrackAttachment::attach_to(const TrackIter &t, float o)
24 {
25         if(track)
26                 track->remove_attachment(*this);
27
28         track = t;
29         offset = o;
30
31         if(track)
32                 track->add_attachment(*this);
33 }
34
35 void TrackAttachment::attach_to_closest(float limit)
36 {
37         const set<Track *> &tracks = layout.get_all<Track>();
38         float dist = -1;
39         Track *trk = 0;
40         Vector closest;
41         for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
42                 if(!(*i)->get_type().is_turnout())
43                 {
44                         Snap sn;
45                         sn.position = position;
46                         sn.rotation = rotation;
47                         if((*i)->snap(sn, limit, SNAP_SEGMENT))
48                         {
49                                 float d = distance(position, sn.position);
50                                 if(d<dist || dist<0)
51                                 {
52                                         trk = *i;
53                                         closest = sn.position;
54                                         dist = d;
55                                 }
56                         }
57                 }
58
59         if(trk)
60         {
61                 unsigned nsn = trk->get_n_snap_nodes();
62                 for(unsigned i=0; i<nsn; ++i)
63                 {
64                         Snap sn = trk->get_snap_node(i);
65                         Angle adiff = abs(wrap_balanced(sn.rotation-rotation));
66                         if(adiff<Angle::quarter_turn())
67                         {
68                                 TrackIter iter(trk, i);
69                                 attach_to(iter, find_offset(iter, closest));
70                                 break;
71                         }
72                 }
73         }
74         else
75                 attach_to(TrackIter(), 0);
76 }
77
78 float TrackAttachment::find_offset(const TrackIter &trk, const Vector &point)
79 {
80         float margin = 0.01*layout.get_catalogue().get_scale();
81         Vector epp = trk->get_snap_node(trk.entry()).position;
82
83         float dist = distance(epp, point);
84         float offs = min(dist, trk->get_type().get_path_length(0));
85         while(1)
86         {
87                 TrackPoint tp = trk->get_point(trk.entry(), offs);
88                 float diff = dist-distance(epp, tp.pos);
89                 if(abs(diff)<margin)
90                         break;
91                 offs += diff;
92         }
93
94         return offs;
95 }
96
97 void TrackAttachment::object_removed(Object &o)
98 {
99         if(&o==track.track())
100                 track = TrackIter();
101 }
102
103 } // namespace R2C"