]> git.tdb.fi Git - r2c2.git/blob - source/designer/slopetool.cpp
Avoid crash in SlopeTool if nothing is selected
[r2c2.git] / source / 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         if(objects.empty())
13         {
14                 set_status("Nothing selected");
15                 set_done(false);
16                 return;
17         }
18
19         for(set<Object *>::const_iterator i=objects.begin(); i!=objects.end(); ++i)
20                 if(!dynamic_cast<Track *>(*i) || (*i)->get_n_link_slots()!=2)
21                 {
22                         set_status("Must have linear tracks only");
23                         set_done(false);
24                         return;
25                 }
26
27         TrackIter track;
28         for(set<Object *>::const_iterator i=objects.begin(); (!track && i!=objects.end()); ++i)
29                 if(Track *t = dynamic_cast<Track *>(*i))
30                 {
31                         unsigned nls = t->get_n_link_slots();
32                         for(unsigned j=0; (!track && j<nls); ++j)
33                                 if(!objects.count((*i)->get_link(j)))
34                                         track = TrackIter(t, j);
35                 }
36
37         total_length = 0;
38         while(track && objects.count(track.track()))
39         {
40                 tracks.push_back(track);
41                 total_length += track->get_type().get_path_length(0);
42                 track = track.next();
43         }
44 }
45
46 void SlopeTool::even_slope(bool smooth)
47 {
48         if(done)
49                 return;
50
51         float start_z = tracks.front()->get_snap_node(tracks.front().entry()).position.z;
52         float end_z = tracks.back()->get_snap_node(tracks.back().reverse().entry()).position.z;
53
54         float length = total_length;
55         if(smooth)
56         {
57                 float dir = (end_z>start_z)?1:-1;
58                 float cur_slope = 0;
59                 while((end_z-start_z)*dir/length>cur_slope+0.025 && tracks.size()>2)
60                 {
61                         cur_slope += 0.025;
62                         Angle tilt = Geometry::atan(cur_slope);
63
64                         set_slope(tracks.front(), start_z, tilt);
65                         start_z += tracks.front()->get_type().get_path_length(0)*dir*cur_slope;
66                         length -= tracks.front()->get_type().get_path_length(0);
67                         tracks.pop_front();
68
69                         end_z -= tracks.back()->get_type().get_path_length(0)*dir*cur_slope;
70                         set_slope(tracks.back(), end_z, tilt);
71                         length -= tracks.back()->get_type().get_path_length(0);
72                         tracks.pop_back();
73                 }
74         }
75
76         float cur_z = start_z;
77         Angle tilt = Geometry::atan((end_z-start_z)/length);
78         for(list<TrackIter>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
79         {
80                 set_slope(*i, cur_z, tilt);
81                 cur_z += (*i)->get_type().get_path_length(0)*(end_z-start_z)/length;
82         }
83
84         set_done(true);
85 }
86
87 void SlopeTool::flatten()
88 {
89         if(done)
90                 return;
91
92         float z = 0;
93         for(list<TrackIter>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
94         {
95                 unsigned nsn = (*i)->get_n_snap_nodes();
96                 for(unsigned j=0; j<nsn; ++j)
97                         z += (*i)->get_snap_node(j).position.z/nsn;
98         }
99         z /= static_cast<int>(tracks.size());
100
101         for(list<TrackIter>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
102         {
103                 Vector p = (*i)->get_position();
104                 (*i)->set_position(Vector(p.x, p.y, z));
105                 (*i)->set_tilt(Angle::zero());
106         }
107
108         set_done(true);
109 }
110
111 void SlopeTool::set_slope(const TrackIter &track, float z, const Angle &tilt)
112 {
113         const Vector &p = track->get_position();
114         float dz = tan(tilt)*track->get_type().get_path_length(0);
115         if(track.entry()==1)
116         {
117                 track->set_position(Vector(p.x, p.y, z+dz));
118                 track->set_tilt(-tilt);
119         }
120         else
121         {
122                 track->set_position(Vector(p.x, p.y, z));
123                 track->set_tilt(tilt);
124         }
125 }