]> git.tdb.fi Git - r2c2.git/commitdiff
Add an abstraction for things that are attached to tracks
authorMikko Rasa <tdb@tdb.fi>
Thu, 4 Jul 2013 20:51:15 +0000 (23:51 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 4 Jul 2013 20:51:15 +0000 (23:51 +0300)
source/libr2c2/signal.cpp
source/libr2c2/signal.h
source/libr2c2/track.cpp
source/libr2c2/track.h
source/libr2c2/trackattachment.cpp [new file with mode: 0644]
source/libr2c2/trackattachment.h [new file with mode: 0644]

index c4a83b9a3cee6719c4afe5f65c406b572edb47c3..96c44d831d225cec9c06613c2500e779a8495558 100644 (file)
@@ -14,12 +14,9 @@ using namespace Msp;
 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)
@@ -54,57 +51,26 @@ void Signal::set_position(const Vector &p)
 {
        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
@@ -136,8 +102,7 @@ void Signal::tick(const Time::TimeDelta &)
        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())
@@ -161,12 +126,12 @@ void Signal::tick(const Time::TimeDelta &)
 
 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();
@@ -188,7 +153,7 @@ void Signal::block_reserved(const Block &b, Train *t)
 
 void Signal::train_advanced(Block &b)
 {
-       if(&b==block)
+       if(&b==block.block())
                passing = true;
        else if(passing && b.get_sensor_id())
        {
index 2f77f0627b11ec8ba46d82f6f8382ab73cd93c56..7f6e011d148c55add40d610a0ae9124695d89ee0 100644 (file)
@@ -3,18 +3,18 @@
 
 #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>
@@ -31,9 +31,7 @@ public:
 private:
        const SignalType &type;
        unsigned address;
-       Track *track;
-       Block *block;
-       unsigned entry;
+       BlockIter block;
        Train *train;
        sigc::connection train_conn;
        bool check_allocated_blocks;
@@ -51,9 +49,8 @@ public:
        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;
index 43bacc3d8bc10f6a4653716064cbffb331e2ed0c..26fb59e0fa7e756b619ad718d090dec6b6f05314 100644 (file)
@@ -1,4 +1,5 @@
 #include <cmath>
+#include <msp/core/maputils.h>
 #include "block.h"
 #include "catalogue.h"
 #include "driver.h"
@@ -331,6 +332,21 @@ bool Track::break_link(unsigned i)
        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));
index 916ea1966183c8ce5a87ec97a0c2297570a29c4a..994712da8c43cc2171cf340cb624cf55aa53bbd4 100644 (file)
@@ -13,6 +13,7 @@ namespace R2C2 {
 
 class Block;
 class Layout;
+class TrackAttachment;
 
 class Track: public Object, public sigc::trackable
 {
@@ -30,6 +31,8 @@ public:
                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;
@@ -44,6 +47,7 @@ private:
        std::vector<Track *> links;
        unsigned active_path;
        bool path_changing;
+       AttachmentList attachments;
 
        Track(const Track &);
        Track &operator=(const Track &);
@@ -92,6 +96,10 @@ public:
        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);
diff --git a/source/libr2c2/trackattachment.cpp b/source/libr2c2/trackattachment.cpp
new file mode 100644 (file)
index 0000000..bed7db8
--- /dev/null
@@ -0,0 +1,95 @@
+#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"
diff --git a/source/libr2c2/trackattachment.h b/source/libr2c2/trackattachment.h
new file mode 100644 (file)
index 0000000..8551250
--- /dev/null
@@ -0,0 +1,34 @@
+#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