for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
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);
- }
+ for(list<Object *>::iterator j=new_objs.begin(); j!=new_objs.end(); ++j)
+ obj->link_to(**j);
new_objs.push_back(obj);
}
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;
+ if(i->object->get_n_link_slots()!=2)
+ return;
list<Track *> tracks2;
for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
}
set<Track *>::iterator nb = neighbors.begin();
- int epi = (*nb)->get_endpoint_by_link(*order.front().track);
+ int epi = (*nb)->get_link_slot(*order.front().track);
float start_z = (*nb)->get_snap_node(epi).position.z;
++nb;
- epi = (*nb)->get_endpoint_by_link(*order.back().track);
+ epi = (*nb)->get_link_slot(*order.back().track);
float end_z = (*nb)->get_snap_node(epi).position.z;
if(smooth)
return;
}
- trks.front()->snap_to(*track1, true);
- trks.back()->snap_to(*track2, true);
+ trks.front()->link_to(*track1);
+ trks.back()->link_to(*track2);
selection.replace(trks.begin(), trks.end());
}
{
for(set<Track *>::iterator i=neighbors.begin(); i!=neighbors.end(); ++i)
for(vector<MObject>::iterator j=objects.begin(); j!=objects.end(); ++j)
- if(Track *track = dynamic_cast<Track *>(j->object))
- track->break_link(**i);
+ j->object->break_link(**i);
}
const set<Track *> <racks = designer.get_layout().get_tracks();
if(!ok) continue;
for(vector<MObject>::iterator j=objects.begin(); j!=objects.end(); ++j)
- if(Track *track = dynamic_cast<Track *>(j->object))
- track->snap_to(**i, true);
+ j->object->link_to(**i);
}
if(m==EXTEND)
continue;
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(j->object->snap_to(**i, limit))
+ snapped = &*j;
}
if(snapped)
float length = 0;
for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
{
- 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)
+ unsigned nls = i->object->get_n_link_slots();
+ for(unsigned j=0; j<nls; ++j)
{
- if(track->get_link(j))
+ if(i->object->get_link(j))
continue;
- Snap sn = track->get_snap_node(j);
+ Snap sn = i->object->get_snap_node(j);
float c = cos(sn.rotation);
float s = sin(sn.rotation);
float dx = gpointer.x-sn.position.x;
track->set_rotation(dir);
if(!trks.empty())
- track->snap_to(*trks.back(), true);
+ track->link_to(*trks.back());
trks.push_back(track);
pos.x += c**i;
void Selection::select_more()
{
- set<Track *> new_tracks;
+ set<Object *> new_objects;
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);
- }
+ {
+ unsigned nls = (*i)->get_n_link_slots();
+ for(unsigned j=0; j<nls; ++j)
+ if(Object *obj = (*i)->get_link(j))
+ new_objects.insert(obj);
+ }
bool changed = false;
- for(set<Track *>::iterator i=new_tracks.begin(); i!=new_tracks.end(); ++i)
+ for(set<Object *>::iterator i=new_objects.begin(); i!=new_objects.end(); ++i)
if(objects.insert(*i).second)
changed = true;
void Selection::select_linked()
{
bool changed = false;
- 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);
+ list<Object *> queue(objects.begin(), objects.end());
while(!queue.empty())
{
- Track *track = queue.front();
- queue.erase(queue.begin());
-
- const vector<Track *> &links = track->get_links();
- for(vector<Track *>::const_iterator j=links.begin(); j!=links.end(); ++j)
- if(*j && objects.insert(*j).second)
- {
- queue.push_back(*j);
- changed = true;
- }
+ Object *obj = queue.front();
+ queue.pop_front();
+
+ unsigned nls = obj->get_n_link_slots();
+ for(unsigned j=0; j<nls; ++j)
+ if(Object *linked = obj->get_link(j))
+ if(objects.insert(linked).second)
+ {
+ queue.push_back(linked);
+ changed = true;
+ }
}
if(changed)
new_tracks = true;
for(set<Track *>::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i)
if(*i!=trk)
- trk->snap_to(**i, true);
+ trk->link_to(**i);
}
void Layout::Loader::train(unsigned art_nr, unsigned addr, const std::string &proto)
return false;
}
+Object *Object::get_link(unsigned) const
+{
+ throw out_of_range("Object::get_link");
+}
+
+bool Object::break_link(Object &other)
+{
+ unsigned nls = get_n_link_slots();
+ for(unsigned i=0; i<nls; ++i)
+ if(get_link(i)==&other)
+ return break_link(i);
+
+ return false;
+}
+
+void Object::break_links()
+{
+ unsigned nls = get_n_link_slots();
+ for(unsigned i=0; i<nls; ++i)
+ break_link(i);
+}
+
} // namespace R2C2
virtual SnapType get_default_snap_type_to(const Object &) const { return NO_SNAP; }
public:
+ virtual unsigned get_n_link_slots() const { return 0; }
+ virtual Object *get_link(unsigned) const;
+ virtual int get_link_slot(const Object &) const { return -1; }
+ virtual bool link_to(Object &) { return false; }
+ virtual bool break_link(Object &);
+ virtual bool break_link(unsigned) { return false; }
+ virtual void break_links();
+
virtual bool collide_ray(const Vector &, const Vector &) const = 0;
};
if(unsigned tid2 = links[j]->get_turnout_id())
{
- const TrackType::Endpoint &ep = links[j]->get_type().get_endpoint(links[j]->get_endpoint_by_link(**i));
+ const TrackType::Endpoint &ep = links[j]->get_type().get_endpoint(links[j]->get_link_slot(**i));
int p = get_turnout(tid2);
if(p>=0 && !ep.has_path(p))
{
if(unsigned tid = (*i)->get_turnout_id())
{
- const TrackType::Endpoint &ep = (*i)->get_type().get_endpoint((*i)->get_endpoint_by_link(trk));
+ const TrackType::Endpoint &ep = (*i)->get_type().get_endpoint((*i)->get_link_slot(trk));
int path = get_turnout(tid);
if(path>=0)
{
unsigned tid2 = tlinks[j]->get_turnout_id();
if(tid2)
{
- const TrackType::Endpoint &ep2 = tlinks[j]->get_type().get_endpoint(tlinks[j]->get_endpoint_by_link(**i));
+ const TrackType::Endpoint &ep2 = tlinks[j]->get_type().get_endpoint(tlinks[j]->get_link_slot(**i));
path = get_turnout(tid2);
// Ignore a linked turnout with some other path set
if(path>=0 && !ep2.has_path(path))
{
Track *link = (*i)->get_link(k);
if(!obj.tracks.count(link))
- obj.add_track_chain(*link, link->get_endpoint_by_link(**i), turnouts);
+ obj.add_track_chain(*link, link->get_link_slot(**i), turnouts);
if(!obj.tracks.count(*i))
obj.add_track_chain(**i, k, turnouts);
break;
if(links[0] && links[1])
{
- Vector epp0 = links[0]->get_snap_node(links[0]->get_endpoint_by_link(*this)).position;
- Vector epp1 = links[1]->get_snap_node(links[1]->get_endpoint_by_link(*this)).position;
+ Vector epp0 = links[0]->get_snap_node(links[0]->get_link_slot(*this)).position;
+ Vector epp1 = links[1]->get_snap_node(links[1]->get_link_slot(*this)).position;
position.z = epp0.z;
slope = epp1.z-position.z;
}
slope = 0;
if(links[0])
{
- Vector epp = links[0]->get_snap_node(links[0]->get_endpoint_by_link(*this)).position;
+ Vector epp = links[0]->get_snap_node(links[0]->get_link_slot(*this)).position;
position.z = epp.z;
}
else if(links[1])
{
- Vector epp = links[1]->get_snap_node(links[1]->get_endpoint_by_link(*this)).position;
+ Vector epp = links[1]->get_snap_node(links[1]->get_link_slot(*this)).position;
position.z = epp.z;
}
}
layout.get_driver().set_turnout(turnout_id, p);
}
-int Track::get_endpoint_by_link(Track &other) const
-{
- for(unsigned i=0; i<links.size(); ++i)
- if(links[i]==&other)
- return i;
-
- return -1;
-}
-
-bool Track::snap_to(Track &other, bool link, float limit)
-{
- if(!limit || link)
- {
- limit = layout.get_catalogue().get_gauge();
- if(link && !flex && !other.get_flex())
- limit /= 10;
- }
- limit *= limit;
-
- const vector<TrackType::Endpoint> &eps = type.get_endpoints();
- const vector<TrackType::Endpoint> &other_eps = other.get_type().get_endpoints();
-
- for(unsigned i=0; i<eps.size(); ++i)
- {
- Vector epp = get_snap_node(i).position;
-
- for(unsigned j=0; j<other_eps.size(); ++j)
- {
- if(other.get_link(j))
- continue;
-
- Vector epp2 = other.get_snap_node(j).position;
- float dx = epp2.x-epp.x;
- float dy = epp2.y-epp.y;
- float dz = epp2.z-epp.z;
- if(dx*dx+dy*dy<limit && dz*dz<limit)
- {
- if(!link || (!flex && !other.get_flex()))
- {
- set_rotation(other.rotation+other_eps[j].dir-eps[i].dir+M_PI);
- Vector p(epp2.x-(eps[i].pos.x*cos(rotation)-eps[i].pos.y*sin(rotation)),
- epp2.y-(eps[i].pos.y*cos(rotation)+eps[i].pos.x*sin(rotation)),
- epp2.z);
- if(eps.size()==2 && i==1)
- p.z -= slope;
- set_position(p);
- }
-
- if(link)
- {
- if(links[i])
- break_link(*links[i]);
- links[i] = &other;
- other.links[j] = this;
- layout.create_blocks(*this);
-
- signal_link_changed.emit(i, &other);
- other.signal_link_changed.emit(j, this);
- }
-
- return true;
- }
- }
- }
-
- return false;
-}
-
-void Track::break_link(Track &trk)
-{
- for(vector<Track *>::iterator i=links.begin(); i!=links.end(); ++i)
- if(*i==&trk)
- {
- *i = 0;
- trk.break_link(*this);
- // XXX Creates the blocks twice
- layout.create_blocks(*this);
- signal_link_changed.emit(i-links.begin(), 0);
- return;
- }
-}
-
-void Track::break_links()
-{
- for(vector<Track *>::iterator i=links.begin(); i!=links.end(); ++i)
- if(Track *trk=*i)
- {
- *i = 0;
- trk->break_link(*this);
- }
-}
-
-Track *Track::get_link(unsigned i) const
-{
- if(i>=links.size())
- throw out_of_range("Track::get_link");
-
- return links[i];
-}
-
TrackPoint Track::get_point(unsigned epi, unsigned path, float d) const
{
TrackPoint p = type.get_point(epi, path, d);
return NO_SNAP;
}
+unsigned Track::get_n_link_slots() const
+{
+ return links.size();
+}
+
+Track *Track::get_link(unsigned i) const
+{
+ if(i>=links.size())
+ throw out_of_range("Track::get_link");
+
+ return links[i];
+}
+
+int Track::get_link_slot(const Object &other) const
+{
+ for(unsigned i=0; i<links.size(); ++i)
+ if(links[i]==&other)
+ return i;
+
+ return -1;
+}
+
+bool Track::link_to(Object &other)
+{
+ Track *otrack = dynamic_cast<Track *>(&other);
+ if(!otrack)
+ return false;
+
+ float limit = layout.get_catalogue().get_gauge();
+ if(!flex && !otrack->get_flex())
+ limit /= 10;
+ limit *= limit;
+
+ unsigned nsn = get_n_snap_nodes();
+ unsigned other_nsn = other.get_n_snap_nodes();
+ for(unsigned i=0; i<nsn; ++i)
+ {
+ Snap sn = get_snap_node(i);
+ for(unsigned j=0; j<other_nsn; ++j)
+ {
+ Snap osn = other.get_snap_node(j);
+ Vector d(osn.position.x-sn.position.x, osn.position.y-sn.position.y, osn.position.z-sn.position.z);
+ float da = osn.rotation-sn.rotation-M_PI;
+ while(da<-M_PI)
+ da += M_PI*2;
+ while(da>M_PI)
+ da -= M_PI*2;
+
+ if(d.x*d.x+d.y*d.y<limit && d.z*d.z<limit && da>-0.01 && da<0.01)
+ {
+ break_link(i);
+ links[i] = otrack;
+ otrack->links[j] = this;
+ layout.create_blocks(*this);
+
+ signal_link_changed.emit(i, otrack);
+ otrack->signal_link_changed.emit(j, this);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool Track::break_link(unsigned i)
+{
+ if(i>=links.size())
+ throw out_of_range("Track::break_link");
+
+ Track *other = links[i];
+ if(!other)
+ return false;
+
+ links[i] = 0;
+ other->break_link(*this);
+ // XXX Creates the blocks twice, because the other track calls this too
+ layout.create_blocks(*this);
+ signal_link_changed.emit(i, 0);
+
+ return true;
+}
+
bool Track::collide_ray(const Vector &start, const Vector &ray) const
{
Vector local_start(start.x-position.x, start.y-position.y, start.z-position.z);
unsigned get_active_path() const { return active_path; }
bool is_path_changing() const { return path_changing; }
- int get_endpoint_by_link(Track &) const;
- bool snap_to(Track &, bool, float = 0);
- void break_link(Track &);
- void break_links();
- const std::vector<Track *> &get_links() const { return links; }
- Track *get_link(unsigned) const;
TrackPoint get_point(unsigned, unsigned, float) const;
TrackPoint get_point(unsigned, float) const;
virtual SnapType get_default_snap_type_to(const Object &) const;
public:
+ virtual unsigned get_n_link_slots() const;
+ virtual Track *get_link(unsigned) const;
+ const std::vector<Track *> &get_links() const { return links; }
+ virtual int get_link_slot(const Object &) const;
+ virtual bool link_to(Object &);
+ using Object::break_link;
+ virtual bool break_link(unsigned);
+
virtual bool collide_ray(const Vector &, const Vector &) const;
void save(std::list<Msp::DataFile::Statement> &) const;
TrackIter result;
result._track = _track->get_link(exit);
- result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0);
+ result._entry = (result._track ? result._track->get_link_slot(*_track) : 0);
return result;
}
TrackIter result;
result._track = _track->get_link(_entry);
- result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0);
+ result._entry = (result._track ? result._track->get_link_slot(*_track) : 0);
return result;
}
return get_point(front.get_point().pos, back.get_point().pos, ratio);
}
+unsigned Vehicle::get_n_link_slots() const
+{
+ return 2;
+}
+
+Vehicle *Vehicle::get_link(unsigned i) const
+{
+ if(i>=2)
+ throw out_of_range("Vehicle::get_link");
+
+ return (i==0 ? prev : next);
+}
+
+int Vehicle::get_link_slot(const Object &other) const
+{
+ if(&other==prev)
+ return 0;
+ else if(&other==next)
+ return 1;
+ else
+ return -1;
+}
+
Vehicle::Axle::Axle(const VehicleType::Axle &t):
type(&t),
TrackPoint get_point(const TrackPosition &, float, float = 0.5) const;
public:
+ virtual unsigned get_n_link_slots() const;
+ virtual Vehicle *get_link(unsigned) const;
+ virtual int get_link_slot(const Object &) const;
+
virtual bool collide_ray(const Vector &, const Vector &) const { return false; }
};