]> git.tdb.fi Git - r2c2.git/blob - source/designer/manipulator.cpp
c07003e4eae3f13617029ee23f02f1ce31ee1e69
[r2c2.git] / source / designer / manipulator.cpp
1 #include <algorithm>
2 #include <cmath>
3 #include <GL/gl.h>
4 #include "3d/layout.h"
5 #include "libmarklin/tracktype.h"
6 #include "designer.h"
7 #include "manipulator.h"
8 #include "selection.h"
9
10 using namespace std;
11 using namespace Marklin;
12 using namespace Msp;
13
14 #include <iostream>
15
16 Manipulator::Manipulator(Designer &d):
17         designer(d),
18         selection(0),
19         wrap_rot(0),
20         mode(NONE),
21         angle(0)
22 { }
23
24 void Manipulator::set_selection(Selection *s)
25 {
26         selection_changed_conn.disconnect();
27
28         selection=s;
29         if(selection)
30                 selection_changed_conn=selection->signal_changed.connect(sigc::mem_fun(this, &Manipulator::selection_changed));
31
32         selection_changed();
33 }
34
35 void Manipulator::start_move()
36 {
37         if(mode)
38                 cancel();
39
40         move_origin=gpointer;
41
42         mode=MOVE;
43 }
44
45 void Manipulator::start_rotate()
46 {
47         if(mode)
48                 cancel();
49
50         rot_origin=atan2(gpointer.y-center.y, gpointer.x-center.x);
51
52         mode=ROTATE;
53 }
54
55 void Manipulator::start_elevate()
56 {
57         if(mode)
58                 cancel();
59
60         elev_origin=pointer_y;
61
62         mode=ELEVATE;
63 }
64
65 void Manipulator::duplicate()
66 {
67         if(mode)
68                 cancel();
69
70         list<Track *> new_tracks;
71         for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
72         {
73                 Track *track=i->track->copy();
74                 designer.get_layout()->add_track(*track);
75                 new_tracks.push_back(track);
76         }
77
78         selection->clear();
79         for(list<Track *>::iterator i=new_tracks.begin(); i!=new_tracks.end(); ++i)
80         {
81                 selection->add_track(*i);
82                 for(list<Track *>::iterator j=i; j!=new_tracks.end(); ++j)
83                         if(j!=i)
84                                 (*i)->snap_to(**j, true);
85         }
86 }
87
88 void Manipulator::flatten()
89 {
90         if(mode)
91                 cancel();
92
93         if(tracks.empty()) return;
94
95         float z=0;
96         for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
97                 z+=i->track->get_position().z+i->track->get_slope()/2;
98         z/=tracks.size();
99
100         for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
101         {
102                 Point p=i->track->get_position();
103                 i->track->set_position(Point(p.x, p.y, z));
104                 i->track->set_slope(0);
105         }
106
107         for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
108                 (*i)->check_slope();
109
110         update_wrap();
111 }
112
113 void Manipulator::even_slope(bool smooth)
114 {
115         if(mode)
116                 cancel();
117
118         if(neighbors.size()!=2)
119                 return;
120
121         for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
122                 if(i->track->get_type().get_endpoints().size()!=2)
123                         return;
124
125         list<Track *> tracks2;
126         for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
127                 tracks2.push_back(i->track);
128
129         float total_len=0;
130
131         list<TrackOrder> order;
132         Track *cur=*neighbors.begin();
133         while(tracks2.size())
134         {
135                 bool rev=false;
136                 for(list<Track *>::iterator i=tracks2.begin(); i!=tracks2.end(); ++i)
137                 {
138                         const vector<Track *> &links=(*i)->get_links();
139                         if(links[0]==cur)
140                         {
141                                 cur=*i;
142                                 tracks2.erase(i);
143                                 break;
144                         }
145                         else if(links[1]==cur)
146                         {
147                                 cur=*i;
148                                 rev=true;
149                                 tracks2.erase(i);
150                                 break;
151                         }
152                 }
153                 order.push_back(TrackOrder(cur, rev));
154                 total_len+=cur->get_type().get_total_length();
155         }
156
157         set<Track *>::iterator nb=neighbors.begin();
158         int epi=(*nb)->get_endpoint_by_link(*order.front().track);
159         float start_z=(*nb)->get_endpoint_position(epi).z;
160         ++nb;
161         epi=(*nb)->get_endpoint_by_link(*order.back().track);
162         float end_z=(*nb)->get_endpoint_position(epi).z;
163
164         if(smooth)
165         {
166                 float dir=(end_z>start_z)?1:-1;
167                 float cur_slope=0;
168                 while((end_z-start_z)*dir/total_len>cur_slope+0.025 && order.size()>2)
169                 {
170                         cur_slope+=0.025;
171
172                         float dz=order.front().track->get_type().get_total_length()*dir*cur_slope;
173                         set_slope(order.front(), start_z, dz);
174                         start_z+=dz;
175                         total_len-=order.front().track->get_type().get_total_length();
176                         order.erase(order.begin());
177
178                         dz=order.back().track->get_type().get_total_length()*dir*cur_slope;
179                         set_slope(order.back(), end_z-dz, dz);
180                         end_z-=dz;
181                         total_len-=order.back().track->get_type().get_total_length();
182                         order.erase(--order.end());
183                 }
184         }
185
186         float cur_z=start_z;
187         for(list<TrackOrder>::iterator i=order.begin(); i!=order.end(); ++i)
188         {
189                 float dz=i->track->get_type().get_total_length()*(end_z-start_z)/total_len;
190                 set_slope(*i, cur_z, dz);
191                 cur_z+=dz;
192         }
193
194         for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
195                 (*i)->check_slope();
196
197         update_wrap();
198 }
199
200 void Manipulator::cancel()
201 {
202         if(!mode)
203                 return;
204         mode=NONE;
205
206         wrap_pos=center;
207         for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
208         {
209                 i->track->set_position(Point(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z));
210                 i->track->set_rotation(i->rot);
211         }
212
213         for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
214                 (*i)->check_slope();
215
216         angle=0;
217         //snapped=0;
218
219         signal_done.emit(false);
220 }
221
222 void Manipulator::button_press(int, int, float, float, unsigned btn)
223 {
224         if(btn==3)
225                 cancel();
226         else if(mode)
227         {
228                 mode=NONE;
229                 update_wrap();
230                 //snapped=0;
231
232                 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
233                         for(vector<MTrack>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
234                                 j->track->break_link(**i);
235
236                 const set<Track *> &ltracks=designer.get_layout()->get_tracks();
237                 for(set<Track *>::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
238                 {
239                         bool ok=true;
240                         for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && ok); ++j)
241                                 ok=(j->track!=*i);
242                         if(!ok) continue;
243
244                         for(vector<MTrack>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
245                                 j->track->snap_to(**i, true);
246                 }
247
248                 update_neighbors();
249
250                 signal_done.emit(true);
251         }
252 }
253
254 void Manipulator::pointer_motion(int, int y, float gx, float gy)
255 {
256         pointer_y=y;
257         gpointer=Point(gx, gy, 0);
258
259         if(mode==MOVE)
260         {
261                 Point delta(gpointer.x-move_origin.x, gpointer.y-move_origin.y, 0);
262
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)
265                 {
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);
268                 }
269
270                 const set<Track *> &ltracks=designer.get_layout()->get_tracks();
271                 MTrack *snapped=0;
272                 for(set<Track *>::const_iterator i=ltracks.begin(); (i!=ltracks.end() && !snapped); ++i)
273                 {
274                         bool ok=true;
275                         for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && ok); ++j)
276                                 ok=(j->track!=*i);
277                         if(!ok) continue;
278
279                         for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && !snapped); ++j)
280                                 if(j->track->snap_to(**i, false))
281                                         snapped=&*j;
282                 }
283
284                 if(snapped)
285                 {
286                         float da=snapped->track->get_rotation()-snapped->rot;
287                         float c=cos(da);
288                         float s=sin(da);
289                         const Point &sp=snapped->track->get_position();
290                         for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
291                         {
292                                 if(&*i==snapped)
293                                         continue;
294
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);
298                         }
299                 }
300         }
301         else if(mode==ROTATE)
302         {
303                 float a=atan2(gpointer.y-center.y, gpointer.x-center.x);
304                 angle+=a-rot_origin;
305                 rot_origin=a;
306
307                 wrap_rot=angle;
308                 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
309                 {
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);
314                 }
315         }
316         else if(mode==ELEVATE)
317         {
318                 float dz=(y-elev_origin)/1000.;
319
320                 ostringstream ss;
321                 ss.precision(3);
322                 ss<<"Elevation: "<<dz*1000<<"mm ("<<(center.z+dz)*1000<<"mm)";
323                 signal_status.emit(ss.str());
324
325                 wrap_pos.z=center.z+dz;
326                 for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
327                         i->track->set_position(Point(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z+dz));
328
329                 for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
330                         (*i)->check_slope();
331         }
332 }
333
334 void Manipulator::render()
335 {
336         glPushMatrix();
337         glTranslatef(wrap_pos.x, wrap_pos.y, wrap_pos.z);
338         glRotatef(wrap_rot*180/M_PI, 0, 0, 1);
339
340         glLineWidth(2);
341         glColor4f(0, 1, 0, 0.5);
342         for(list<TrackWrap>::iterator i=wrap.begin(); i!=wrap.end(); ++i)
343         {
344                 glPushMatrix();
345                 glTranslatef(i->pos.x, i->pos.y, i->pos.z);
346                 glRotatef(i->rot*180/M_PI, 0, 0, 1);
347
348                 glBegin(GL_LINE_LOOP);
349                 glVertex2f(-i->width/2, -i->height/2);
350                 glVertex2f(i->width/2, -i->height/2);
351                 glVertex2f(i->width/2, i->height/2);
352                 glVertex2f(-i->width/2, i->height/2);
353                 glEnd();
354
355                 glPopMatrix();
356         }
357
358         glPopMatrix();
359 }
360
361 /*** private ***/
362
363 void Manipulator::selection_changed()
364 {
365         if(mode)
366                 cancel();
367
368         tracks.clear();
369         if(selection)
370         {
371                 const set<Track *> &stracks=selection->get_tracks();
372                 tracks.insert(tracks.end(), stracks.begin(), stracks.end());
373         }
374
375         update_neighbors();
376         update_wrap();
377 }
378
379 void Manipulator::update_wrap()
380 {
381         wrap.clear();
382         float min_x=0, max_x=0;
383         float min_y=0, max_y=0;
384         for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
385         {
386                 Track3D &t3d=designer.get_layout_3d()->get_track(*i->track);
387
388                 TrackWrap tw;
389                 float min_area=100;
390                 for(float a=0; a<M_PI; a+=0.01)
391                 {
392                         Point minp, maxp;
393                         t3d.get_bounds(a, minp, maxp);
394                         float area=(maxp.x-minp.x)*(maxp.y-minp.y);
395                         if(area<min_area)
396                         {
397                                 float c=cos(a);
398                                 float s=sin(a);
399                                 float x=(minp.x+maxp.x)/2;
400                                 float y=(minp.y+maxp.y)/2;
401                                 tw.pos=Point(c*x-s*y, s*x+c*y, (minp.z+maxp.z)/2);
402                                 tw.rot=a;
403                                 tw.width=maxp.x-minp.x+0.01;
404                                 tw.height=maxp.y-minp.y+0.01;
405
406                                 min_area=area;
407                         }
408                 }
409
410                 if(i==tracks.begin())
411                 {
412                         min_x=max_x=tw.pos.x;
413                         min_y=max_y=tw.pos.y;
414                 }
415                 else
416                 {
417                         min_x=min(min_x, tw.pos.x);
418                         max_x=max(max_x, tw.pos.x);
419                         min_y=min(min_y, tw.pos.y);
420                         max_y=max(max_y, tw.pos.y);
421                 }
422                 wrap.push_back(tw);
423         }
424
425         center=Point((min_x+max_x)/2, (min_y+max_y)/2, 0);
426         wrap_pos=center;
427         wrap_rot=0;
428         for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
429         {
430                 const Point &tp=i->track->get_position();
431                 i->pos=Point(tp.x-center.x, tp.y-center.y, tp.z);
432         }
433         for(list<TrackWrap>::iterator i=wrap.begin(); i!=wrap.end(); ++i)
434         {
435                 i->pos.x-=center.x;
436                 i->pos.y-=center.y;
437         }
438 }
439
440 void Manipulator::update_neighbors()
441 {
442         neighbors.clear();
443         for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
444         {
445                 const vector<Track *> &links=i->track->get_links();
446                 for(vector<Track *>::const_iterator j=links.begin(); j!=links.end(); ++j)
447                 {
448                         if(!*j)
449                                 continue;
450                         if(neighbors.count(*j))
451                                 continue;
452
453                         bool ok=true;
454                         for(vector<MTrack>::iterator k=tracks.begin(); (k!=tracks.end() && ok); ++k)
455                                 ok=(k->track!=*j);
456
457                         if(ok)
458                                 neighbors.insert(*j);
459                 }
460         }
461 }
462
463 void Manipulator::set_slope(TrackOrder &track, float z, float dz)
464 {
465         const Point &p=track.track->get_position();
466         if(track.rev)
467         {
468                 track.track->set_position(Point(p.x, p.y, z+dz));
469                 track.track->set_slope(-dz);
470         }
471         else
472         {
473                 track.track->set_position(Point(p.x, p.y, z));
474                 track.track->set_slope(dz);
475         }
476 }
477
478 Manipulator::MTrack::MTrack(Track *t):
479         track(t),
480         pos(track->get_position()),
481         rot(track->get_rotation())
482 { }