]> git.tdb.fi Git - r2c2.git/blob - designer/slopetool.cpp
Don't crash if a train has no router
[r2c2.git] / designer / slopetool.cpp
1 #include "libr2c2/track.h"
2 #include "slopetool.h"
3
4 using namespace std;
5 using namespace Msp;
6 using namespace R2C2;
7
8 SlopeTool::SlopeTool(Designer &d, Input::Keyboard &k, Input::Mouse &m, const set<Object *> &objects):
9         Tool(d, k, m),
10         total_length(0)
11 {
12         for(set<Object *>::const_iterator i=objects.begin(); i!=objects.end(); ++i)
13                 if(!dynamic_cast<Track *>(*i) || (*i)->get_n_link_slots()!=2)
14                 {
15                         set_status("Must have linear tracks only");
16                         set_done(false);
17                         return;
18                 }
19
20         TrackIter track;
21         for(set<Object *>::const_iterator i=objects.begin(); (!track && i!=objects.end()); ++i)
22                 if(Track *t = dynamic_cast<Track *>(*i))
23                 {
24                         unsigned nls = t->get_n_link_slots();
25                         for(unsigned j=0; (!track && j<nls); ++j)
26                                 if(!objects.count((*i)->get_link(j)))
27                                         track = TrackIter(t, j);
28                 }
29
30         total_length = 0;
31         while(track && objects.count(track.track()))
32         {
33                 tracks.push_back(track);
34                 total_length += track->get_type().get_path_length(0);
35                 track = track.next();
36         }
37 }
38
39 void SlopeTool::even_slope(bool smooth)
40 {
41         float start_z = tracks.front()->get_snap_node(tracks.front().entry()).position.z;
42         float end_z = tracks.back()->get_snap_node(tracks.back().reverse().entry()).position.z;
43
44         float length = total_length;
45         if(smooth)
46         {
47                 float dir = (end_z>start_z)?1:-1;
48                 float cur_slope = 0;
49                 while((end_z-start_z)*dir/length>cur_slope+0.025 && tracks.size()>2)
50                 {
51                         cur_slope += 0.025;
52                         Angle tilt = Geometry::atan(cur_slope);
53
54                         set_slope(tracks.front(), start_z, tilt);
55                         start_z += tracks.front()->get_type().get_path_length(0)*dir*cur_slope;
56                         length -= tracks.front()->get_type().get_path_length(0);
57                         tracks.pop_front();
58
59                         end_z -= tracks.back()->get_type().get_path_length(0)*dir*cur_slope;
60                         set_slope(tracks.back(), end_z, tilt);
61                         length -= tracks.back()->get_type().get_path_length(0);
62                         tracks.pop_back();
63                 }
64         }
65
66         float cur_z = start_z;
67         Angle tilt = Geometry::atan((end_z-start_z)/length);
68         for(list<TrackIter>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
69         {
70                 set_slope(*i, cur_z, tilt);
71                 cur_z += (*i)->get_type().get_path_length(0)*(end_z-start_z)/length;
72         }
73 }
74
75 void SlopeTool::flatten()
76 {
77         float z = 0;
78         for(list<TrackIter>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
79         {
80                 unsigned nsn = (*i)->get_n_snap_nodes();
81                 for(unsigned j=0; j<nsn; ++j)
82                         z += (*i)->get_snap_node(j).position.z/nsn;
83         }
84         z /= static_cast<int>(tracks.size());
85
86         for(list<TrackIter>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
87         {
88                 Vector p = (*i)->get_position();
89                 (*i)->set_position(Vector(p.x, p.y, z));
90                 (*i)->set_tilt(Angle::zero());
91         }
92 }
93
94 void SlopeTool::set_slope(const TrackIter &track, float z, const Angle &tilt)
95 {
96         const Vector &p = track->get_position();
97         float dz = tan(tilt)*track->get_type().get_path_length(0);
98         if(track.entry()==1)
99         {
100                 track->set_position(Vector(p.x, p.y, z+dz));
101                 track->set_tilt(-tilt);
102         }
103         else
104         {
105                 track->set_position(Vector(p.x, p.y, z));
106                 track->set_tilt(tilt);
107         }
108 }