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 track->set_position(i->track->get_position());
72 track->set_rotation(i->track->get_rotation());
73 new_tracks.push_back(track);
77 for(list<Track *>::iterator i=new_tracks.begin(); i!=new_tracks.end(); ++i)
79 selection.add_track(*i);
80 for(list<Track *>::iterator j=i; j!=new_tracks.end(); ++j)
82 (*i)->snap_to(**j, true);
86 void Manipulator::flatten()
91 if(tracks.empty()) return;
94 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
95 z += i->track->get_position().z+i->track->get_slope()/2;
98 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
100 Point p = i->track->get_position();
101 i->track->set_position(Point(p.x, p.y, z));
102 i->track->set_slope(0);
105 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
111 void Manipulator::even_slope(bool smooth)
116 if(neighbors.size()!=2)
119 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
120 if(i->track->get_type().get_endpoints().size()!=2)
123 list<Track *> tracks2;
124 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
125 tracks2.push_back(i->track);
129 list<TrackOrder> order;
130 Track *cur = *neighbors.begin();
131 while(tracks2.size())
134 for(list<Track *>::iterator i=tracks2.begin(); i!=tracks2.end(); ++i)
136 const vector<Track *> &links = (*i)->get_links();
143 else if(links[1]==cur)
151 order.push_back(TrackOrder(cur, rev));
152 total_len += cur->get_type().get_total_length();
155 set<Track *>::iterator nb = neighbors.begin();
156 int epi = (*nb)->get_endpoint_by_link(*order.front().track);
157 float start_z = (*nb)->get_endpoint_position(epi).z;
159 epi = (*nb)->get_endpoint_by_link(*order.back().track);
160 float end_z = (*nb)->get_endpoint_position(epi).z;
164 float dir = (end_z>start_z)?1:-1;
166 while((end_z-start_z)*dir/total_len>cur_slope+0.025 && order.size()>2)
170 float dz = order.front().track->get_type().get_total_length()*dir*cur_slope;
171 set_slope(order.front(), start_z, dz);
173 total_len -= order.front().track->get_type().get_total_length();
174 order.erase(order.begin());
176 dz = order.back().track->get_type().get_total_length()*dir*cur_slope;
177 set_slope(order.back(), end_z-dz, dz);
179 total_len -= order.back().track->get_type().get_total_length();
180 order.erase(--order.end());
184 float cur_z = start_z;
185 for(list<TrackOrder>::iterator i=order.begin(); i!=order.end(); ++i)
187 float dz = i->track->get_type().get_total_length()*(end_z-start_z)/total_len;
188 set_slope(*i, cur_z, dz);
192 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
198 void Manipulator::cancel()
205 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
207 i->track->set_position(Point(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z));
208 i->track->set_rotation(i->rot);
211 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
217 signal_done.emit(false);
220 void Manipulator::button_press(int, int, float, float, unsigned btn)
230 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
231 for(vector<MTrack>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
232 j->track->break_link(**i);
234 const set<Track *> <racks = designer.get_layout()->get_tracks();
235 for(set<Track *>::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
238 for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && ok); ++j)
242 for(vector<MTrack>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
243 j->track->snap_to(**i, true);
246 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
247 i->rot = i->track->get_rotation();
251 signal_done.emit(true);
255 void Manipulator::pointer_motion(int, int y, float gx, float gy)
258 gpointer = Point(gx, gy, 0);
262 Point delta(gpointer.x-move_origin.x, gpointer.y-move_origin.y, 0);
264 wrap_pos = Point(center.x+delta.x, center.y+delta.y, center.z);
265 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
267 i->track->set_position(Point(wrap_pos.x+i->pos.x, wrap_pos.y+i->pos.y, wrap_pos.z+i->pos.z));
268 i->track->set_rotation(i->rot);
271 const set<Track *> <racks = designer.get_layout()->get_tracks();
273 for(set<Track *>::const_iterator i=ltracks.begin(); (i!=ltracks.end() && !snapped); ++i)
276 for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && ok); ++j)
280 for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && !snapped); ++j)
281 if(j->track->snap_to(**i, false))
287 float da = snapped->track->get_rotation()-snapped->rot;
290 const Point &sp = snapped->track->get_position();
291 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
296 Point dp(i->pos.x-snapped->pos.x, i->pos.y-snapped->pos.y, 0);
297 i->track->set_position(Point(sp.x+c*dp.x-s*dp.y, sp.y+s*dp.x+c*dp.y, sp.z));
298 i->track->set_rotation(i->rot+da);
302 else if(mode==ROTATE)
304 float a = atan2(gpointer.y-center.y, gpointer.x-center.x);
305 angle += a-rot_origin;
309 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
311 float c = cos(angle);
312 float s = sin(angle);
313 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));
314 i->track->set_rotation(angle+i->rot);
317 else if(mode==ELEVATE)
319 float dz = (y-elev_origin)/1000.;
321 signal_status.emit(format("Elevation: %+.0fmm (%.0fmm)", dz*1000, (center.z+dz)*1000));
323 wrap_pos.z = center.z+dz;
324 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
325 i->track->set_position(Point(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z+dz));
327 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
332 void Manipulator::render()
335 glTranslatef(wrap_pos.x, wrap_pos.y, wrap_pos.z);
336 glRotatef(wrap_rot*180/M_PI, 0, 0, 1);
339 glColor4f(0, 1, 0, 0.5);
340 for(list<TrackWrap>::iterator i=wrap.begin(); i!=wrap.end(); ++i)
343 glTranslatef(i->pos.x, i->pos.y, i->pos.z);
344 glRotatef(i->rot*180/M_PI, 0, 0, 1);
346 glBegin(GL_LINE_LOOP);
347 glVertex2f(-i->width/2, -i->height/2);
348 glVertex2f(i->width/2, -i->height/2);
349 glVertex2f(i->width/2, i->height/2);
350 glVertex2f(-i->width/2, i->height/2);
359 void Manipulator::selection_changed()
365 const set<Track *> &stracks = selection.get_tracks();
366 tracks.insert(tracks.end(), stracks.begin(), stracks.end());
372 void Manipulator::update_wrap()
375 float min_x = 0, max_x = 0;
376 float min_y = 0, max_y = 0;
378 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
380 Track3D &t3d = designer.get_layout_3d()->get_track(*i->track);
383 float min_area = 100;
384 for(float a=0; a<M_PI; a+=0.01)
387 t3d.get_bounds(a, minp, maxp);
388 float area = (maxp.x-minp.x)*(maxp.y-minp.y);
393 float x = (minp.x+maxp.x)/2;
394 float y = (minp.y+maxp.y)/2;
395 tw.pos = Point(c*x-s*y, s*x+c*y, minp.z);
397 tw.width = maxp.x-minp.x+0.01;
398 tw.height = maxp.y-minp.y+0.01;
404 if(i==tracks.begin())
406 min_x = max_x = tw.pos.x;
407 min_y = max_y = tw.pos.y;
412 min_x = min(min_x, tw.pos.x);
413 max_x = max(max_x, tw.pos.x);
414 min_y = min(min_y, tw.pos.y);
415 max_y = max(max_y, tw.pos.y);
416 min_z = min(min_z, tw.pos.z);
421 center = Point((min_x+max_x)/2, (min_y+max_y)/2, min_z);
424 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
426 const Point &tp = i->track->get_position();
427 i->pos = Point(tp.x-center.x, tp.y-center.y, tp.z-center.z);
429 for(list<TrackWrap>::iterator i=wrap.begin(); i!=wrap.end(); ++i)
431 i->pos.x -= center.x;
432 i->pos.y -= center.y;
433 i->pos.z -= center.z;
437 void Manipulator::update_neighbors()
440 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
442 const vector<Track *> &links = i->track->get_links();
443 for(vector<Track *>::const_iterator j=links.begin(); j!=links.end(); ++j)
447 if(neighbors.count(*j))
451 for(vector<MTrack>::iterator k=tracks.begin(); (k!=tracks.end() && ok); ++k)
455 neighbors.insert(*j);
460 void Manipulator::set_slope(TrackOrder &track, float z, float dz)
462 const Point &p = track.track->get_position();
465 track.track->set_position(Point(p.x, p.y, z+dz));
466 track.track->set_slope(-dz);
470 track.track->set_position(Point(p.x, p.y, z));
471 track.track->set_slope(dz);
475 Manipulator::MTrack::MTrack(Track *t):
477 pos(track->get_position()),
478 rot(track->get_rotation())