3 This file is part of the MSP Märklin suite
4 Copyright © 2006-2008 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 = i->track->copy();
71 designer.get_layout()->add_track(*track);
72 new_tracks.push_back(track);
76 for(list<Track *>::iterator i=new_tracks.begin(); i!=new_tracks.end(); ++i)
78 selection.add_track(*i);
79 for(list<Track *>::iterator j=i; j!=new_tracks.end(); ++j)
81 (*i)->snap_to(**j, true);
85 void Manipulator::flatten()
90 if(tracks.empty()) return;
93 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
94 z += i->track->get_position().z+i->track->get_slope()/2;
97 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
99 Point p = i->track->get_position();
100 i->track->set_position(Point(p.x, p.y, z));
101 i->track->set_slope(0);
104 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
110 void Manipulator::even_slope(bool smooth)
115 if(neighbors.size()!=2)
118 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
119 if(i->track->get_type().get_endpoints().size()!=2)
122 list<Track *> tracks2;
123 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
124 tracks2.push_back(i->track);
128 list<TrackOrder> order;
129 Track *cur = *neighbors.begin();
130 while(tracks2.size())
133 for(list<Track *>::iterator i=tracks2.begin(); i!=tracks2.end(); ++i)
135 const vector<Track *> &links = (*i)->get_links();
142 else if(links[1]==cur)
150 order.push_back(TrackOrder(cur, rev));
151 total_len += cur->get_type().get_total_length();
154 set<Track *>::iterator nb = neighbors.begin();
155 int epi = (*nb)->get_endpoint_by_link(*order.front().track);
156 float start_z = (*nb)->get_endpoint_position(epi).z;
158 epi = (*nb)->get_endpoint_by_link(*order.back().track);
159 float end_z = (*nb)->get_endpoint_position(epi).z;
163 float dir = (end_z>start_z)?1:-1;
165 while((end_z-start_z)*dir/total_len>cur_slope+0.025 && order.size()>2)
169 float dz = order.front().track->get_type().get_total_length()*dir*cur_slope;
170 set_slope(order.front(), start_z, dz);
172 total_len -= order.front().track->get_type().get_total_length();
173 order.erase(order.begin());
175 dz = order.back().track->get_type().get_total_length()*dir*cur_slope;
176 set_slope(order.back(), end_z-dz, dz);
178 total_len -= order.back().track->get_type().get_total_length();
179 order.erase(--order.end());
183 float cur_z = start_z;
184 for(list<TrackOrder>::iterator i=order.begin(); i!=order.end(); ++i)
186 float dz = i->track->get_type().get_total_length()*(end_z-start_z)/total_len;
187 set_slope(*i, cur_z, dz);
191 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
197 void Manipulator::cancel()
204 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
206 i->track->set_position(Point(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z));
207 i->track->set_rotation(i->rot);
210 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
216 signal_done.emit(false);
219 void Manipulator::button_press(int, int, float, float, unsigned btn)
229 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
230 for(vector<MTrack>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
231 j->track->break_link(**i);
233 const set<Track *> <racks = designer.get_layout()->get_tracks();
234 for(set<Track *>::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
237 for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && ok); ++j)
241 for(vector<MTrack>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
242 j->track->snap_to(**i, true);
245 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
246 i->rot = i->track->get_rotation();
250 signal_done.emit(true);
254 void Manipulator::pointer_motion(int, int y, float gx, float gy)
257 gpointer = Point(gx, gy, 0);
261 Point delta(gpointer.x-move_origin.x, gpointer.y-move_origin.y, 0);
263 wrap_pos = Point(center.x+delta.x, center.y+delta.y, center.z);
264 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
266 i->track->set_position(Point(wrap_pos.x+i->pos.x, wrap_pos.y+i->pos.y, wrap_pos.z+i->pos.z));
267 i->track->set_rotation(i->rot);
270 const set<Track *> <racks = designer.get_layout()->get_tracks();
272 for(set<Track *>::const_iterator i=ltracks.begin(); (i!=ltracks.end() && !snapped); ++i)
275 for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && ok); ++j)
279 for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && !snapped); ++j)
280 if(j->track->snap_to(**i, false))
286 float da = snapped->track->get_rotation()-snapped->rot;
289 const Point &sp = snapped->track->get_position();
290 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
295 Point dp(i->pos.x-snapped->pos.x, i->pos.y-snapped->pos.y, 0);
296 i->track->set_position(Point(sp.x+c*dp.x-s*dp.y, sp.y+s*dp.x+c*dp.y, sp.z));
297 i->track->set_rotation(i->rot+da);
301 else if(mode==ROTATE)
303 float a = atan2(gpointer.y-center.y, gpointer.x-center.x);
304 angle += a-rot_origin;
308 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
310 float c = cos(angle);
311 float s = sin(angle);
312 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));
313 i->track->set_rotation(angle+i->rot);
316 else if(mode==ELEVATE)
318 float dz = (y-elev_origin)/1000.;
320 signal_status.emit(format("Elevation: %+.0fmm (%.0fmm)", dz*1000, (center.z+dz)*1000));
322 wrap_pos.z = center.z+dz;
323 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
324 i->track->set_position(Point(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z+dz));
326 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
331 void Manipulator::render()
334 glTranslatef(wrap_pos.x, wrap_pos.y, wrap_pos.z);
335 glRotatef(wrap_rot*180/M_PI, 0, 0, 1);
338 glColor4f(0, 1, 0, 0.5);
339 for(list<TrackWrap>::iterator i=wrap.begin(); i!=wrap.end(); ++i)
342 glTranslatef(i->pos.x, i->pos.y, i->pos.z);
343 glRotatef(i->rot*180/M_PI, 0, 0, 1);
345 glBegin(GL_LINE_LOOP);
346 glVertex2f(-i->width/2, -i->height/2);
347 glVertex2f(i->width/2, -i->height/2);
348 glVertex2f(i->width/2, i->height/2);
349 glVertex2f(-i->width/2, i->height/2);
360 void Manipulator::selection_changed()
366 const set<Track *> &stracks = selection.get_tracks();
367 tracks.insert(tracks.end(), stracks.begin(), stracks.end());
373 void Manipulator::update_wrap()
376 float min_x = 0, max_x = 0;
377 float min_y = 0, max_y = 0;
379 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
381 Track3D &t3d = designer.get_layout_3d()->get_track(*i->track);
384 float min_area = 100;
385 for(float a=0; a<M_PI; a+=0.01)
388 t3d.get_bounds(a, minp, maxp);
389 float area = (maxp.x-minp.x)*(maxp.y-minp.y);
394 float x = (minp.x+maxp.x)/2;
395 float y = (minp.y+maxp.y)/2;
396 tw.pos = Point(c*x-s*y, s*x+c*y, minp.z);
398 tw.width = maxp.x-minp.x+0.01;
399 tw.height = maxp.y-minp.y+0.01;
405 if(i==tracks.begin())
407 min_x = max_x = tw.pos.x;
408 min_y = max_y = tw.pos.y;
413 min_x = min(min_x, tw.pos.x);
414 max_x = max(max_x, tw.pos.x);
415 min_y = min(min_y, tw.pos.y);
416 max_y = max(max_y, tw.pos.y);
417 min_z = min(min_z, tw.pos.z);
422 center = Point((min_x+max_x)/2, (min_y+max_y)/2, min_z);
425 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
427 const Point &tp = i->track->get_position();
428 i->pos = Point(tp.x-center.x, tp.y-center.y, tp.z-center.z);
430 for(list<TrackWrap>::iterator i=wrap.begin(); i!=wrap.end(); ++i)
432 i->pos.x -= center.x;
433 i->pos.y -= center.y;
434 i->pos.z -= center.z;
438 void Manipulator::update_neighbors()
441 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
443 const vector<Track *> &links = i->track->get_links();
444 for(vector<Track *>::const_iterator j=links.begin(); j!=links.end(); ++j)
448 if(neighbors.count(*j))
452 for(vector<MTrack>::iterator k=tracks.begin(); (k!=tracks.end() && ok); ++k)
456 neighbors.insert(*j);
461 void Manipulator::set_slope(TrackOrder &track, float z, float dz)
463 const Point &p = track.track->get_position();
466 track.track->set_position(Point(p.x, p.y, z+dz));
467 track.track->set_slope(-dz);
471 track.track->set_position(Point(p.x, p.y, z));
472 track.track->set_slope(dz);
476 Manipulator::MTrack::MTrack(Track *t):
478 pos(track->get_position()),
479 rot(track->get_rotation())