+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;
+}
+