--- /dev/null
+#include "slopetool.h"
+
+using namespace std;
+using namespace Msp;
+using namespace R2C2;
+
+SlopeTool::SlopeTool(Designer &d, Input::Mouse &m, const set<Object *> &objects):
+ Tool(d, m),
+ total_length(0)
+{
+ for(set<Object *>::const_iterator i=objects.begin(); i!=objects.end(); ++i)
+ {
+ unsigned nls = (*i)->get_n_link_slots();
+ if(nls!=2 || !dynamic_cast<Track *>(*i))
+ {
+ set_status("Must have linear tracks only");
+ return;
+ }
+ }
+
+ for(set<Object *>::const_iterator i=objects.begin(); i!=objects.end(); ++i)
+ {
+ unsigned nls = (*i)->get_n_link_slots();
+ for(unsigned j=0; j<nls; ++j)
+ if(Track *link = dynamic_cast<Track *>((*i)->get_link(j)))
+ if(!objects.count(link))
+ neighbors.push_back(link);
+ }
+
+ list<Track *> tmp_tracks;
+ for(set<Object *>::iterator i=objects.begin(); i!=objects.end(); ++i)
+ if(Track *track = dynamic_cast<Track *>(*i))
+ tmp_tracks.push_back(track);
+
+ Track *cur = neighbors.front();
+ while(!tmp_tracks.empty())
+ {
+ bool rev = false;
+ for(list<Track *>::iterator i=tmp_tracks.begin(); i!=tmp_tracks.end(); ++i)
+ {
+ const vector<Track *> &links = (*i)->get_links();
+ if(links[0]==cur)
+ {
+ cur = *i;
+ tmp_tracks.erase(i);
+ break;
+ }
+ else if(links[1]==cur)
+ {
+ cur = *i;
+ rev = true;
+ tmp_tracks.erase(i);
+ break;
+ }
+ }
+ tracks.push_back(TrackOrder(cur, rev));
+ total_length += cur->get_type().get_total_length();
+ }
+}
+
+void SlopeTool::even_slope(bool smooth)
+{
+ list<Track *>::iterator nb = neighbors.begin();
+ int epi = (*nb)->get_link_slot(*tracks.front().track);
+ float start_z = (*nb)->get_snap_node(epi).position.z;
+ ++nb;
+ epi = (*nb)->get_link_slot(*tracks.back().track);
+ float end_z = (*nb)->get_snap_node(epi).position.z;
+
+ float length = total_length;
+ if(smooth)
+ {
+ float dir = (end_z>start_z)?1:-1;
+ float cur_slope = 0;
+ while((end_z-start_z)*dir/length>cur_slope+0.025 && tracks.size()>2)
+ {
+ cur_slope += 0.025;
+ Angle tilt = Geometry::atan(cur_slope);
+
+ set_slope(tracks.front(), start_z, tilt);
+ start_z += tracks.front().track->get_type().get_path_length(0)*dir*cur_slope;
+ length -= tracks.front().track->get_type().get_path_length(0);
+ tracks.pop_front();
+
+ end_z -= tracks.back().track->get_type().get_path_length(0)*dir*cur_slope;
+ set_slope(tracks.back(), end_z, tilt);
+ length -= tracks.back().track->get_type().get_path_length(0);
+ tracks.pop_back();
+ }
+ }
+
+ float cur_z = start_z;
+ Angle tilt = Geometry::atan((end_z-start_z)/length);
+ for(list<TrackOrder>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ {
+ set_slope(*i, cur_z, tilt);
+ cur_z += i->track->get_type().get_path_length(0)*(end_z-start_z)/length;
+ }
+}
+
+void SlopeTool::flatten()
+{
+ float z = 0;
+ for(list<TrackOrder>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ {
+ unsigned nsn = i->track->get_n_snap_nodes();
+ for(unsigned j=0; j<nsn; ++j)
+ z += i->track->get_snap_node(j).position.z/nsn;
+ }
+ z /= static_cast<int>(tracks.size());
+
+ for(list<TrackOrder>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ {
+ Vector p = i->track->get_position();
+ i->track->set_position(Vector(p.x, p.y, z));
+ i->track->set_tilt(Angle::zero());
+ }
+}
+
+void SlopeTool::set_slope(TrackOrder &track, float z, const Angle &tilt)
+{
+ const Vector &p = track.track->get_position();
+ float dz = tan(tilt)*track.track->get_type().get_path_length(0);
+ if(track.rev)
+ {
+ track.track->set_position(Vector(p.x, p.y, z+dz));
+ track.track->set_tilt(-tilt);
+ }
+ else
+ {
+ track.track->set_position(Vector(p.x, p.y, z));
+ track.track->set_tilt(tilt);
+ }
+}