if(mode!=SELECT)
return;
- set<Track *> tracks = selection.get_tracks();
+ set<Track *> tracks = selection.get_objects<Track>();
selection.clear();
for(set<Track *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
{
try
{
- cur_route->add_tracks(selection.get_tracks());
+ cur_route->add_tracks(selection.get_objects<Track>());
}
catch(const exception &e)
{
try
{
- cur_zone->add_tracks(selection.get_tracks());
+ cur_zone->add_tracks(selection.get_objects<Track>());
}
catch(const exception &e)
{
erase_tracks();
else if(key==Msp::Input::KEY_F && shift)
{
- const set<Track *> &tracks = selection.get_tracks();
+ const set<Track *> &tracks = selection.get_objects<Track>();
const set<Track *> <racks = layout->get_tracks();
for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
{
{
if(btn==1)
{
- Track *ctrack = pick_track(pointer);
- if(ctrack)
+ Object *cobj = pick_object(pointer);
+ if(cobj)
{
- Track *track = new Track(*layout, ctrack->get_type());
- track->set_position(ground);
+ Object *obj = cobj->clone(layout);
+ obj->set_position(ground);
selection.clear();
- selection.add_track(track);
+ selection.add_object(obj);
mode = SELECT;
}
{
if(btn==1)
{
- Track *track = pick_track(pointer);
- if(track)
+ Object *obj = pick_object(pointer);
+ if(obj)
{
if(!shift)
selection.clear();
- selection.toggle_track(track);
+ selection.toggle_object(obj);
}
}
}
new_tracks.erase(i);
}
-Track *Designer::pick_track(const Vector &pointer)
+Object *Designer::pick_object(const Vector &pointer)
{
View3D &view = *(mode==CATALOGUE ? cat_view : main_view);
const GL::Vector3 &cpos = view.get_camera().get_position();
GL::Vector4 cray = view.get_camera().unproject(GL::Vector4(pointer.x, pointer.y, 0, 0));
- return view.get_layout().get_layout().pick_track(Vector(cpos.x, cpos.y, cpos.z), Vector(cray.x, cray.y, cray.z));
+ return view.get_layout().get_layout().pick_object(Vector(cpos.x, cpos.y, cpos.z), Vector(cray.x, cray.y, cray.z));
}
void Designer::update_track_icon(Track3D &track)
void Designer::selection_changed()
{
- const set<Track *> &tracks = selection.get_tracks();
+ const set<Track *> &tracks = selection.get_objects<Track>();
if(tracks.empty())
lbl_status->set_text(string());
else
void Designer::track_properties_response(int)
{
- const set<Track *> &tracks = selection.get_tracks();
+ const set<Track *> &tracks = selection.get_objects<Track>();
for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
update_track_icon(layout_3d->get_track(**i));
}
string Designer::tooltip(int x, int y)
{
- if(Track *track = pick_track(Vector(x*2.0f/window.get_width()-1.0f, y*2.0f/window.get_height()-1.0f, 0)))
+ if(Object *obj = pick_object(Vector(x*2.0f/window.get_width()-1.0f, y*2.0f/window.get_height()-1.0f, 0)))
{
- const TrackType &ttype = track->get_type();
- string info = format("%d %s", ttype.get_article_number(), ttype.get_description());
- if(mode!=CATALOGUE && abs(track->get_slope())>1e-4)
- info += format(" (slope %.1f%%)", abs(track->get_slope()/ttype.get_total_length()*100));
- if(track->get_turnout_id())
- info += format(" (turnout %d)", track->get_turnout_id());
- else if(track->get_sensor_id())
- info += format(" (sensor %d)", track->get_sensor_id());
-
+ const ObjectType &otype = obj->get_type();
+ string info = format("%d %s", otype.get_article_number(), otype.get_description());
+ if(Track *track = dynamic_cast<Track *>(obj))
+ {
+ const TrackType &ttype = track->get_type();
+ if(mode!=CATALOGUE && abs(track->get_slope())>1e-4)
+ info += format(" (slope %.1f%%)", abs(track->get_slope()/ttype.get_total_length()*100));
+ if(track->get_turnout_id())
+ info += format(" (turnout %d)", track->get_turnout_id());
+ else if(track->get_sensor_id())
+ info += format(" (sensor %d)", track->get_sensor_id());
+ }
return info;
}
cancel();
bool ok = false;
- const set<Track *> &stracks = selection.get_tracks();
+ const set<Track *> &stracks = selection.get_objects<Track>();
for(set<Track *>::const_iterator i=stracks.begin(); (!ok && i!=stracks.end()); ++i)
{
const vector<Track *> &links = (*i)->get_links();
if(mode)
cancel();
- list<Track *> new_tracks;
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ list<Object *> new_objs;
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
- Track *track = new Track(designer.get_layout(), i->track->get_type());
- track->set_position(i->track->get_position());
- track->set_rotation(i->track->get_rotation());
- new_tracks.push_back(track);
+ Object *obj = i->object->clone(&designer.get_layout());
+ if(Track *track = dynamic_cast<Track *>(obj))
+ {
+ for(list<Object *>::iterator j=new_objs.begin(); j!=new_objs.end(); ++j)
+ if(Track *track2 = dynamic_cast<Track *>(*j))
+ track->snap_to(*track2, true);
+ }
+ new_objs.push_back(obj);
}
- selection.clear();
- for(list<Track *>::iterator i=new_tracks.begin(); i!=new_tracks.end(); ++i)
- {
- selection.add_track(*i);
- for(list<Track *>::iterator j=i; j!=new_tracks.end(); ++j)
- if(j!=i)
- (*i)->snap_to(**j, true);
- }
+ selection.replace(new_objs.begin(), new_objs.end());
}
void Manipulator::flatten()
if(mode)
cancel();
- if(tracks.empty()) return;
+ if(objects.empty())
+ return;
float z = 0;
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
- z += i->track->get_position().z+i->track->get_slope()/2;
- z /= tracks.size();
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
+ {
+ z += i->object->get_position().z;
+ if(Track *track = dynamic_cast<Track *>(i->object))
+ z += track->get_slope()/2;
+ }
+ z /= static_cast<int>(objects.size());
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
- Vector p = i->track->get_position();
- i->track->set_position(Vector(p.x, p.y, z));
- i->track->set_slope(0);
+ Vector p = i->object->get_position();
+ i->object->set_position(Vector(p.x, p.y, z));
+ if(Track *track = dynamic_cast<Track *>(i->object))
+ track->set_slope(0);
}
for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
(*i)->check_slope();
- update_tracks();
+ update_objects();
}
void Manipulator::even_slope(bool smooth)
if(neighbors.size()!=2)
return;
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
- if(i->track->get_type().get_endpoints().size()!=2)
- return;
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
+ if(Track *track = dynamic_cast<Track *>(i->object))
+ if(track->get_type().get_endpoints().size()!=2)
+ return;
list<Track *> tracks2;
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
- tracks2.push_back(i->track);
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
+ if(Track *track = dynamic_cast<Track *>(i->object))
+ tracks2.push_back(track);
float total_len = 0;
for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
(*i)->check_slope();
- update_tracks();
+ update_objects();
}
void Manipulator::connect()
{
- if(tracks.size()!=2)
+ if(objects.size()!=2)
+ {
+ signal_status.emit("Exactly two tracks must be selected");
+ return;
+ }
+
+ Track *track1 = dynamic_cast<Track *>(objects.front().object);
+ Track *track2 = dynamic_cast<Track *>(objects.back().object);
+ if(!track1 || !track2)
{
signal_status.emit("Exactly two tracks must be selected");
return;
float limit = designer.get_layout().get_catalogue().get_gauge()/10;
- Track *track1 = tracks.front().track;
Vector pos1;
float dir1;
- Track *track2 = tracks.back().track;
bool ok = false;
float gap = 0;
for(unsigned i=0; i<track1->get_type().get_endpoints().size(); ++i)
return;
mode = NONE;
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
- i->track->set_position(Vector(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z));
- i->track->set_rotation(i->rot);
+ i->object->set_position(Vector(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z));
+ i->object->set_rotation(i->rot);
}
for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
if(m!=EXTEND)
{
for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
- for(vector<MTrack>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
- j->track->break_link(**i);
+ for(vector<MObject>::iterator j=objects.begin(); j!=objects.end(); ++j)
+ if(Track *track = dynamic_cast<Track *>(j->object))
+ track->break_link(**i);
}
const set<Track *> <racks = designer.get_layout().get_tracks();
for(set<Track *>::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
{
bool ok = true;
- for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && ok); ++j)
- ok = (j->track!=*i);
+ for(vector<MObject>::iterator j=objects.begin(); (j!=objects.end() && ok); ++j)
+ ok = (j->object!=*i);
if(!ok) continue;
- for(vector<MTrack>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
- j->track->snap_to(**i, true);
+ for(vector<MObject>::iterator j=objects.begin(); j!=objects.end(); ++j)
+ if(Track *track = dynamic_cast<Track *>(j->object))
+ track->snap_to(**i, true);
}
if(m==EXTEND)
}
else
{
- update_tracks();
+ update_objects();
update_neighbors();
}
{
Vector delta(gpointer.x-move_origin.x, gpointer.y-move_origin.y, 0);
Vector offset(center.x+delta.x, center.y+delta.y, center.z);
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
- i->track->set_position(Vector(offset.x+i->pos.x, offset.y+i->pos.y, offset.z+i->pos.z));
- i->track->set_rotation(i->rot);
+ i->object->set_position(Vector(offset.x+i->pos.x, offset.y+i->pos.y, offset.z+i->pos.z));
+ i->object->set_rotation(i->rot);
}
const set<Track *> <racks = designer.get_layout().get_tracks();
float limit = max(designer.get_layout().get_catalogue().get_gauge(),
designer.get_camera_controller().get_view_scale()/100.0f);
- MTrack *snapped = 0;
+ MObject *snapped = 0;
for(set<Track *>::const_iterator i=ltracks.begin(); (i!=ltracks.end() && !snapped); ++i)
{
bool ok = true;
- for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && ok); ++j)
- ok = (j->track!=*i);
- if(!ok) continue;
+ for(vector<MObject>::iterator j=objects.begin(); (j!=objects.end() && ok); ++j)
+ ok = (j->object!=*i);
+ if(!ok)
+ continue;
- for(vector<MTrack>::iterator j=tracks.begin(); (j!=tracks.end() && !snapped); ++j)
- if(j->track->snap_to(**i, false, limit))
- snapped = &*j;
+ for(vector<MObject>::iterator j=objects.begin(); (j!=objects.end() && !snapped); ++j)
+ if(Track *track = dynamic_cast<Track *>(j->object))
+ if(track->snap_to(**i, false, limit))
+ snapped = &*j;
}
if(snapped)
{
- float da = snapped->track->get_rotation()-snapped->rot;
+ float da = snapped->object->get_rotation()-snapped->rot;
float c = cos(da);
float s = sin(da);
- const Vector &sp = snapped->track->get_position();
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ const Vector &sp = snapped->object->get_position();
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
if(&*i==snapped)
continue;
Vector dp(i->pos.x-snapped->pos.x, i->pos.y-snapped->pos.y, 0);
- i->track->set_position(Vector(sp.x+c*dp.x-s*dp.y, sp.y+s*dp.x+c*dp.y, sp.z+i->pos.z-snapped->pos.z));
- i->track->set_rotation(i->rot+da);
+ i->object->set_position(Vector(sp.x+c*dp.x-s*dp.y, sp.y+s*dp.x+c*dp.y, sp.z+i->pos.z-snapped->pos.z));
+ i->object->set_rotation(i->rot+da);
}
}
}
angle += a-rot_origin;
rot_origin = a;
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
float c = cos(angle);
float s = sin(angle);
- i->track->set_position(Vector(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));
- i->track->set_rotation(angle+i->rot);
+ i->object->set_position(Vector(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));
+ i->object->set_rotation(angle+i->rot);
}
}
else if(mode==ELEVATE && axis==1)
signal_status.emit(format("Elevation: %+.0fmm (%.0fmm)", dz*1000, (center.z+dz)*1000));
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
- i->track->set_position(Vector(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z+dz));
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
+ i->object->set_position(Vector(center.x+i->pos.x, center.y+i->pos.y, center.z+i->pos.z+dz));
for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
(*i)->check_slope();
Vector pos;
float dir = 0;
float length = 0;
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
- unsigned n_endpoints = i->track->get_type().get_endpoints().size();
+ Track *track = dynamic_cast<Track *>(i->object);
+ if(!track)
+ continue;
+
+ unsigned n_endpoints = track->get_type().get_endpoints().size();
for(unsigned j=0; j<n_endpoints; ++j)
{
- if(i->track->get_link(j))
+ if(track->get_link(j))
continue;
- Vector ep_pos = i->track->get_endpoint_position(j);
- float ep_dir = i->track->get_endpoint_direction(j);
+ Vector ep_pos = track->get_endpoint_position(j);
+ float ep_dir = track->get_endpoint_direction(j);
float c = cos(ep_dir);
float s = sin(ep_dir);
float dx = gpointer.x-ep_pos.x;
if(mode)
cancel();
- tracks.clear();
- const set<Track *> &stracks = selection.get_tracks();
- tracks.insert(tracks.end(), stracks.begin(), stracks.end());
+ objects.clear();
+ set<Object *> pending = selection.get_objects();
+ while(!pending.empty())
+ {
+ for(set<Object *>::iterator i=pending.begin(); i!=pending.end(); )
+ {
+ if((*i)->get_parent() && pending.count((*i)->get_parent()))
+ ++i;
+ else
+ {
+ objects.push_back(*i);
+ pending.erase(i++);
+ }
+ }
+ }
update_neighbors();
- update_tracks();
+ update_objects();
}
-void Manipulator::update_tracks()
+void Manipulator::update_objects()
{
Vector minp, maxp;
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
- unsigned n_endpoints = i->track->get_type().get_endpoints().size();
- for(unsigned j=0; j<n_endpoints; ++j)
+ // XXX Use generic bounding box when it is implemented
+ if(Track *track = dynamic_cast<Track *>(i->object))
{
- Vector p = i->track->get_endpoint_position(j);
- if(i==tracks.begin() && j==0)
- minp = maxp = p;
- else
+ unsigned n_endpoints = track->get_type().get_endpoints().size();
+ for(unsigned j=0; j<n_endpoints; ++j)
{
- minp.x = min(minp.x, p.x);
- maxp.x = max(maxp.x, p.x);
- minp.y = min(minp.y, p.y);
- maxp.y = max(maxp.y, p.y);
- minp.z = min(minp.z, p.z);
+ Vector p = track->get_endpoint_position(j);
+ if(i==objects.begin() && j==0)
+ minp = maxp = p;
+ else
+ {
+ minp.x = min(minp.x, p.x);
+ maxp.x = max(maxp.x, p.x);
+ minp.y = min(minp.y, p.y);
+ maxp.y = max(maxp.y, p.y);
+ minp.z = min(minp.z, p.z);
+ }
}
}
+ else
+ {
+ const Vector &p = i->object->get_position();
+ minp.x = min(minp.x, p.x);
+ maxp.x = max(maxp.x, p.x);
+ minp.y = min(minp.y, p.y);
+ maxp.y = max(maxp.y, p.y);
+ minp.z = min(minp.z, p.z);
+ }
}
center = Vector((minp.x+maxp.x)/2, (minp.y+maxp.y)/2, minp.z);
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
- const Vector &tp = i->track->get_position();
- i->pos = Vector(tp.x-center.x, tp.y-center.y, tp.z-center.z);
- i->rot = i->track->get_rotation();
+ const Vector &p = i->object->get_position();
+ i->pos = Vector(p.x-center.x, p.y-center.y, p.z-center.z);
+ i->rot = i->object->get_rotation();
}
}
void Manipulator::update_neighbors()
{
neighbors.clear();
- for(vector<MTrack>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
- const vector<Track *> &links = i->track->get_links();
+ Track *track = dynamic_cast<Track *>(i->object);
+ if(!track)
+ continue;
+
+ const vector<Track *> &links = track->get_links();
for(vector<Track *>::const_iterator j=links.begin(); j!=links.end(); ++j)
{
if(!*j)
continue;
bool ok = true;
- for(vector<MTrack>::iterator k=tracks.begin(); (k!=tracks.end() && ok); ++k)
- ok = (k->track!=*j);
+ for(vector<MObject>::iterator k=objects.begin(); (k!=objects.end() && ok); ++k)
+ ok = (k->object!=*j);
if(ok)
neighbors.insert(*j);
}
-Manipulator::MTrack::MTrack(Track *t):
- track(t),
- pos(track->get_position()),
- rot(track->get_rotation())
+Manipulator::MObject::MObject(Object *o):
+ object(o),
+ pos(object->get_position()),
+ rot(object->get_rotation())
{ }
using namespace R2C2;
using namespace Msp;
-Track *Selection::get_track() const
+Object *Selection::get_object() const
{
- if(tracks.empty())
+ if(objects.empty())
return 0;
else
- return *tracks.begin();
+ return *objects.begin();
}
void Selection::clear()
{
- tracks.clear();
+ objects.clear();
signal_changed.emit();
}
-void Selection::add_track(Track *t)
+void Selection::add_object(Object *o)
{
- if(tracks.insert(t).second)
+ if(objects.insert(o).second)
signal_changed.emit();
}
-void Selection::remove_track(Track *t)
+void Selection::remove_object(Object *o)
{
- if(tracks.erase(t))
+ if(objects.erase(o))
signal_changed.emit();
}
-void Selection::toggle_track(Track *t)
+void Selection::toggle_object(Object *o)
{
- if(!tracks.erase(t))
- tracks.insert(t);
+ if(!objects.erase(o))
+ objects.insert(o);
signal_changed.emit();
}
void Selection::select_more()
{
set<Track *> new_tracks;
- for(set<Track *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
- {
- const vector<Track *> &links = (*i)->get_links();
- for(vector<Track *>::const_iterator j=links.begin(); j!=links.end(); ++j)
- if(*j)
- new_tracks.insert(*j);
- }
+ for(set<Object *>::iterator i=objects.begin(); i!=objects.end(); ++i)
+ if(Track *track = dynamic_cast<Track *>(*i))
+ {
+ const vector<Track *> &links = track->get_links();
+ for(vector<Track *>::const_iterator j=links.begin(); j!=links.end(); ++j)
+ if(*j)
+ new_tracks.insert(*j);
+ }
bool changed = false;
for(set<Track *>::iterator i=new_tracks.begin(); i!=new_tracks.end(); ++i)
- if(tracks.insert(*i).second)
+ if(objects.insert(*i).second)
changed = true;
if(changed)
void Selection::select_linked()
{
bool changed = false;
- list<Track *> queue(tracks.begin(), tracks.end());
+ list<Track *> queue;
+ for(set<Object *>::iterator i=objects.begin(); i!=objects.end(); ++i)
+ if(Track *track = dynamic_cast<Track *>(*i))
+ queue.push_back(track);
+
while(!queue.empty())
{
Track *track = queue.front();
const vector<Track *> &links = track->get_links();
for(vector<Track *>::const_iterator j=links.begin(); j!=links.end(); ++j)
- if(*j && tracks.insert(*j).second)
+ if(*j && objects.insert(*j).second)
{
queue.push_back(*j);
changed = true;
}
}
- for(set<Track *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
- {
- const vector<Track *> &links = (*i)->get_links();
- for(vector<Track *>::const_iterator j=links.begin(); j!=links.end(); ++j)
- if(*j && tracks.insert(*j).second)
- changed = true;
- }
if(changed)
signal_changed.emit();
void Selection::select_blocks()
{
bool changed = false;
- for(set<Track *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
- {
- const set<Track *> &btracks = (*i)->get_block().get_tracks();
- for(set<Track *>::iterator j=btracks.begin(); j!=btracks.end(); ++j)
- if(!tracks.count(*j))
- {
- tracks.insert(*j);
- changed = true;
- }
- }
+ for(set<Object *>::iterator i=objects.begin(); i!=objects.end(); ++i)
+ if(Track *track = dynamic_cast<Track *>(*i))
+ {
+ const set<Track *> &btracks = track->get_block().get_tracks();
+ for(set<Track *>::iterator j=btracks.begin(); j!=btracks.end(); ++j)
+ if(objects.insert(*j).second)
+ changed = true;
+ }
if(changed)
signal_changed.emit();