namespace R2C2 {
Signal::Signal(Layout &l, const SignalType &t):
- Object(l),
+ TrackAttachment(l),
type(t),
address(0),
- track(0),
- block(0),
- entry(0),
train(0),
check_allocated_blocks(false),
passing(false)
{
position = p;
- update_location();
+ update_attachment();
signal_moved.emit();
}
-void Signal::update_location()
+void Signal::set_rotation(const Angle &r)
{
- const set<Track *> &tracks = layout.get_all<Track>();
- float limit = layout.get_catalogue().get_gauge()*2;
- float dist = -1;
- for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
- if(!(*i)->get_type().is_turnout())
- {
- Snap sn;
- sn.position = position;
- sn.rotation = rotation;
- (*i)->snap(sn, limit, SNAP_SEGMENT);
- float d = distance(position, sn.position);
- if(d<dist || dist<0)
- {
- track = *i;
- dist = d;
- }
- }
-
- block = 0;
-
- if(!track)
- return;
+ rotation = r;
- unsigned n_endpoints = track->get_type().get_endpoints().size();
- for(unsigned j=0; j<n_endpoints; ++j)
- {
- Angle a = wrap_with_base(track->get_snap_node(j).rotation-rotation, -Angle::quarter_turn());
- if(a>=Angle::quarter_turn())
- {
- BlockIter biter = TrackIter(track, j).block_iter();
- if(biter)
- {
- block = &track->get_block();
- entry = biter.entry();
- }
- }
- }
+ update_attachment();
+ signal_moved.emit();
}
-void Signal::set_rotation(const Angle &r)
+void Signal::update_attachment()
{
- rotation = r;
+ attach_to_closest(layout.get_catalogue().get_gauge()*2);
- update_location();
- signal_moved.emit();
+ if(track)
+ block = track.block_iter();
+ else
+ block = BlockIter();
}
unsigned Signal::get_n_snap_nodes() const
if(check_allocated_blocks)
{
unsigned n_blocks = 0;
- BlockIter iter(block, entry);
- iter = iter.next();
+ BlockIter iter = block.next();
while(iter && iter->get_train()==train)
{
if(iter->get_sensor_id())
void Signal::block_reserved(const Block &b, Train *t)
{
- if(&b==block)
+ if(&b==block.block())
{
if(t)
{
const BlockIter &b_iter = t->get_block_allocator().iter_for(b);
- if(b_iter && b_iter.entry()==entry)
+ if(b_iter && b_iter.entry()==block.entry())
{
if(train_conn)
train_conn.disconnect();
void Signal::train_advanced(Block &b)
{
- if(&b==block)
+ if(&b==block.block())
passing = true;
else if(passing && b.get_sensor_id())
{
#include <msp/datafile/objectloader.h>
#include <msp/time/timedelta.h>
+#include "blockiter.h"
#include "geometry.h"
-#include "object.h"
#include "signaltype.h"
#include "track.h"
+#include "trackattachment.h"
namespace R2C2 {
-class Block;
class Layout;
class Train;
-class Signal: public Object
+class Signal: public TrackAttachment
{
public:
class Loader: public Msp::DataFile::ObjectLoader<Signal>
private:
const SignalType &type;
unsigned address;
- Track *track;
- Block *block;
- unsigned entry;
+ BlockIter block;
Train *train;
sigc::connection train_conn;
bool check_allocated_blocks;
virtual void set_rotation(const Angle &);
virtual void set_tilt(const Angle &) { }
private:
- void update_location();
+ void update_attachment();
public:
- virtual Track *get_parent() const { return track; }
virtual unsigned get_n_snap_nodes() const;
virtual Snap get_snap_node(unsigned) const;
#include <cmath>
+#include <msp/core/maputils.h>
#include "block.h"
#include "catalogue.h"
#include "driver.h"
return true;
}
+void Track::add_attachment(TrackAttachment &a)
+{
+ if(find(attachments.begin(), attachments.end(), &a)!=attachments.end())
+ throw key_error(&a);
+ attachments.push_back(&a);
+}
+
+void Track::remove_attachment(TrackAttachment &a)
+{
+ AttachmentList::iterator i = find(attachments.begin(), attachments.end(), &a);
+ if(i==attachments.end())
+ throw key_error(&a);
+ attachments.erase(i);
+}
+
void Track::save(list<DataFile::Statement> &st) const
{
st.push_back((DataFile::Statement("position"), position.x, position.y, position.z));
class Block;
class Layout;
+class TrackAttachment;
class Track: public Object, public sigc::trackable
{
void turnout_id(unsigned);
};
+ typedef std::list<TrackAttachment *> AttachmentList;
+
sigc::signal<void, unsigned, Track *> signal_link_changed;
sigc::signal<void, unsigned> signal_path_changing;
sigc::signal<void, unsigned> signal_path_changed;
std::vector<Track *> links;
unsigned active_path;
bool path_changing;
+ AttachmentList attachments;
Track(const Track &);
Track &operator=(const Track &);
using Object::break_link;
virtual bool break_link(unsigned);
+ void add_attachment(TrackAttachment &);
+ void remove_attachment(TrackAttachment &);
+ const AttachmentList &get_attachments() const { return attachments; }
+
void save(std::list<Msp::DataFile::Statement> &) const;
private:
void turnout_event(unsigned, unsigned);
--- /dev/null
+#include "catalogue.h"
+#include "layout.h"
+#include "track.h"
+#include "trackattachment.h"
+
+using namespace std;
+
+namespace R2C2 {
+
+TrackAttachment::TrackAttachment(Layout &l):
+ Object(l),
+ offset(0)
+{ }
+
+TrackAttachment::~TrackAttachment()
+{
+ if(track)
+ track->remove_attachment(*this);
+}
+
+void TrackAttachment::attach_to(const TrackIter &t, float o)
+{
+ if(track)
+ track->remove_attachment(*this);
+
+ track = t;
+ offset = o;
+
+ if(track)
+ track->add_attachment(*this);
+}
+
+void TrackAttachment::attach_to_closest(float limit)
+{
+ const set<Track *> &tracks = layout.get_all<Track>();
+ float dist = -1;
+ Track *trk = 0;
+ Vector closest;
+ for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ if(!(*i)->get_type().is_turnout())
+ {
+ Snap sn;
+ sn.position = position;
+ sn.rotation = rotation;
+ if((*i)->snap(sn, limit, SNAP_SEGMENT))
+ {
+ float d = distance(position, sn.position);
+ if(d<dist || dist<0)
+ {
+ trk = *i;
+ closest = sn.position;
+ dist = d;
+ }
+ }
+ }
+
+ if(trk)
+ {
+ unsigned nsn = trk->get_n_snap_nodes();
+ for(unsigned i=0; i<nsn; ++i)
+ {
+ Snap sn = trk->get_snap_node(i);
+ Angle adiff = abs(wrap_balanced(sn.rotation-rotation));
+ if(adiff<Angle::quarter_turn())
+ {
+ TrackIter iter(trk, i);
+ attach_to(iter, find_offset(iter, closest));
+ break;
+ }
+ }
+ }
+ else
+ attach_to(TrackIter(), 0);
+}
+
+float TrackAttachment::find_offset(const TrackIter &trk, const Vector &point)
+{
+ float margin = 0.01*layout.get_catalogue().get_scale();
+ Vector epp = trk->get_snap_node(trk.entry()).position;
+
+ float dist = distance(epp, point);
+ float offs = dist;
+ while(1)
+ {
+ TrackPoint tp = trk->get_point(trk.entry(), offs);
+ float diff = dist-distance(epp, tp.pos);
+ if(abs(diff)<margin)
+ break;
+ offs += diff;
+ }
+
+ return offs;
+}
+
+} // namespace R2C"
--- /dev/null
+#ifndef LIBR2C2_TRACKATTACHMENT_H_
+#define LIBR2C2_TRACKATTACHMENT_H_
+
+#include "object.h"
+#include "trackiter.h"
+
+namespace R2C2 {
+
+class TrackAttachment: public Object
+{
+protected:
+ TrackIter track;
+ float offset;
+
+ TrackAttachment(Layout &);
+public:
+ virtual ~TrackAttachment();
+
+ const TrackIter &get_track_iter() const { return track; }
+ Track *get_track() const { return track.track(); }
+ unsigned get_entry() const { return track.entry(); }
+ float get_offset() const { return offset; }
+protected:
+ void attach_to(const TrackIter &, float);
+ void attach_to_closest(float);
+ float find_offset(const TrackIter &, const Vector &);
+
+public:
+ virtual Track *get_parent() const { return track.track(); }
+};
+
+} // namespace R2C2
+
+#endif