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