3 #include <msp/strings/format.h>
4 #include "libr2c2/tracktype.h"
6 #include "manipulator.h"
13 Manipulator::Manipulator(Designer &d, Input::Mouse &m, Selection &s):
19 mouse.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Manipulator::button_press), false));
20 mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Manipulator::axis_motion), false));
21 selection.signal_changed.connect(sigc::mem_fun(this, &Manipulator::selection_changed));
24 void Manipulator::start_move()
29 move_origin = gpointer;
34 void Manipulator::start_rotate()
39 rot_origin = Geometry::atan2(gpointer.y-center.y, gpointer.x-center.x);
44 void Manipulator::start_elevate()
51 elev_origin = pointer.y;
54 bool Manipulator::start_extend()
60 const set<Track *> &stracks = selection.get_objects<Track>();
61 for(set<Track *>::const_iterator i=stracks.begin(); (!ok && i!=stracks.end()); ++i)
63 const vector<Track *> &links = (*i)->get_links();
64 for(vector<Track *>::const_iterator j=links.begin(); (!ok && j!=links.end()); ++j)
71 signal_status.emit("No free endpoints");
76 void Manipulator::duplicate()
81 list<Object *> new_objs;
82 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
84 Object *obj = i->object->clone(&designer.get_layout());
85 for(list<Object *>::iterator j=new_objs.begin(); j!=new_objs.end(); ++j)
87 new_objs.push_back(obj);
90 selection.replace(new_objs.begin(), new_objs.end());
93 void Manipulator::flatten()
102 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
104 unsigned nsn = i->object->get_n_snap_nodes();
105 for(unsigned j=0; j<nsn; ++j)
106 z += i->object->get_snap_node(j).position.z/nsn;
108 z /= static_cast<int>(objects.size());
110 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
112 Vector p = i->object->get_position();
113 i->object->set_position(Vector(p.x, p.y, z));
114 if(Track *track = dynamic_cast<Track *>(i->object))
115 track->set_tilt(Angle::zero());
121 void Manipulator::even_slope(bool smooth)
126 if(neighbors.size()!=2)
129 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
130 if(i->object->get_n_link_slots()!=2)
133 list<Track *> tracks2;
134 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
135 if(Track *track = dynamic_cast<Track *>(i->object))
136 tracks2.push_back(track);
140 list<TrackOrder> order;
141 Track *cur = dynamic_cast<Track *>(*neighbors.begin());
142 while(tracks2.size())
145 for(list<Track *>::iterator i=tracks2.begin(); i!=tracks2.end(); ++i)
147 const vector<Track *> &links = (*i)->get_links();
154 else if(links[1]==cur)
162 order.push_back(TrackOrder(cur, rev));
163 total_len += cur->get_type().get_total_length();
166 set<Object *>::iterator nb = neighbors.begin();
167 int epi = (*nb)->get_link_slot(*order.front().track);
168 float start_z = (*nb)->get_snap_node(epi).position.z;
170 epi = (*nb)->get_link_slot(*order.back().track);
171 float end_z = (*nb)->get_snap_node(epi).position.z;
175 float dir = (end_z>start_z)?1:-1;
177 while((end_z-start_z)*dir/total_len>cur_slope+0.025 && order.size()>2)
180 Angle tilt = Geometry::atan(cur_slope);
182 set_slope(order.front(), start_z, tilt);
183 start_z += order.front().track->get_type().get_path_length(0)*dir*cur_slope;
184 total_len -= order.front().track->get_type().get_path_length(0);
187 end_z -= order.back().track->get_type().get_path_length(0)*dir*cur_slope;
188 set_slope(order.back(), end_z, tilt);
189 total_len -= order.back().track->get_type().get_path_length(0);
194 float cur_z = start_z;
195 Angle tilt = Geometry::atan((end_z-start_z)/total_len);
196 for(list<TrackOrder>::iterator i=order.begin(); i!=order.end(); ++i)
198 set_slope(*i, cur_z, tilt);
199 cur_z += i->track->get_type().get_path_length(0)*(end_z-start_z)/total_len;
205 void Manipulator::connect()
207 if(objects.size()!=2)
209 signal_status.emit("Exactly two tracks must be selected");
213 Track *track1 = dynamic_cast<Track *>(objects.front().object);
214 Track *track2 = dynamic_cast<Track *>(objects.back().object);
215 if(!track1 || !track2)
217 signal_status.emit("Exactly two tracks must be selected");
221 float limit = designer.get_layout().get_catalogue().get_gauge()/10;
226 for(unsigned i=0; i<track1->get_type().get_endpoints().size(); ++i)
228 if(track1->get_link(i))
231 sn1 = track1->get_snap_node(i);
233 for(unsigned j=0; j<track2->get_type().get_endpoints().size(); ++j)
235 if(track2->get_link(j))
238 Snap sn2 = track2->get_snap_node(j);
240 float dz = sn2.position.z-sn1.position.z;
244 Angle adiff = wrap_balanced(sn1.rotation+Angle::half_turn()-sn2.rotation);
245 if(abs(adiff).radians()>0.01)
248 Vector delta = rotated_vector(sn2.position-sn1.position, -sn1.rotation);
249 if(abs(delta.y)>limit)
265 signal_status.emit("No aligned endpoints found");
269 vector<Track *> trks = create_straight(sn1.position, sn1.rotation, gap, limit);
273 signal_status.emit("No connection possible");
277 trks.front()->link_to(*track1);
278 trks.back()->link_to(*track2);
280 selection.replace(trks.begin(), trks.end());
283 void Manipulator::cancel()
289 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
291 i->object->set_position(center+i->pos);
292 i->object->set_rotation(i->rot);
295 for(vector<Track *>::iterator i=extend_tracks.begin(); i!=extend_tracks.end(); ++i)
297 extend_tracks.clear();
299 angle = Angle::zero();
301 signal_done.emit(false);
304 void Manipulator::button_press(unsigned btn)
315 angle = Angle::zero();
319 for(set<Object *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
320 for(vector<MObject>::iterator j=objects.begin(); j!=objects.end(); ++j)
321 j->object->break_link(**i);
324 const set<Track *> <racks = designer.get_layout().get_all<Track>();
325 for(set<Track *>::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
328 for(vector<MObject>::iterator j=objects.begin(); (j!=objects.end() && ok); ++j)
329 ok = (j->object!=*i);
332 for(vector<MObject>::iterator j=objects.begin(); j!=objects.end(); ++j)
333 j->object->link_to(**i);
338 selection.replace(extend_tracks.begin(), extend_tracks.end());
339 extend_tracks.clear();
347 signal_done.emit(true);
351 void Manipulator::axis_motion(unsigned axis, float value, float)
357 gpointer = designer.map_pointer_to_ground(pointer);
361 Vector offset = center+gpointer-move_origin;
362 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
364 i->object->set_position(offset+i->pos);
365 i->object->set_rotation(i->rot);
368 const set<Track *> <racks = designer.get_layout().get_all<Track>();
369 float limit = max(designer.get_layout().get_catalogue().get_gauge(),
370 designer.get_camera_controller().get_view_scale()/100.0f);
371 MObject *snapped = 0;
372 for(set<Track *>::const_iterator i=ltracks.begin(); (i!=ltracks.end() && !snapped); ++i)
375 for(vector<MObject>::iterator j=objects.begin(); (j!=objects.end() && ok); ++j)
376 ok = (j->object!=*i);
380 for(vector<MObject>::iterator j=objects.begin(); (j!=objects.end() && !snapped); ++j)
381 if(j->object->snap_to(**i, limit))
387 Angle da = snapped->object->get_rotation()-snapped->rot;
388 Transform trans = Transform::rotation(da, Vector(0, 0, 1));
389 const Vector &sp = snapped->object->get_position();
390 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
395 i->object->set_position(sp+trans.transform(i->pos-snapped->pos));
396 i->object->set_rotation(i->rot+da);
400 else if(mode==ROTATE)
402 Angle a = Geometry::atan2(gpointer.y-center.y, gpointer.x-center.x);
403 angle += a-rot_origin;
406 Transform trans = Transform::rotation(angle, Vector(0, 0, 1));
407 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
409 i->object->set_position(center+trans.transform(i->pos));
410 i->object->set_rotation(angle+i->rot);
413 else if(mode==ELEVATE && axis==1)
415 float dz = pointer.y-elev_origin;
417 signal_status.emit(format("Elevation: %+.0fmm (%.0fmm)", dz*1000, (center.z+dz)*1000));
419 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
420 i->object->set_position(center+i->pos+Vector(0, 0, dz));
422 else if(mode==EXTEND)
427 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
429 unsigned nls = i->object->get_n_link_slots();
430 for(unsigned j=0; j<nls; ++j)
432 if(i->object->get_link(j))
435 Snap sn = i->object->get_snap_node(j);
436 Vector delta = rotated_vector(gpointer-sn.position, -sn.rotation);
449 vector<Track *> trks = create_straight(pos, dir, length, max(length/500, 0.001f));
453 for(vector<Track *>::iterator i=extend_tracks.begin(); i!=extend_tracks.end(); ++i)
455 extend_tracks = trks;
457 map<ArticleNumber, unsigned> counts;
459 for(vector<Track *>::iterator i=extend_tracks.begin(); i!=extend_tracks.end(); ++i)
461 length += (*i)->get_type().get_total_length();
462 ++counts[(*i)->get_type().get_article_number()];
466 for(map<ArticleNumber, unsigned>::const_iterator i=counts.begin(); i!=counts.end(); ++i)
470 detail += format("%dx %s", i->second, i->first);
473 signal_status.emit(format("Extend: %.0fmm (%s)", length*1000, detail));
479 void Manipulator::selection_changed()
485 set<Object *> pending = selection.get_objects();
486 while(!pending.empty())
488 for(set<Object *>::iterator i=pending.begin(); i!=pending.end(); )
490 if((*i)->get_parent() && pending.count((*i)->get_parent()))
494 objects.push_back(*i);
504 void Manipulator::update_objects()
506 Geometry::BoundingBox<float, 3> bbox;
507 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
508 bbox = bbox|i->object->get_bounding_box();
510 const Vector &minp = bbox.get_minimum_point();
511 const Vector &maxp = bbox.get_maximum_point();
513 center = (minp+maxp)/2.0f;
515 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
517 i->pos = i->object->get_position()-center;
518 i->rot = i->object->get_rotation();
522 void Manipulator::update_neighbors()
525 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
527 unsigned nls = i->object->get_n_link_slots();
528 for(unsigned j=0; j<nls; ++j)
530 Object *linked = i->object->get_link(j);
533 if(neighbors.count(linked))
537 for(vector<MObject>::iterator k=objects.begin(); (k!=objects.end() && ok); ++k)
538 ok = (k->object!=linked);
541 neighbors.insert(linked);
546 void Manipulator::set_slope(TrackOrder &track, float z, const Angle &tilt)
548 const Vector &p = track.track->get_position();
549 float dz = tan(tilt)*track.track->get_type().get_path_length(0);
552 track.track->set_position(Vector(p.x, p.y, z+dz));
553 track.track->set_tilt(-tilt);
557 track.track->set_position(Vector(p.x, p.y, z));
558 track.track->set_tilt(tilt);
562 vector<Track *> Manipulator::create_straight(const R2C2::Vector &start, const Angle &dir, float length, float limit)
564 const Catalogue::TrackMap &track_types = designer.get_catalogue().get_tracks();
565 std::map<float, const TrackType *> types_by_length;
566 unsigned preference = 0;
567 for(Catalogue::TrackMap::const_iterator i=track_types.begin(); i!=track_types.end(); ++i)
569 const vector<TrackPart> &parts = i->second->get_parts();
572 if(parts.front().is_curved() || parts.front().is_dead_end())
575 types_by_length[parts.front().get_length()] = i->second;
576 preference = max(preference, i->second->get_autofit_preference());
579 vector<float> lengths;
584 for(map<float, const TrackType *>::iterator i=types_by_length.end(); i!=types_by_length.begin(); )
587 if(i->second->get_autofit_preference()<preference)
589 if((!removed || i->first<removed) && i->first<length+limit)
591 unsigned n = static_cast<unsigned>((length+limit)/i->first);
592 lengths.insert(lengths.end(), n, i->first);
593 length -= n*i->first;
613 length += lengths.back();
614 removed = lengths.back();
618 vector<Track *> trks;
623 Transform trans = Transform::rotation(dir, Vector(0, 0, 1));
624 for(vector<float>::iterator i=lengths.begin(); i!=lengths.end(); ++i)
626 Track *track = new Track(designer.get_layout(), *get_item(types_by_length, *i));
627 track->set_position(pos);
628 track->set_rotation(dir);
631 track->link_to(*trks.back());
632 trks.push_back(track);
634 pos += trans.transform(Vector(*i, 0, 0));
642 Manipulator::MObject::MObject(Object *o):
644 pos(object->get_position()),
645 rot(object->get_rotation())