603
608
// standard names:
604
609
// order: factory, attraction, direction, normal name
605
610
// prissi: first we try a factory name
606
slist_tpl<fabrik_t *>fabs;
607
if (self.is_bound()) {
608
// first factories (so with same distance, they have priority)
609
int this_distance = 999;
610
slist_iterator_tpl<fabrik_t*> fab_iter(get_fab_list());
612
// is there a translation for factory defined?
613
const char *fab_base_text = "%s factory %s %s";
614
const char *fab_base = translator::translate(fab_base_text,lang);
615
if( fab_base_text != fab_base ) {
616
slist_tpl<fabrik_t *>fabs;
617
if (self.is_bound()) {
618
// first factories (so with same distance, they have priority)
619
int this_distance = 999;
620
slist_iterator_tpl<fabrik_t*> fab_iter(get_fab_list());
621
while (fab_iter.next()) {
622
int distance = koord_distance(fab_iter.get_current()->get_pos().get_2d(), k);
623
if (distance < this_distance) {
624
fabs.insert(fab_iter.get_current());
625
distance = this_distance;
628
fabs.append(fab_iter.get_current());
633
// since the distance are presorted, we can just append for a good choice ...
634
for( int test=0; test<24; test++ ) {
635
fabrik_t *fab = fabrik_t::get_fab(welt,k+next_building[test]);
636
if(fab && fabs.is_contained(fab)) {
643
slist_iterator_tpl<fabrik_t*> fab_iter(fabs);
611
644
while (fab_iter.next()) {
612
int distance = koord_distance(fab_iter.get_current()->get_pos().get_2d(), k);
613
if (distance < this_distance) {
614
fabs.insert(fab_iter.get_current());
615
distance = this_distance;
618
fabs.append(fab_iter.get_current());
623
// since the distance are presorted, we can just append for a good choice ...
624
for( int test=0; test<24; test++ ) {
625
fabrik_t *fab = fabrik_t::get_fab(welt,k+next_building[test]);
626
if(fab && fabs.is_contained(fab)) {
633
const char *fab_base = translator::translate("%s factory %s %s",lang);
634
slist_iterator_tpl<fabrik_t*> fab_iter(fabs);
635
while (fab_iter.next()) {
637
sprintf(buf, fab_base, city_name, translator::translate(fab_iter.get_current()->get_besch()->get_name(),lang), stop );
638
if( !all_names.get(buf).is_bound() ) {
646
buf.printf( fab_base, city_name, fab_iter.get_current()->get_name(), stop );
647
if( !all_names.get(buf).is_bound() ) {
643
654
// no fabs or all names used up already
644
// check for other special building (townhall, monument, tourst attraction)
645
for (int i=0; i<24; i++) {
646
grund_t *gr = welt->lookup_kartenboden( next_building[i] + k);
647
if(gr==NULL || gr->get_typ()!=grund_t::fundament) {
651
// since closes coordinates are tested first, we do not need to not sort this
652
const char *building_name = NULL;
653
const gebaeude_t* gb = gr->find<gebaeude_t>();
655
// field may have foundations but no building
658
// now we have a building here
659
if (gb->is_monument()) {
660
building_name = translator::translate(gb->get_name(),lang);
662
else if (gb->ist_rathaus() ||
663
gb->get_tile()->get_besch()->get_utyp() == haus_besch_t::attraction_land || // land attraction
664
gb->get_tile()->get_besch()->get_utyp() == haus_besch_t::attraction_city) { // town attraction
665
building_name = make_single_line_string(translator::translate(gb->get_tile()->get_besch()->get_name(),lang), 2);
668
// normal town house => not suitable for naming
671
// now we have a name: try it
672
sprintf(buf, translator::translate("%s building %s %s",lang), city_name, building_name, stop );
673
if( !all_names.get(buf).is_bound() ) {
655
// is there a translation for buildings defined?
656
const char *building_base_text = "%s building %s %s";
657
const char *building_base = translator::translate(building_base_text,lang);
658
if( building_base_text != building_base ) {
659
// check for other special building (townhall, monument, tourst attraction)
660
for (int i=0; i<24; i++) {
661
grund_t *gr = welt->lookup_kartenboden( next_building[i] + k);
662
if(gr==NULL || gr->get_typ()!=grund_t::fundament) {
666
// since closes coordinates are tested first, we do not need to not sort this
667
const char *building_name = NULL;
668
const gebaeude_t* gb = gr->find<gebaeude_t>();
670
// field may have foundations but no building
673
// now we have a building here
674
if (gb->is_monument()) {
675
building_name = translator::translate(gb->get_name(),lang);
677
else if (gb->ist_rathaus() ||
678
gb->get_tile()->get_besch()->get_utyp() == haus_besch_t::attraction_land || // land attraction
679
gb->get_tile()->get_besch()->get_utyp() == haus_besch_t::attraction_city) { // town attraction
680
building_name = make_single_line_string(translator::translate(gb->get_tile()->get_besch()->get_name(),lang), 2);
683
// normal town house => not suitable for naming
686
// now we have a name: try it
687
buf.printf( building_base, city_name, building_name, stop );
688
if( !all_names.get(buf).is_bound() ) {
695
// if there are street names, use them
696
if( inside || suburb ) {
698
vector_tpl<char *> street_names( translator::get_street_name_list() );
699
while( !street_names.empty() ) {
700
const uint32 idx = simrand(street_names.get_count());
703
buf.printf( street_names[idx], city_name, stop );
704
if( !all_names.get(buf).is_bound() ) {
707
// esle: remove this entry ...
708
street_names.remove_at(idx);
678
713
// still all names taken => then try the normal naming scheme ...
679
714
char numbername[10];
681
716
strcpy( numbername, "0center" );
682
} else if (li_gr - 6 < k.x && re_gr + 6 > k.x && ob_gr - 6 < k.y && un_gr + 6 > k.y) {
683
718
// close to the city we use a different scheme, with suburbs
684
719
strcpy( numbername, "0suburb" );
1114
1114
INT_CHECK("simhalt.cc 612");
1116
1116
// now we add the schedule to the connection array
1117
uint8 stop_count = 0; // Measures the distance to "self".
1118
for( uint8 j=1; j<fpl->get_count(); j++ ) {
1120
halthandle_t halt = get_halt(welt, fpl->eintrag[(first_self_index+j)%fpl->get_count()].pos,owner);
1121
if( !halt.is_bound() ) {
1131
for( uint8 ctg=0; ctg<supported_catg_index.get_count(); ctg ++ ) {
1117
uint16 aggregate_weight = WEIGHT_WAIT;
1118
for( uint8 j=1; j<fpl->get_count(); ++j ) {
1120
halthandle_t current_halt = get_halt(welt, fpl->eintrag[(first_self_index+j)%fpl->get_count()].pos,owner);
1121
if( !current_halt.is_bound() ) {
1122
// ignore way points
1125
if( current_halt==self ) {
1126
// reset aggregate weight
1127
aggregate_weight = WEIGHT_WAIT;
1131
aggregate_weight += WEIGHT_HALT;
1133
for( uint8 ctg=0; ctg<supported_catg_index.get_count(); ++ctg ) {
1132
1134
const uint8 catg_index = supported_catg_index[ctg];
1133
if( halt->is_enabled(catg_index) ) {
1134
warenzielsorter_t wzs( halt, stop_count, catg_index );
1135
// might be a new halt to add
1136
if( !warenziele_by_stops.is_contained(wzs) ) {
1137
warenziele_by_stops.append(wzs);
1138
non_identical_schedules_flag[catg_index] = true;
1135
if( current_halt->is_enabled(catg_index) ) {
1136
// there is at least a reachable halt served by this schedule and supporting this goods category
1137
suitable_halt_found[catg_index] = true;
1139
// either add a new connection or update the weight of an existing connection where necessary
1140
connection_t *const existing_connection = connections[catg_index].insert_unique_ordered( connection_t( current_halt, aggregate_weight ), connection_t::compare );
1141
if( existing_connection && aggregate_weight<existing_connection->weight ) {
1142
existing_connection->weight = aggregate_weight;
1144
for( uint8 ctg=0; ctg<supported_catg_index.get_count(); ctg ++ ) {
1148
for( uint8 ctg=0; ctg<supported_catg_index.get_count(); ++ctg ) {
1145
1149
const uint8 catg_index = supported_catg_index[ctg];
1146
if( non_identical_schedules_flag[catg_index] ) {
1147
non_identical_schedules_flag[catg_index] = false;
1148
if( non_identical_schedules[catg_index] < 255 ) {
1149
// added additional stops => might be transfer stop
1150
non_identical_schedules[catg_index]++;
1150
if( suitable_halt_found[catg_index] ) {
1151
suitable_halt_found[catg_index] = false;
1152
if( serving_schedules[catg_index]<255 ) {
1153
serving_schedules[catg_index]++;
1154
1157
connections_searched += fpl->get_count();
1157
// now add them to warenziele ...
1158
uint32 processed_entries = 0;
1160
while( processed_entries<warenziele_by_stops.get_count() ) {
1161
for( uint32 i=processed_entries; i<warenziele_by_stops.get_count(); i++ ) {
1163
if( warenziele_by_stops[i].stops==stops ) {
1164
vector_tpl<halthandle_t> &wz_list = warenziele[ warenziele_by_stops[i].catg_index ];
1165
// this test is needed, since the same halt may be added earlier, since it came first in another schedule
1166
if( !wz_list.is_contained( warenziele_by_stops[i].halt ) ) {
1167
wz_list.append( warenziele_by_stops[i].halt );
1168
if( waren[ warenziele_by_stops[i].catg_index ] == NULL ) {
1169
// indicates that this can route those goods
1170
waren[ warenziele_by_stops[i].catg_index ] = new vector_tpl<ware_t>(0);
1173
// after processing, current entry becomes useless
1174
// --> overwrite it with an unprocessed entry where necessary
1175
if ( i != processed_entries ) {
1176
warenziele_by_stops[i] = warenziele_by_stops[processed_entries];
1178
++processed_entries;
1183
1159
return connections_searched;
1188
/* HNode is used for route search */
1164
* Data for route searching
1166
haltestelle_t::halt_data_t haltestelle_t::halt_data[65536];
1167
binary_heap_tpl<haltestelle_t::route_node_t> haltestelle_t::open_list;
1168
uint8 haltestelle_t::markers[65536];
1169
uint8 haltestelle_t::current_marker = 0;
1171
* Data for resumable route search
1173
halthandle_t haltestelle_t::last_search_origin;
1174
uint8 haltestelle_t::last_search_ware_catg_idx = 255;
1196
1176
* This routine tries to find a route for a good packet (ware)
1197
1177
* it will be called for
1209
1189
* if USE_ROUTE_SLIST_TPL is defined, the list template will be used.
1210
1190
* However, this is about 50% slower.
1212
* @author Hj. Malthaner/prissi/gerw
1192
* @author Hj. Malthaner/prissi/gerw/Knightly
1214
int haltestelle_t::suche_route( ware_t &ware, koord *next_to_ziel, const bool no_routing_over_overcrowding )
1194
int haltestelle_t::search_route( const halthandle_t *const start_halts, const uint16 start_halt_count, const bool no_routing_over_overcrowding, ware_t &ware, ware_t *const return_ware )
1216
const ware_besch_t * warentyp = ware.get_besch();
1217
const uint8 ware_catg_index = warentyp->get_catg_index();
1218
const koord ziel = ware.get_zielpos();
1196
const uint8 ware_catg_idx = ware.get_besch()->get_catg_index();
1220
1198
// since also the factory halt list is added to the ground, we can use just this ...
1221
const planquadrat_t *plan = welt->lookup(ziel);
1222
const halthandle_t *halt_list = plan->get_haltlist();
1199
const planquadrat_t *const plan = welt->lookup( ware.get_zielpos() );
1200
const halthandle_t *const halt_list = plan->get_haltlist();
1223
1201
// but we can only use a subset of these
1224
vector_tpl<halthandle_t> ziel_list(plan->get_haltlist_count());
1225
for( unsigned h=0; h<plan->get_haltlist_count(); h++ ) {
1202
static vector_tpl<halthandle_t> end_halts(16);
1204
for( uint32 h=0; h<plan->get_haltlist_count(); ++h ) {
1226
1205
halthandle_t halt = halt_list[h];
1227
if( halt->is_enabled(warentyp) ) {
1228
ziel_list.append(halt);
1231
//DBG_MESSAGE("suche_route()","halt %s near (%i,%i) does not accept %s!",halt->get_name(),ziel.x,ziel.y,warentyp->get_name());
1206
if( halt.is_bound() && halt->is_enabled(ware_catg_idx) ) {
1207
// check if this is present in the list of start halts
1208
for( uint16 s=0; s<start_halt_count; ++s ) {
1209
if( halt==start_halts[s] ) {
1210
// destination halt is also a start halt -> within walking distance
1211
ware.set_ziel( start_halts[s] );
1212
ware.set_zwischenziel( halthandle_t() );
1214
return_ware->set_ziel( start_halts[s] );
1215
return_ware->set_zwischenziel( halthandle_t() );
1220
end_halts.append(halt);
1235
if( ziel_list.empty() ) {
1236
//no target station found
1224
if( end_halts.empty() ) {
1225
// no end halt found
1237
1226
ware.set_ziel( halthandle_t() );
1238
1227
ware.set_zwischenziel( halthandle_t() );
1239
// printf("keine route zu %d,%d nach %d steps\n", ziel.x, ziel.y, step);
1240
if( next_to_ziel != NULL ) {
1241
*next_to_ziel = koord::invalid;
1229
return_ware->set_ziel( halthandle_t() );
1230
return_ware->set_zwischenziel( halthandle_t() );
1243
1232
return NO_ROUTE;
1246
// check, if the shortest connection is not right to us ...
1247
if( ziel_list.is_contained(self) ) {
1248
ware.set_ziel( self );
1249
ware.set_zwischenziel( halthandle_t() );
1250
if( next_to_ziel != NULL ) {
1251
*next_to_ziel = koord::invalid;
1256
// set curretn marker
1258
if( current_mark==0 ) {
1234
// invalidate search history
1235
last_search_origin = halthandle_t();
1237
// set current marker
1239
if( current_marker==0 ) {
1259
1240
MEMZERON(markers, halthandle_t::get_size());
1263
// single threading makes some things easier
1264
static HNode nodes[32768];
1266
// die Berechnung erfolgt durch eine Breitensuche fuer Graphen
1267
// Warteschlange fuer Breitensuche
1268
const uint16 max_transfers = welt->get_einstellungen()->get_max_transfers();
1269
#ifdef USE_ROUTE_SLIST_TPL
1270
slist_tpl<HNode *> queue;
1272
// we need just need to know the current bottom of the list with respect to the nodes array
1273
uint32 progress_pointer = 0;
1275
uint32 allocation_pointer = 1;
1276
HNode *current_node;
1279
nodes[0].halt = self;
1280
nodes[0].link = NULL;
1283
#ifdef USE_ROUTE_SLIST_TPL
1284
queue.insert( &nodes[0] ); // init queue mit erstem feld
1286
markers[ self.get_id() ] = current_mark;
1288
const uint32 max_hops = welt->get_einstellungen()->get_max_hops();
1241
current_marker = 1u;
1244
// initialisations for end halts => save some checking inside search loop
1245
for( uint32 e=0; e<end_halts.get_count(); ++e ) {
1246
const uint16 halt_id = end_halts[e].get_id();
1247
halt_data[ halt_id ].best_weight = 65535u;
1248
halt_data[ halt_id ].destination = 1u;
1249
markers[ halt_id ] = current_marker;
1252
uint16 const max_transfers = welt->get_settings().get_max_transfers();
1253
uint16 const max_hops = welt->get_settings().get_max_hops();
1254
uint16 allocation_pointer = 0;
1255
uint16 best_destination_weight = 65535u; // best weight among all destinations
1259
// initialise the origin node(s)
1260
for( ; allocation_pointer<start_halt_count; ++allocation_pointer ) {
1261
halthandle_t start_halt = start_halts[allocation_pointer];
1263
open_list.insert( route_node_t(start_halt, 0) );
1265
halt_data_t & start_data = halt_data[ start_halt.get_id() ];
1266
start_data.best_weight = 65535u;
1267
start_data.destination = 0;
1268
start_data.depth = 0;
1269
start_data.transfer = halthandle_t();
1271
markers[ start_halt.get_id() ] = current_marker;
1289
1274
// here the normal routing with overcrowded stops is done
1291
#ifdef USE_ROUTE_SLIST_TPL
1292
tmp = queue.remove_first();
1294
current_node = &nodes[progress_pointer++];
1297
// Hajo: check for max transfers -> don't add more stations
1298
// to queue if the limit is reached
1299
if( current_node->depth < max_transfers ) {
1300
const vector_tpl<halthandle_t> &wz = current_node->halt->warenziele[ware_catg_index];
1301
for( uint32 i=0; i<wz.get_count(); i++ ) {
1303
// since these are precalculated, they should be always pointing to a valid ground
1304
// (if not, we were just under construction, and will be fine after 16 steps)
1305
const halthandle_t &reachable_halt = wz[i];
1306
if( markers[ reachable_halt.get_id() ]<current_mark && reachable_halt.is_bound() ) {
1308
// betretene Haltestellen markieren
1309
markers[ reachable_halt.get_id() ] = current_mark;
1311
// Knightly : Only transfer halts and destination halt are added to the HNode array
1312
if( ziel_list.is_contained(reachable_halt) ) {
1313
// Case : Destination found
1314
new_node = &nodes[allocation_pointer++];
1315
new_node->halt = reachable_halt;
1316
// Knightly : node depth will not be used afterwards, so no need to assign a value
1317
// new_node->depth = current_node->depth + 1;
1318
new_node->link = current_node;
1319
#ifdef USE_ROUTE_SLIST_TPL
1320
queue.append( new_node );
1322
current_node = new_node;
1325
else if( reachable_halt->non_identical_schedules[ware_catg_index] > 1 && allocation_pointer < 32000u ) {
1326
// Case : Transfer halt
1327
new_node = &nodes[allocation_pointer++];
1328
new_node->halt = reachable_halt;
1329
new_node->depth = current_node->depth + 1;
1330
new_node->link = current_node;
1331
#ifdef USE_ROUTE_SLIST_TPL
1332
queue.append( new_node );
1339
#ifdef USE_ROUTE_SLIST_TPL
1340
} while (!queue.empty() && progress_pointer < max_hops);
1342
} while( progress_pointer < allocation_pointer && progress_pointer < max_hops );
1276
route_node_t current_node = open_list.pop();
1277
// do not use aggregate_weight as it is _not_ the weight of the current_node
1278
// there might be a heuristic weight added
1280
const uint16 current_halt_id = current_node.halt.get_id();
1281
halt_data_t & current_halt_data = halt_data[ current_halt_id ];
1283
if( current_halt_data.destination ) {
1284
// destination found
1285
ware.set_ziel( current_node.halt );
1286
assert(current_halt_data.transfer.get_id() != 0);
1288
// next transfer for the reverse route
1289
// if the end halt and its connections contain more than one transfer halt then
1290
// the transfer halt may not be the last transfer of the forward route
1291
// (the rerouting will happen in haltestelle_t::hole_ab)
1292
return_ware->set_zwischenziel(current_halt_data.transfer);
1293
const vector_tpl<connection_t> &conns = current_node.halt->connections[ware_catg_idx];
1294
// count the connected transfer halts (including end halt)
1295
uint8 t = current_node.halt->serving_schedules[ware_catg_idx] > 1;
1296
for( uint32 i=0; t<=1 && i<conns.get_count(); ++i ) {
1297
t += conns[i].halt.is_bound() && conns[i].halt->serving_schedules[ware_catg_idx] > 1;
1299
return_ware->set_zwischenziel( t<=1 ? current_halt_data.transfer : halthandle_t());
1301
// find the next transfer
1302
bool via_overcrowded_transfer = false;
1303
halthandle_t transfer_halt = current_node.halt;
1304
if( no_routing_over_overcrowding ) {
1305
while( halt_data[ transfer_halt.get_id() ].depth > 1 ) {
1306
transfer_halt = halt_data[ transfer_halt.get_id() ].transfer;
1307
if( !via_overcrowded_transfer && transfer_halt->is_overcrowded(ware_catg_idx) ) {
1308
via_overcrowded_transfer = true;
1313
while( halt_data[ transfer_halt.get_id() ].depth > 1 ) {
1314
transfer_halt = halt_data[ transfer_halt.get_id() ].transfer;
1317
ware.set_zwischenziel(transfer_halt);
1319
// return ware's destination halt is the start halt of the forward trip
1320
assert( halt_data[ transfer_halt.get_id() ].transfer.get_id() );
1321
return_ware->set_ziel( halt_data[ transfer_halt.get_id() ].transfer );
1323
return via_overcrowded_transfer ? ROUTE_OVERCROWDED : ROUTE_OK;
1326
// check if the current halt is already in closed list
1327
if( current_halt_data.best_weight==0 ) {
1328
// shortest path to the current halt has already been found earlier
1332
if( current_halt_data.depth > max_transfers ) {
1333
// maximum transfer limit is reached -> do not add reachable halts to open list
1337
const vector_tpl<connection_t> &conns = current_node.halt->connections[ware_catg_idx];
1338
for( uint32 i=0; i<conns.get_count(); ++i ) {
1340
// since these are precalculated, they should be always pointing to a valid ground
1341
// (if not, we were just under construction, and will be fine after 16 steps)
1342
const connection_t ¤t_conn = conns[i];
1344
const uint16 reachable_halt_id = current_conn.halt.get_id();
1346
if( markers[ reachable_halt_id ]!=current_marker ) {
1347
// Case : not processed before
1349
// indicate that this halt has been processed
1350
markers[ reachable_halt_id ] = current_marker;
1352
if( current_conn.halt.is_bound() && current_conn.halt->serving_schedules[ware_catg_idx]>1u && allocation_pointer<max_hops ) {
1353
// Case : transfer halt
1354
const uint16 total_weight = current_halt_data.best_weight + current_conn.weight;
1356
if( total_weight < best_destination_weight ) {
1358
halt_data[ reachable_halt_id ].best_weight = total_weight;
1359
halt_data[ reachable_halt_id ].destination = 0;
1360
halt_data[ reachable_halt_id ].depth = current_halt_data.depth + 1u;
1361
halt_data[ reachable_halt_id ].transfer = current_node.halt;
1363
allocation_pointer++;
1364
// as the next halt is not a destination add WEIGHT_MIN
1365
open_list.insert( route_node_t(current_conn.halt, total_weight + WEIGHT_MIN) );
1368
// Case: non-optimal transfer halt -> put in closed list
1369
halt_data[ reachable_halt_id ].best_weight = 0;
1373
// Case: halt is removed / no transfer halt -> put in closed list
1374
halt_data[ reachable_halt_id ].best_weight = 0;
1377
} // if not processed before
1378
else if( halt_data[ reachable_halt_id ].best_weight!=0 ) {
1379
// Case : processed before but not in closed list : that is, in open list
1380
// --> can only be destination halt or transfer halt
1382
uint16 total_weight = current_halt_data.best_weight + current_conn.weight;
1384
if( total_weight<halt_data[ reachable_halt_id ].best_weight && total_weight<best_destination_weight && allocation_pointer<max_hops ) {
1385
// new weight is lower than lowest weight --> create new node and update halt data
1387
halt_data[ reachable_halt_id ].best_weight = total_weight;
1388
// no need to update destination, as halt nature (as destination or transfer) will not change
1389
halt_data[ reachable_halt_id ].depth = current_halt_data.depth + 1u;
1390
halt_data[ reachable_halt_id ].transfer = current_node.halt;
1392
if (halt_data[ reachable_halt_id ].destination) {
1393
best_destination_weight = total_weight;
1396
// as the next halt is not a destination add WEIGHT_MIN
1397
total_weight += WEIGHT_MIN;
1400
allocation_pointer++;
1401
open_list.insert( route_node_t(current_conn.halt, total_weight) );
1403
} // else if not in closed list
1404
} // for each connection entry
1406
// indicate that the current halt is in closed list
1407
current_halt_data.best_weight = 0;
1409
} while( !open_list.empty() );
1345
1411
// if the loop ends, nothing was found
1346
current_node = NULL;
1352
ware.set_ziel( current_node->halt );
1354
assert(current_node->link != NULL);
1356
if(next_to_ziel!=NULL) {
1357
// for reverse route the next hop
1358
*next_to_ziel = current_node->link->halt->get_basis_pos();
1360
// find the intermediate stops
1361
while(current_node->link->link) {
1362
current_node = current_node->link;
1363
if( no_routing_over_overcrowding && current_node->halt->is_overcrowded(ware_catg_index) ) {
1364
return ROUTE_OVERCROWDED;
1367
ware.set_zwischenziel(current_node->halt);
1371
// no suitable target station found
1372
ware.set_ziel( halthandle_t() );
1373
ware.set_zwischenziel( halthandle_t() );
1374
if(next_to_ziel!=NULL) {
1375
*next_to_ziel = koord::invalid;
1412
ware.set_ziel( halthandle_t() );
1413
ware.set_zwischenziel( halthandle_t() );
1415
return_ware->set_ziel( halthandle_t() );
1416
return_ware->set_zwischenziel( halthandle_t() );
1422
void haltestelle_t::search_route_resumable( ware_t &ware )
1424
const uint8 ware_catg_idx = ware.get_besch()->get_catg_index();
1426
// continue search if start halt and good category did not change
1427
const bool resume_search = last_search_origin == self && ware_catg_idx == last_search_ware_catg_idx;
1429
if (!resume_search) {
1430
last_search_origin = self;
1431
last_search_ware_catg_idx = ware_catg_idx;
1432
// set current marker
1434
if( current_marker==0 ) {
1435
MEMZERON(markers, halthandle_t::get_size());
1436
current_marker = 1u;
1440
// remember destination nodes, to reset them before returning
1441
static vector_tpl<uint16> dest_indices(16);
1442
dest_indices.clear();
1444
uint16 best_destination_weight = 65535u;
1446
// reset next transfer and destination halt to null -> if they remain null after search, no route can be found
1447
ware.set_ziel( halthandle_t() );
1448
ware.set_zwischenziel( halthandle_t() );
1449
// find suitable destination halts for the ware packet's target position
1450
const planquadrat_t *const plan = welt->lookup( ware.get_zielpos() );
1451
const halthandle_t *const halt_list = plan->get_haltlist();
1453
// check halt list for presence of current halt
1454
for( uint8 h = 0; h<plan->get_haltlist_count(); ++h ) {
1455
if (halt_list[h] == self) {
1456
// a destination halt is the same as the current halt -> no route searching is necessary
1457
ware.set_ziel( self );
1462
// check explored connection
1463
if (resume_search) {
1464
for( uint8 h=0; h<plan->get_haltlist_count(); ++h ) {
1465
const halthandle_t halt = halt_list[h];
1466
if (markers[ halt.get_id() ]==current_marker && halt_data[ halt.get_id() ].best_weight < best_destination_weight && halt.is_bound()) {
1467
best_destination_weight = halt_data[ halt.get_id() ].best_weight;
1468
ware.set_ziel( halt );
1469
ware.set_zwischenziel( halt_data[ halt.get_id() ].transfer );
1472
// for all halts with halt_data.weight < explored_weight one of the best routes is found
1473
const uint16 explored_weight = open_list.empty() ? 65535u : open_list.front().aggregate_weight;
1475
if (best_destination_weight <= explored_weight) {
1476
// we explored best route to this destination in last run
1477
// (any other not yet explored connection will have larger weight)
1478
// no need to search route for this ware
1482
// find suitable destination halt(s), if any
1483
for( uint8 h=0; h<plan->get_haltlist_count(); ++h ) {
1484
const halthandle_t halt = halt_list[h];
1485
if( halt.is_bound() && halt->is_enabled(ware_catg_idx) ) {
1486
// initialisations for destination halts => save some checking inside search loop
1487
if( markers[ halt.get_id() ]!=current_marker ) {
1488
// first time -> initialise marker and all halt data
1489
markers[ halt.get_id() ] = current_marker;
1490
halt_data[ halt.get_id() ].best_weight = 65535u;
1491
halt_data[ halt.get_id() ].destination = true;
1494
// initialised before -> only update destination bit set
1495
halt_data[ halt.get_id() ].destination = true;
1497
dest_indices.append(halt.get_id());
1501
if( dest_indices.empty() ) {
1502
// no destination halt found or current halt is the same as (all) the destination halt(s)
1506
uint16 const max_transfers = welt->get_settings().get_max_transfers();
1507
uint16 const max_hops = welt->get_settings().get_max_hops();
1509
static uint16 allocation_pointer;
1510
if (!resume_search) {
1513
// initialise the origin node
1514
allocation_pointer = 1u;
1515
open_list.insert( route_node_t(self, 0) );
1517
halt_data_t & start_data = halt_data[ self.get_id() ];
1518
start_data.best_weight = 0;
1519
start_data.destination = 0;
1520
start_data.depth = 0;
1521
start_data.transfer = halthandle_t();
1523
markers[ self.get_id() ] = current_marker;
1526
while( !open_list.empty() ) {
1528
if (best_destination_weight <= open_list.front().aggregate_weight) {
1529
// best route to destination found already
1533
route_node_t current_node = open_list.pop();
1535
const uint16 current_halt_id = current_node.halt.get_id();
1536
const uint16 current_weight = current_node.aggregate_weight;
1537
halt_data_t & current_halt_data = halt_data[ current_halt_id ];
1539
// check if the current halt is already in closed list (or removed)
1540
if( !current_node.halt.is_bound() ) {
1543
else if( current_halt_data.best_weight < current_weight) {
1544
// shortest path to the current halt has already been found earlier
1545
// assert(markers[ current_halt_id ]==current_marker);
1549
// no need to update weight, as it is already the right one
1550
// assert(current_halt_data.best_weight == current_weight);
1553
if( current_halt_data.destination ) {
1554
// destination found
1555
ware.set_ziel( current_node.halt );
1556
ware.set_zwischenziel( current_halt_data.transfer );
1557
// update best_destination_weight to leave loop due to first check above
1558
best_destination_weight = current_weight;
1559
// if this destination halt is not a transfer halt -> do not proceed to process its reachable halt(s)
1560
if( current_node.halt->serving_schedules[ware_catg_idx]<=1u ) {
1565
if( current_halt_data.depth > max_transfers ) {
1566
// maximum transfer limit is reached -> do not add reachable halts to open list
1570
const vector_tpl<connection_t> &conns = current_node.halt->connections[ware_catg_idx];
1571
for( uint32 i=0; i<conns.get_count(); ++i ) {
1573
const connection_t ¤t_conn = conns[i];
1575
const uint16 reachable_halt_id = current_conn.halt.get_id();
1577
const uint16 total_weight = current_weight + current_conn.weight;
1579
if( !current_conn.halt.is_bound() ) {
1580
// Case: halt removed -> make sure we never visit it again
1581
markers[ reachable_halt_id ] = current_marker;
1582
halt_data[ reachable_halt_id ].best_weight = 0;
1584
else if( markers[ reachable_halt_id ]!=current_marker ) {
1585
// Case : not processed before and not destination
1587
// indicate that this halt has been processed
1588
markers[ reachable_halt_id ] = current_marker;
1591
halt_data[ reachable_halt_id ].best_weight = total_weight;
1592
halt_data[ reachable_halt_id ].destination = false; // reset necessary if this was set by search_route
1593
halt_data[ reachable_halt_id ].depth = current_halt_data.depth + 1u;
1594
halt_data[ reachable_halt_id ].transfer = current_halt_data.transfer.get_id() ? current_halt_data.transfer : current_conn.halt;
1596
if( current_conn.halt->serving_schedules[ware_catg_idx]>1u && allocation_pointer<max_hops ) {
1597
// Case : transfer halt
1598
allocation_pointer++;
1599
open_list.insert( route_node_t(current_conn.halt, total_weight) );
1601
} // if not processed before
1603
// Case : processed before (or destination halt)
1604
// -> need to check whether we can reach it with smaller weight
1605
if( total_weight<halt_data[ reachable_halt_id ].best_weight ) {
1606
// new weight is lower than lowest weight --> update halt data
1608
halt_data[ reachable_halt_id ].best_weight = total_weight;
1609
halt_data[ reachable_halt_id ].transfer = current_halt_data.transfer.get_id() ? current_halt_data.transfer : current_conn.halt;
1611
// for transfer/destination nodes create new node
1612
if ( (halt_data[ reachable_halt_id ].destination || current_conn.halt->serving_schedules[ware_catg_idx] > 1u) && allocation_pointer<max_hops ) {
1613
halt_data[ reachable_halt_id ].depth = current_halt_data.depth + 1u;
1614
allocation_pointer++;
1615
open_list.insert( route_node_t(current_conn.halt, total_weight) );
1618
} // else processed before
1619
} // for each connection entry
1622
// clear destinations since we may want to do another search with the same current_marker
1623
for(uint32 i=0; i<dest_indices.get_count(); i++) {
1624
halt_data[ dest_indices[i] ].destination = false;
1625
if( halt_data[ dest_indices[i] ].best_weight == 65535u) {
1626
// not processed -> reset marker
1627
markers[ dest_indices[i] ] --;