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