X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibr2c2%2Ftrain.cpp;h=eb5724b762a9777494ec71ec23acccf8bf81a787;hb=66c2c7ca5a4bd369293959bc211b040834343381;hp=782da37cc305935ff5b5186f0151f7dd432a5cef;hpb=ce29d0ccf89840c9581314301de0ea2b5b261c43;p=r2c2.git diff --git a/source/libr2c2/train.cpp b/source/libr2c2/train.cpp index 782da37..eb5724b 100644 --- a/source/libr2c2/train.cpp +++ b/source/libr2c2/train.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -63,7 +64,7 @@ Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p): overshoot_dist(false) { if(!loco_type.is_locomotive()) - throw InvalidParameterValue("Initial vehicle must be a locomotive"); + throw invalid_argument("Train::Train"); unsigned speed_steps = layout.get_driver().get_protocol_speed_steps(protocol); if(speed_steps) @@ -125,9 +126,9 @@ void Train::add_vehicle(const VehicleType &vt) void Train::remove_vehicle(unsigned i) { if(i>=vehicles.size()) - throw InvalidParameterValue("Vehicle index out of range"); + throw out_of_range("Train::remove_vehicle"); if(i==0) - throw InvalidParameterValue("Can't remove the locomotive"); + throw logic_error("can't remove locomotive"); delete vehicles[i]; vehicles.erase(vehicles.begin()+i); if(i=vehicles.size()) - throw InvalidParameterValue("Vehicle index out of range"); + throw out_of_range("Train::get_vehicle"); return *vehicles[i]; } const Vehicle &Train::get_vehicle(unsigned i) const { if(i>=vehicles.size()) - throw InvalidParameterValue("Vehicle index out of range"); + throw out_of_range("Train::get_vehicle"); return *vehicles[i]; } @@ -163,7 +164,7 @@ void Train::set_active(bool a) if(a==active) return; if(!a && controller->get_speed()) - throw InvalidState("Can't deactivate while moving"); + throw logic_error("moving"); active = a; if(active) @@ -178,7 +179,7 @@ void Train::set_active(bool a) void Train::set_function(unsigned func, bool state) { if(!loco_type.get_functions().count(func)) - throw InvalidParameterValue("Invalid function"); + throw invalid_argument("Train::set_function"); layout.get_driver().set_loco_function(address, func, state); } @@ -317,122 +318,30 @@ bool Train::go_to(const Zone &to) return set_route(route); } -bool Train::divert(Track &from) -{ - if(!from.get_turnout_id()) - throw InvalidParameterValue("Can't divert from a non-turnout"); - if(routes.empty()) - return false; - - unsigned path = 0; - unsigned entry = 0; - list::iterator route = routes.begin(); - - // Follow our routes to find out where we're entering the turnout - for(TrackLoopIter track = blocks.front().track_iter();;) - { - if(!advance_route(route, *track)) - return false; - - if(&*track==&from) - { - Block &block = track->get_block(); - if(block.get_train()==this && !free_block(block)) - return false; - - int route_path = route->route->get_turnout(from.get_turnout_id()); - - // Check that more than one path is available - unsigned ep_paths = track.endpoint().paths; - if(!(ep_paths&(ep_paths-1))) - return false; - - // Choose some other path - for(int i=0; ep_paths>>i; ++i) - if((ep_paths&(1<route->get_path(*track)); - - if(!track || track.looped()) - return false; - } - - TrackIter track = TrackIter(&from, entry).next(path); - if(!track) - return false; - - set tracks; - for(list::iterator i=routes.begin(); i!=routes.end(); ++i) - tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end()); - RefPtr diversion = Route::find(track, tracks); - if(!diversion) - return false; - - diversion->set_name("Diversion"); - diversion->add_track(from); - diversion->set_turnout(from.get_turnout_id(), path); - - if(!is_valid_diversion(*diversion, TrackIter(&from, entry))) - return false; - - // Follow the diversion route until we get back to the original route - list::iterator end = routes.end(); - while(1) - { - for(list::iterator i=route; (end==routes.end() && i!=routes.end()); ++i) - if(i->route->has_track(*track)) - end = i; - - if(end!=routes.end()) - break; - else if(!diversion->has_track(*track)) - throw LogicError("Pathfinder returned a bad route"); - - track = track.next(diversion->get_path(*track)); - } - - if(route==end) - // We are rejoining the same route we diverted from, duplicate it - routes.insert(end, *route); - else - { - ++route; - routes.erase(route, end); - } - routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id())); - - return true; -} - const Route *Train::get_route() const { if(routes.empty()) return 0; - return routes.front().route; + return routes.front(); } void Train::place(Block &block, unsigned entry) { if(controller->get_speed()) - throw InvalidState("Must be stopped before placing"); + throw logic_error("moving"); release_blocks(); set_active(false); accurate_position = false; + blocks.push_back(BlockIter(&block, entry)); if(!block.reserve(this)) + { + blocks.pop_back(); return; + } - blocks.push_back(BlockIter(&block, entry)); if(reverse) { TrackIter track = BlockIter(&block, entry).reverse().track_iter(); @@ -448,7 +357,7 @@ void Train::place(Block &block, unsigned entry) void Train::unplace() { if(controller->get_speed()) - throw InvalidState("Must be stopped before unplacing"); + throw logic_error("moving"); release_blocks(); @@ -541,7 +450,7 @@ void Train::free_noncritical_blocks() } } -int Train::get_entry_to_block(Block &block) const +int Train::get_entry_to_block(const Block &block) const { for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) if(i->block()==&block) @@ -647,8 +556,9 @@ void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt) if(dist>10*layout.get_catalogue().get_scale()) { - blocks.front()->reserve(0); + Block &block = *blocks.front(); blocks.pop_front(); + block.reserve(0); } } } @@ -685,10 +595,10 @@ void Train::save(list &st) const if(!routes.empty()) { - list::const_iterator i = routes.begin(); - for(; (i!=routes.end() && i->route->is_temporary()); ++i) ; + list::const_iterator i = routes.begin(); + for(; (i!=routes.end() && (*i)->is_temporary()); ++i) ; if(i!=routes.end()) - st.push_back((DataFile::Statement("route"), i->route->get_name())); + st.push_back((DataFile::Statement("route"), (*i)->get_name())); } // XXX Need more generic way of saving AI state @@ -790,13 +700,13 @@ void Train::block_state_changed(Block &block, Block::State state) // Check if we've reached the next route if(routes.size()>1) { - const Route &route = *(++routes.begin())->route; + const Route &route = **(++routes.begin()); for(BlockList::iterator j=cur_blocks_end; j!=end; ++j) if(route.has_track(*j->track_iter())) { routes.pop_front(); // XXX Exceptions? - signal_route_changed.emit(routes.front().route); + signal_route_changed.emit(routes.front()); break; } } @@ -881,7 +791,7 @@ void Train::reserve_more() dist += (*i)->get_path_length(i->entry()); } - list::iterator cur_route = routes.begin(); + list::iterator cur_route = routes.begin(); advance_route(cur_route, *start.track_iter()); float approach_margin = 50*layout.get_catalogue().get_scale(); @@ -889,8 +799,6 @@ void Train::reserve_more() BlockIter block = start; list::iterator good_end = blocks.end(); - Track *divert_track = 0; - bool try_divert = false; Train *blocking_train = 0; BlockList contested_blocks; @@ -899,7 +807,7 @@ void Train::reserve_more() while(1) { BlockIter last = block; - block = block.next(cur_route!=routes.end() ? cur_route->route : 0); + block = block.next(cur_route!=routes.end() ? *cur_route : 0); if(!block || block->get_endpoints().size()<2) { if(!blocking_train) @@ -955,7 +863,6 @@ void Train::reserve_more() { yield_to(*blocking_train); pending_block = contested_blocks.front().block(); - try_divert = divert_track; break; } } @@ -966,9 +873,11 @@ void Train::reserve_more() } } + blocks.push_back(block); bool reserved = block->reserve(this); if(!reserved) { + blocks.pop_back(); /* We've found another train. If it wants to exit the block from the same endpoint we're trying to enter from or the other way around, treat it as coming towards us. Otherwise treat it as going in the @@ -976,7 +885,7 @@ void Train::reserve_more() Train *other_train = block->get_train(); int other_entry = other_train->get_entry_to_block(*block); if(other_entry<0) - throw LogicError("Block reservation inconsistency"); + throw logic_error("block reservation inconsistency"); unsigned exit = block.reverse().entry(); unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry(); @@ -999,7 +908,11 @@ void Train::reserve_more() /* Ask a lesser priority train going to the same direction to free the block for us */ if(other_train->free_block(*block)) - reserved = block->reserve(this); + { + blocks.push_back(block); + if(!(reserved = block->reserve(this))) + blocks.pop_back(); + } } else if(other_train!=yielding_to && (other_priois_active())) - // We are blocked, but there's a diversion possibility - try_divert = true; if(!reserved) { @@ -1021,22 +931,9 @@ void Train::reserve_more() } } - if(block->get_turnout_id()) - { - const TrackType::Endpoint &track_ep = track.endpoint(); - bool multiple_paths = (track_ep.paths&(track_ep.paths-1)); - - if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id()) - /* There's multiple paths to be taken and we are on a route - take - note of the diversion possibility */ - divert_track = &*track; - } - if(!contested_blocks.empty() && contested_blocks.front()==block) contested_blocks.pop_front(); - blocks.push_back(block); - if(cur_blocks_end==blocks.end()) --cur_blocks_end; if(clear_blocks_end==blocks.end()) @@ -1062,9 +959,6 @@ void Train::reserve_more() // Make any sensorless blocks at the beginning immediately current while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id()) ++cur_blocks_end; - - if(try_divert && divert(*divert_track)) - reserve_more(); } void Train::check_turnout_paths(bool set) @@ -1104,6 +998,8 @@ void Train::check_turnout_paths(bool set) if(i==clear_blocks_end) ++clear_blocks_end; + if(i==cur_blocks_end && !(*i)->get_sensor_id()) + ++cur_blocks_end; } } @@ -1193,18 +1089,13 @@ void Train::reverse_blocks(BlockList &blks) const *i = i->reverse(); } -bool Train::advance_route(list::iterator &iter, Track &track) +bool Train::advance_route(list::iterator &iter, Track &track) { - while(iter!=routes.end() && !iter->route->has_track(track)) + while(iter!=routes.end() && !(*iter)->has_track(track)) ++iter; if(iter==routes.end()) return false; - list::iterator next = iter; - ++next; - if(next!=routes.end() && next->diversion && next->route->has_track(track)) - iter = next; - return true; } @@ -1231,64 +1122,9 @@ Route *Train::create_lead_route(Route *lead, const Route *target) return lead; } -bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from) -{ - float diversion_len = 0; - TrackLoopIter track1 = from; - while(diversion.has_track(*track1)) - { - unsigned path = diversion.get_path(*track1); - diversion_len += track1->get_type().get_path_length(path); - - track1 = track1.next(path); - - if(!track1 || track1.looped()) - return false; - } - - list::iterator route = routes.begin(); - if(!advance_route(route, *from)) - return false; - - float route_len = 0; - TrackLoopIter track2 = from; - while(1) - { - unsigned path = route->route->get_path(*track2); - route_len += track2->get_type().get_path_length(path); - - bool ok = (track2!=from && diversion.has_track(*track2)); - - track2 = track2.next(path); - if(!track2) - return false; - - if(ok) - break; - - if(track2.looped()) - return false; - - if(!advance_route(route, *track2)) - return false; - } - - // Must end up at the same place through both routes - if(track2!=track1) - return false; - - return diversion_len(t), + DataFile::ObjectLoader(t), prev_block(0), blocks_valid(true) { @@ -1322,7 +1158,7 @@ void Train::Loader::block(unsigned id) { blk = &obj.layout.get_block(id); } - catch(const KeyError &) + catch(const key_error &) { blocks_valid = false; return; @@ -1334,8 +1170,8 @@ void Train::Loader::block(unsigned id) if(entry<0) entry = 0; - blk->reserve(&obj); obj.blocks.push_back(BlockIter(blk, entry)); + blk->reserve(&obj); if(blk->get_sensor_id()) obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true); @@ -1349,7 +1185,7 @@ void Train::Loader::block_hint(unsigned id) { prev_block = &obj.layout.get_block(id); } - catch(const KeyError &) + catch(const key_error &) { blocks_valid = false; }