]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/zone.cpp
Support directionality for zones
[r2c2.git] / source / libr2c2 / zone.cpp
index 8b6c95f9c9af2fd0911c956e76fe44e15cfb0362..52e3c281d8175254474cef140ea4217774c3c3e9 100644 (file)
@@ -12,7 +12,8 @@ namespace R2C2 {
 
 Zone::Zone(Layout &l):
        TrackChain(l),
-       number(0)
+       number(0),
+       up_end(-1)
 {
        layout.add(*this);
 }
@@ -54,6 +55,91 @@ void Zone::update_name()
        TrackChain::set_name(full_name);
 }
 
+void Zone::set_direction_towards(Track &track, Direction dir)
+{
+       if(dir==UNSPECIFIED)
+               throw invalid_argument("Zone::set_direction_towards");
+       if(tracks.empty())
+               throw logic_error("no tracks");
+       if(tracks.count(&track))
+               throw invalid_argument("Zone::set_direction_towards");
+
+       Validity valid = check_validity(track);
+       if(valid!=VALID)
+               throw_bad_chain(valid);
+
+       for(unsigned i=0; i<2; ++i)
+               if(ends[i] && ends[i]->get_link_slot(track)>=0)
+               {
+                       up_end = (dir==UP ? i : 1-i);
+                       return;
+               }
+
+       throw logic_error("internal error (valid track not linked to ends)");
+}
+
+void Zone::clear_direction()
+{
+       up_end = -1;
+}
+
+TrackIter Zone::iter_for(Track &track, Direction dir) const
+{
+       if(!tracks.count(&track))
+               return TrackIter();
+       else if(dir==UNSPECIFIED)
+               return TrackIter(&track, 0);
+       else if(up_end<0)
+               return TrackIter();
+
+       for(int i=0; i<2; ++i)
+               if(&track==ends[i].track())
+               {
+                       if((i==up_end)==(dir==UP))
+                               return ends[i];
+                       else
+                               return ends[i].reverse();
+               }
+
+       TrackIter iter = ends[up_end^(dir==UP)].reverse();
+       while(iter && tracks.count(iter.track()))
+       {
+               if(iter.track()==&track)
+                       return iter;
+
+               iter = next_iter(iter);
+       }
+
+       return TrackIter();
+}
+
+TrackIter Zone::get_end(Direction dir) const
+{
+       if(dir==UNSPECIFIED)
+               return ends[0];
+       if(up_end<0)
+               return TrackIter();
+
+       return ends[up_end^(dir==DOWN)];
+}
+
+TrackIter Zone::next_iter(const TrackIter &iter) const
+{
+       TrackIter next_outside;
+       const TrackType::Endpoint &ep = iter.endpoint();
+       for(unsigned i=0; ep.paths>>i; ++i)
+               if(ep.has_path(i))
+                       if(TrackIter next = iter.next(i))
+                       {
+                               if(tracks.count(next.track()))
+                                       return next;
+                               else
+                                       next_outside = next;
+                       }
+
+       return next_outside;
+}
+
 void Zone::save(list<DataFile::Statement> &st) const
 {
        st.push_back((DataFile::Statement("group"), group));
@@ -75,6 +161,19 @@ void Zone::save(list<DataFile::Statement> &st) const
 
                iter = next_iter(iter);
        }
+
+       if(up_end>=0)
+       {
+               for(unsigned i=0; i<2; ++i)
+               {
+                       TrackIter hint = next_iter(ends[up_end^i]);
+                       if(hint && !tracks.count(hint.track()))
+                       {
+                               st.push_back((DataFile::Statement("direction_hint"), hint->get_block().get_id(), (i==0 ? UP : DOWN)));
+                               break;
+                       }
+               }
+       }
 }
 
 DataFile::Statement Zone::save_reference() const
@@ -87,6 +186,7 @@ Zone::Loader::Loader(Zone &z):
        DataFile::ObjectLoader<Zone>(z)
 {
        add("block",     &Loader::block);
+       add("direction_hint", &Loader::direction_hint);
        add("group",     &Zone::group);
        add("number",    &Zone::number);
        add("qualifier", &Zone::qualifier);
@@ -103,4 +203,18 @@ void Zone::Loader::block(unsigned b)
        obj.add_tracks(blk.get_tracks());
 }
 
+void Zone::Loader::direction_hint(unsigned b, Direction d)
+{
+       Block &blk = obj.layout.get_block(b);
+       const TrackSet &btracks = blk.get_tracks();
+       for(TrackSet::const_iterator i=btracks.begin(); i!=btracks.end(); ++i)
+               if(obj.check_validity(**i)==VALID)
+               {
+                       obj.set_direction_towards(**i, d);
+                       return;
+               }
+
+       throw invalid_argument("Zone::Loader::direction_hint");
+}
+
 } // namespace R2C2