]> git.tdb.fi Git - r2c2.git/blob - source/designer/slopetool.cpp
d4a6ffb770f7b5fecd38b2b5c6e14544efa63e94
[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         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         if(done)
42                 return;
43
44         float start_z = tracks.front()->get_snap_node(tracks.front().entry()).position.z;
45         float end_z = tracks.back()->get_snap_node(tracks.back().reverse().entry()).position.z;
46
47         float length = total_length;
48         if(smooth)
49         {
50                 float dir = (end_z>start_z)?1:-1;
51                 float cur_slope = 0;
52                 while((end_z-start_z)*dir/length>cur_slope+0.025 && tracks.size()>2)
53                 {
54                         cur_slope += 0.025;
55                         Angle tilt = Geometry::atan(cur_slope);
56
57                         set_slope(tracks.front(), start_z, tilt);
58                         start_z += tracks.front()->get_type().get_path_length(0)*dir*cur_slope;
59                         length -= tracks.front()->get_type().get_path_length(0);
60                         tracks.pop_front();
61
62                         end_z -= tracks.back()->get_type().get_path_length(0)*dir*cur_slope;
63                         set_slope(tracks.back(), end_z, tilt);
64                         length -= tracks.back()->get_type().get_path_length(0);
65                         tracks.pop_back();
66                 }
67         }
68
69         float cur_z = start_z;
70         Angle tilt = Geometry::atan((end_z-start_z)/length);
71         for(list<TrackIter>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
72         {
73                 set_slope(*i, cur_z, tilt);
74                 cur_z += (*i)->get_type().get_path_length(0)*(end_z-start_z)/length;
75         }
76
77         set_done(true);
78 }
79
80 void SlopeTool::flatten()
81 {
82         if(done)
83                 return;
84
85         float z = 0;
86         for(list<TrackIter>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
87         {
88                 unsigned nsn = (*i)->get_n_snap_nodes();
89                 for(unsigned j=0; j<nsn; ++j)
90                         z += (*i)->get_snap_node(j).position.z/nsn;
91         }
92         z /= static_cast<int>(tracks.size());
93
94         for(list<TrackIter>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
95         {
96                 Vector p = (*i)->get_position();
97                 (*i)->set_position(Vector(p.x, p.y, z));
98                 (*i)->set_tilt(Angle::zero());
99         }
100
101         set_done(true);
102 }
103
104 void SlopeTool::set_slope(const TrackIter &track, float z, const Angle &tilt)
105 {
106         const Vector &p = track->get_position();
107         float dz = tan(tilt)*track->get_type().get_path_length(0);
108         if(track.entry()==1)
109         {
110                 track->set_position(Vector(p.x, p.y, z+dz));
111                 track->set_tilt(-tilt);
112         }
113         else
114         {
115                 track->set_position(Vector(p.x, p.y, z));
116                 track->set_tilt(tilt);
117         }
118 }