3 This file is part of the MSP Märklin suite
4 Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
11 #include <msp/strings/formatter.h>
12 #include "3d/layout.h"
13 #include "libmarklin/tracktype.h"
15 #include "manipulator.h"
16 #include "selection.h"
19 using namespace Marklin;
22 Manipulator::Manipulator(Designer &d, Selection &s):
29 selection.signal_changed.connect(sigc::mem_fun(this, &Manipulator::selection_changed));
32 void Manipulator::start_move()
37 move_origin = gpointer;
42 void Manipulator::start_rotate()
47 rot_origin = atan2(gpointer.y-center.y, gpointer.x-center.x);
52 void Manipulator::start_elevate()
57 elev_origin = pointer_y;
62 void Manipulator::duplicate()
67 list<Track *> new_tracks;
68 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
70 Track *track = new Track(*designer.get_layout(), i->track->get_type());
71 new_tracks.push_back(track);
75 for(list<Track *>::iterator i=new_tracks.begin(); i!=new_tracks.end(); ++i)
77 selection.add_track(*i);
78 for(list<Track *>::iterator j=i; j!=new_tracks.end(); ++j)
80 (*i)->snap_to(**j, true);
84 void Manipulator::flatten()
89 if(tracks.empty()) return;
92 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
93 z += i->track->get_position().z+i->track->get_slope()/2;
96 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
98 Point p = i->track->get_position();
99 i->track->set_position(Point(p.x, p.y, z));
100 i->track->set_slope(0);
103 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
109 void Manipulator::even_slope(bool smooth)
114 if(neighbors.size()!=2)
117 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
118 if(i->track->get_type().get_endpoints().size()!=2)
121 list<Track *> tracks2;
122 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
123 tracks2.push_back(i->track);
127 list<TrackOrder> order;
128 Track *cur = *neighbors.begin();
129 while(tracks2.size())
132 for(list<Track *>::iterator i=tracks2.begin(); i!=tracks2.end(); ++i)
134 const vector<Track *> &links = (*i)->get_links();
141 else if(links[1]==cur)
149 order.push_back(TrackOrder(cur, rev));
150 total_len += cur->get_type().get_total_length();
153 set<Track *>::iterator nb = neighbors.begin();
154 int epi = (*nb)->get_endpoint_by_link(*order.front().track);
155 float start_z = (*nb)->get_endpoint_position(epi).z;
157 epi = (*nb)->get_endpoint_by_link(*order.back().track);
158 float end_z = (*nb)->get_endpoint_position(epi).z;
162 float dir = (end_z>start_z)?1:-1;
164 while((end_z-start_z)*dir/total_len>cur_slope+0.025 && order.size()>2)
168 float dz = order.front().track->get_type().get_total_length()*dir*cur_slope;
169 set_slope(order.front(), start_z, dz);
171 total_len -= order.front().track->get_type().get_total_length();
172 order.erase(order.begin());
174 dz = order.back().track->get_type().get_total_length()*dir*cur_slope;
175 set_slope(order.back(), end_z-dz, dz);
177 total_len -= order.back().track->get_type().get_total_length();
178 order.erase(--order.end());
182 float cur_z = start_z;
183 for(list<TrackOrder>::iterator i=order.begin(); i!=order.end(); ++i)
185 float dz = i->track->get_type().get_total_length()*(end_z-start_z)/total_len;
186 set_slope(*i, cur_z, dz);
190 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
196 void Manipulator::cancel()
203 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
205 i->track->set_position(Point(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z));
206 i->track->set_rotation(i->rot);
209 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
215 signal_done.emit(false);
218 void Manipulator::button_press(int, int, float, float, unsigned btn)
228 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
229 for(vector<MTrack>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
230 j->track->break_link(**i);
232 const set<Track *> <racks = designer.get_layout()->get_tracks();
233 for(set<Track *>::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
236 for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && ok); ++j)
240 for(vector<MTrack>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
241 j->track->snap_to(**i, true);
244 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
245 i->rot = i->track->get_rotation();
249 signal_done.emit(true);
253 void Manipulator::pointer_motion(int, int y, float gx, float gy)
256 gpointer = Point(gx, gy, 0);
260 Point delta(gpointer.x-move_origin.x, gpointer.y-move_origin.y, 0);
262 wrap_pos = Point(center.x+delta.x, center.y+delta.y, center.z);
263 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
265 i->track->set_position(Point(wrap_pos.x+i->pos.x, wrap_pos.y+i->pos.y, wrap_pos.z+i->pos.z));
266 i->track->set_rotation(i->rot);
269 const set<Track *> <racks = designer.get_layout()->get_tracks();
271 for(set<Track *>::const_iterator i=ltracks.begin(); (i!=ltracks.end() && !snapped); ++i)
274 for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && ok); ++j)
278 for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && !snapped); ++j)
279 if(j->track->snap_to(**i, false))
285 float da = snapped->track->get_rotation()-snapped->rot;
288 const Point &sp = snapped->track->get_position();
289 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
294 Point dp(i->pos.x-snapped->pos.x, i->pos.y-snapped->pos.y, 0);
295 i->track->set_position(Point(sp.x+c*dp.x-s*dp.y, sp.y+s*dp.x+c*dp.y, sp.z));
296 i->track->set_rotation(i->rot+da);
300 else if(mode==ROTATE)
302 float a = atan2(gpointer.y-center.y, gpointer.x-center.x);
303 angle += a-rot_origin;
307 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
309 float c = cos(angle);
310 float s = sin(angle);
311 i->track->set_position(Point(center.x+c*i->pos.x-s*i->pos.y, center.y+s*i->pos.x+c*i->pos.y, center.z*i->pos.z));
312 i->track->set_rotation(angle+i->rot);
315 else if(mode==ELEVATE)
317 float dz = (y-elev_origin)/1000.;
319 signal_status.emit(format("Elevation: %+.0fmm (%.0fmm)", dz*1000, (center.z+dz)*1000));
321 wrap_pos.z = center.z+dz;
322 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
323 i->track->set_position(Point(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z+dz));
325 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
330 void Manipulator::render()
333 glTranslatef(wrap_pos.x, wrap_pos.y, wrap_pos.z);
334 glRotatef(wrap_rot*180/M_PI, 0, 0, 1);
337 glColor4f(0, 1, 0, 0.5);
338 for(list<TrackWrap>::iterator i=wrap.begin(); i!=wrap.end(); ++i)
341 glTranslatef(i->pos.x, i->pos.y, i->pos.z);
342 glRotatef(i->rot*180/M_PI, 0, 0, 1);
344 glBegin(GL_LINE_LOOP);
345 glVertex2f(-i->width/2, -i->height/2);
346 glVertex2f(i->width/2, -i->height/2);
347 glVertex2f(i->width/2, i->height/2);
348 glVertex2f(-i->width/2, i->height/2);
357 void Manipulator::selection_changed()
363 const set<Track *> &stracks = selection.get_tracks();
364 tracks.insert(tracks.end(), stracks.begin(), stracks.end());
370 void Manipulator::update_wrap()
373 float min_x = 0, max_x = 0;
374 float min_y = 0, max_y = 0;
376 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
378 Track3D &t3d = designer.get_layout_3d()->get_track(*i->track);
381 float min_area = 100;
382 for(float a=0; a<M_PI; a+=0.01)
385 t3d.get_bounds(a, minp, maxp);
386 float area = (maxp.x-minp.x)*(maxp.y-minp.y);
391 float x = (minp.x+maxp.x)/2;
392 float y = (minp.y+maxp.y)/2;
393 tw.pos = Point(c*x-s*y, s*x+c*y, minp.z);
395 tw.width = maxp.x-minp.x+0.01;
396 tw.height = maxp.y-minp.y+0.01;
402 if(i==tracks.begin())
404 min_x = max_x = tw.pos.x;
405 min_y = max_y = tw.pos.y;
410 min_x = min(min_x, tw.pos.x);
411 max_x = max(max_x, tw.pos.x);
412 min_y = min(min_y, tw.pos.y);
413 max_y = max(max_y, tw.pos.y);
414 min_z = min(min_z, tw.pos.z);
419 center = Point((min_x+max_x)/2, (min_y+max_y)/2, min_z);
422 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
424 const Point &tp = i->track->get_position();
425 i->pos = Point(tp.x-center.x, tp.y-center.y, tp.z-center.z);
427 for(list<TrackWrap>::iterator i=wrap.begin(); i!=wrap.end(); ++i)
429 i->pos.x -= center.x;
430 i->pos.y -= center.y;
431 i->pos.z -= center.z;
435 void Manipulator::update_neighbors()
438 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
440 const vector<Track *> &links = i->track->get_links();
441 for(vector<Track *>::const_iterator j=links.begin(); j!=links.end(); ++j)
445 if(neighbors.count(*j))
449 for(vector<MTrack>::iterator k=tracks.begin(); (k!=tracks.end() && ok); ++k)
453 neighbors.insert(*j);
458 void Manipulator::set_slope(TrackOrder &track, float z, float dz)
460 const Point &p = track.track->get_position();
463 track.track->set_position(Point(p.x, p.y, z+dz));
464 track.track->set_slope(-dz);
468 track.track->set_position(Point(p.x, p.y, z));
469 track.track->set_slope(dz);
473 Manipulator::MTrack::MTrack(Track *t):
475 pos(track->get_position()),
476 rot(track->get_rotation())