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 z += i->object->get_position().z;
105 if(Track *track = dynamic_cast<Track *>(i->object))
106 z += track->get_slope()/2;
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))
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)
181 float dz = order.front().track->get_type().get_total_length()*dir*cur_slope;
182 set_slope(order.front(), start_z, dz);
184 total_len -= order.front().track->get_type().get_total_length();
185 order.erase(order.begin());
187 dz = order.back().track->get_type().get_total_length()*dir*cur_slope;
188 set_slope(order.back(), end_z-dz, dz);
190 total_len -= order.back().track->get_type().get_total_length();
191 order.erase(--order.end());
195 float cur_z = start_z;
196 for(list<TrackOrder>::iterator i=order.begin(); i!=order.end(); ++i)
198 float dz = i->track->get_type().get_total_length()*(end_z-start_z)/total_len;
199 set_slope(*i, cur_z, dz);
206 void Manipulator::connect()
208 if(objects.size()!=2)
210 signal_status.emit("Exactly two tracks must be selected");
214 Track *track1 = dynamic_cast<Track *>(objects.front().object);
215 Track *track2 = dynamic_cast<Track *>(objects.back().object);
216 if(!track1 || !track2)
218 signal_status.emit("Exactly two tracks must be selected");
222 float limit = designer.get_layout().get_catalogue().get_gauge()/10;
227 for(unsigned i=0; i<track1->get_type().get_endpoints().size(); ++i)
229 if(track1->get_link(i))
232 sn1 = track1->get_snap_node(i);
234 for(unsigned j=0; j<track2->get_type().get_endpoints().size(); ++j)
236 if(track2->get_link(j))
239 Snap sn2 = track2->get_snap_node(j);
241 float dz = sn2.position.z-sn1.position.z;
245 Angle adiff = wrap_balanced(sn1.rotation+Angle::half_turn()-sn2.rotation);
246 if(abs(adiff).radians()>0.01)
249 Vector delta = rotated_vector(sn2.position-sn1.position, -sn1.rotation);
250 if(abs(delta.y)>limit)
266 signal_status.emit("No aligned endpoints found");
270 vector<Track *> trks = create_straight(sn1.position, sn1.rotation, gap, limit);
274 signal_status.emit("No connection possible");
278 trks.front()->link_to(*track1);
279 trks.back()->link_to(*track2);
281 selection.replace(trks.begin(), trks.end());
284 void Manipulator::cancel()
290 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
292 i->object->set_position(center+i->pos);
293 i->object->set_rotation(i->rot);
296 for(vector<Track *>::iterator i=extend_tracks.begin(); i!=extend_tracks.end(); ++i)
298 extend_tracks.clear();
300 angle = Angle::zero();
302 signal_done.emit(false);
305 void Manipulator::button_press(unsigned btn)
316 angle = Angle::zero();
320 for(set<Object *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
321 for(vector<MObject>::iterator j=objects.begin(); j!=objects.end(); ++j)
322 j->object->break_link(**i);
325 const set<Track *> <racks = designer.get_layout().get_all<Track>();
326 for(set<Track *>::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
329 for(vector<MObject>::iterator j=objects.begin(); (j!=objects.end() && ok); ++j)
330 ok = (j->object!=*i);
333 for(vector<MObject>::iterator j=objects.begin(); j!=objects.end(); ++j)
334 j->object->link_to(**i);
339 selection.replace(extend_tracks.begin(), extend_tracks.end());
340 extend_tracks.clear();
348 signal_done.emit(true);
352 void Manipulator::axis_motion(unsigned axis, float value, float)
358 gpointer = designer.map_pointer_to_ground(pointer);
362 Vector offset = center+gpointer-move_origin;
363 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
365 i->object->set_position(offset+i->pos);
366 i->object->set_rotation(i->rot);
369 const set<Track *> <racks = designer.get_layout().get_all<Track>();
370 float limit = max(designer.get_layout().get_catalogue().get_gauge(),
371 designer.get_camera_controller().get_view_scale()/100.0f);
372 MObject *snapped = 0;
373 for(set<Track *>::const_iterator i=ltracks.begin(); (i!=ltracks.end() && !snapped); ++i)
376 for(vector<MObject>::iterator j=objects.begin(); (j!=objects.end() && ok); ++j)
377 ok = (j->object!=*i);
381 for(vector<MObject>::iterator j=objects.begin(); (j!=objects.end() && !snapped); ++j)
382 if(j->object->snap_to(**i, limit))
388 Angle da = snapped->object->get_rotation()-snapped->rot;
389 Transform trans = Transform::rotation(da, Vector(0, 0, 1));
390 const Vector &sp = snapped->object->get_position();
391 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
396 i->object->set_position(sp+trans.transform(i->pos-snapped->pos));
397 i->object->set_rotation(i->rot+da);
401 else if(mode==ROTATE)
403 Angle a = Geometry::atan2(gpointer.y-center.y, gpointer.x-center.x);
404 angle += a-rot_origin;
407 Transform trans = Transform::rotation(angle, Vector(0, 0, 1));
408 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
410 i->object->set_position(center+trans.transform(i->pos));
411 i->object->set_rotation(angle+i->rot);
414 else if(mode==ELEVATE && axis==1)
416 float dz = pointer.y-elev_origin;
418 signal_status.emit(format("Elevation: %+.0fmm (%.0fmm)", dz*1000, (center.z+dz)*1000));
420 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
421 i->object->set_position(center+i->pos+Vector(0, 0, dz));
423 else if(mode==EXTEND)
428 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
430 unsigned nls = i->object->get_n_link_slots();
431 for(unsigned j=0; j<nls; ++j)
433 if(i->object->get_link(j))
436 Snap sn = i->object->get_snap_node(j);
437 Vector delta = rotated_vector(gpointer-sn.position, -sn.rotation);
450 vector<Track *> trks = create_straight(pos, dir, length, max(length/500, 0.001f));
454 for(vector<Track *>::iterator i=extend_tracks.begin(); i!=extend_tracks.end(); ++i)
456 extend_tracks = trks;
458 map<ArticleNumber, unsigned> counts;
460 for(vector<Track *>::iterator i=extend_tracks.begin(); i!=extend_tracks.end(); ++i)
462 length += (*i)->get_type().get_total_length();
463 ++counts[(*i)->get_type().get_article_number()];
467 for(map<ArticleNumber, unsigned>::const_iterator i=counts.begin(); i!=counts.end(); ++i)
471 detail += format("%dx %s", i->second, i->first);
474 signal_status.emit(format("Extend: %.0fmm (%s)", length*1000, detail));
480 void Manipulator::selection_changed()
486 set<Object *> pending = selection.get_objects();
487 while(!pending.empty())
489 for(set<Object *>::iterator i=pending.begin(); i!=pending.end(); )
491 if((*i)->get_parent() && pending.count((*i)->get_parent()))
495 objects.push_back(*i);
505 void Manipulator::update_objects()
507 Geometry::BoundingBox<float, 3> bbox;
508 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
509 bbox = bbox|i->object->get_bounding_box();
511 const Vector &minp = bbox.get_minimum_point();
512 const Vector &maxp = bbox.get_maximum_point();
514 center = (minp+maxp)/2.0f;
516 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
518 i->pos = i->object->get_position()-center;
519 i->rot = i->object->get_rotation();
523 void Manipulator::update_neighbors()
526 for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
528 unsigned nls = i->object->get_n_link_slots();
529 for(unsigned j=0; j<nls; ++j)
531 Object *linked = i->object->get_link(j);
534 if(neighbors.count(linked))
538 for(vector<MObject>::iterator k=objects.begin(); (k!=objects.end() && ok); ++k)
539 ok = (k->object!=linked);
542 neighbors.insert(linked);
547 void Manipulator::set_slope(TrackOrder &track, float z, float dz)
549 const Vector &p = track.track->get_position();
552 track.track->set_position(Vector(p.x, p.y, z+dz));
553 track.track->set_slope(-dz);
557 track.track->set_position(Vector(p.x, p.y, z));
558 track.track->set_slope(dz);
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())