home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
linuxmafia.com 2016
/
linuxmafia.com.tar
/
linuxmafia.com
/
pub
/
palmos
/
bart-1.3b2.tar.gz
/
bart-1.3b2.tar
/
bart-1.3b2
/
README.src
< prev
next >
Wrap
Text File
|
2000-03-12
|
12KB
|
243 lines
This file is intended for people interested in porting this code for
use with other transit systems. To do so requires knowledge of both C
and Perl, but should not be too difficult if you've got that. At a
minimum, a port will require a small amounts of modification to the C
code, and a fair amount of modification to the Perl code. I've tried
to keep most transit system and schedule-specific data in the pdb file
so that the C code is fairly general and can serve as a base for
others' efforts.
Changes vs. Version 1.21
------------------------
- user interface enhancements mentioned in README
- renamed itineraries to routes, which better describes what they
are
- time is now updated when the device is powered on, eliminating
the need for TIME_UPDATE_INTERVAL. this should save a small
amount of power.
- removed preferences form, but left preferences form code intact
and #if 0'd out.
- DB_ID is now uniquely defined in bartdata.h, written by
make-pdb-file
- moved some initialization code from MainFormInit() to
StartApplication(), revised locking/unlocking of StationNameArray
to minimize time holding the handle locked
Changes vs. Version 1.01
------------------------
- user visible changes: see the README file
- completely rewrote the code that finds train times; it is now
much faster, cleaner, more predictable in its running time, and
(IMHO) simpler and easier to understand.
- rewrote the MergeTimes function
- changed TimeInfoType struct to array of TripInfoType, which is a
bit more manageable
- got rid of yucky (Byte)-1's and replaced with symbolic constants
- added a LineDataCache struct to cache pointers frequently needed
by the train time finding code
- added TUNING #define; if you set this to 1 you can easily time
sections of the code, run alternate implementations of parts of
the code, and display results
- increased MAX_TRIPS from 5 to 8 (it's only slightly slower, but
gives better results)
- now record two station indices for each line in the route,
instead of a station number; this way we don't have to search for
the station indices each time we need them. this should also
make support easier for stations appearing multiple times on a
single line
- got rid of duplication of time printing functionality
- database format changes: added "time necessary to make transfer"
field for each transfer, added database creation date to general
info record
- make-pdb-file: now constructs the pdb file in memory by printing
everything to buffers, obviating the need for a temp file; also
got rid of unused line-abbrevs file
- there is now a single unique version string in bart.prc which is
propagated everywhere else it is needed (including the "About"
form)
- added much inline documentation
- other changes I've probably forgotten...
How the code works
------------------
Initialization:
On starting, the application reads from the database the schedule
category names (e.g. Weekday, Saturday, Sunday), the station names,
prior user interface settings, and other miscellaneous info that is
needed for the user interface. In the main form initialization
function the user interface is actually set up.
Other "Front End" Code:
The remainder of the bart.c file deals with the necessary manipulation
of the user interface, with the exception of the ResultsFormInit and
ResultsFormUnInit functions. ResultsFormInit sets up the results form
and calls functions to set up the lineInfo array for the lines in the
desired schedule category. It also finds the fare and sets the fare
label, and calls the FindTrips function, which actually finds the
desired trips. ResultsFormUnInit undoes the work of ResultsFormInit
by deallocating memory and unlocking handles.
"Back End" Code:
The find.c file consists entirely of the back end code that finds the
desired trips, given that the lineInfo array is properly initialized.
The trips are found in two stages. First, all possible routes (ways
to get from the source station to the destination station by taking
different lines) are found in the FindRoute function. This is done,
by checking for each line, if the source stations appears before the
destination station in that line. If so, we record that route. We
then check all transfer stations after the source station and call
FindRoute recursively on the lines that we would transfer to at each
one, up to a recursion level of MAX_TRANSFERS+1. In this way, we find
all routes that take at most MAX_TRANSFERS transfers.
The second stage of finding trips consists of finding and evaluating
times of the possible trips for each route. This stage is performed
by the FindTimes function. In that function, we perform the following
steps.
1. Lock handle pointers to data we need for each line in the
route, allocate a transfer_train array for each line, and
allocate a data cache for each line.
2. In the FindValidTrains function, set transfer_train[segment][t] to
zero if train t on line route->line[segment] stops at both the
source and destination stations. If not, or if we are using bike
restrictions and the train fails any of them, we set
transfer_train[segment][t] to INVALID_TRAIN (0xff). We call this
function for each line in the route.
3. If there is more than one line used in the trip, for all but the
last line, calculate the "transfer train" in the next line on which
a transfer would be made for each train in current line. In doing
this we ignore trains in the next line already marked invalid in
step 2. This is done by the FindTransferTrains function, and sets
transfer_train[segment][t] to the index of the train in line
route->line[segment+1] on which the transfer would be made. If
there is no valid train on which to make a transfer, we set
transfer_train[segment][t] to INVALID_TRAIN. By doing this
backward from the last pair of lines in the trip to the first pair,
we are guaranteed that transfer_train[0][t] is valid if and only if
there is a series of valid trains starting with train t on line
route->line[0] that gets us to the destination. Moreover, we
can follow the indices in the transfer_train arrays to find the
necessary trains to take on that trip.
4. Use KillDuplicateTransferTrains to follow the indices in the
transfer_train arrays and find the number of the train on the last
line that corresponds to each train on the first line. We then
mark invalid transfer_train[0][t1] if there exists a train t2 > t1
that has the same final train number. In this way, we eliminate
any trips on this route that take longer than necessary to get
to the destination.
5. Use FindBestRouteTrains to find the "best" MAX_TRIPS trips
around the desired time of all the valid trips we found for this
route. This function assumes there is at most one trip that
exactly meets the desired time condition. Let e be that number of
"exact" trips. If the time condition is leaving, we try to find
(MAX_TRIPS-e)/2 trips before the desired time, and
(MAX_TRIPS-e+1)/2 trips after the desired time. If the time
condition is arriving, we try to find (MAX_TRIPS-e+1)/2 trips
before the desired time and (MAX_TRIPS-e)/2 trips after the desired
time. The logic thus gives preference to trips after the desired
time if we are leaving, or preference to trips before the desired
time if we are arriving. If there are insufficient trips either
before or after, we take whatever extra trips we can get in the
opposite direction to fill up to MAX_TRIPS trips.
6. Use FindRouteTrainTimes to find times for the trains in the
trips found in step 5.
7. Deallocate the data cache for each line and unlock handles.
After finding the trips for each route, we use MergeTimes to merge
those trips into the list previously found trips. We try to maintain
the same before/exact/after split as in step 5 of FindTimes, but here
e may be greater than one. Finally, we take the list of MAX_TRIPS
trips merged from all routes and use MergeTimes to pare the list down
to MAX_TRIPS_DISPLAYED trips. This list is then used to fill the
resultsInfo table which in turn is used by the user interface
functions to display the results in the results form.
On Exit:
User interface settings are saved, and memory is freed.
Notes on the Database Format
----------------------------
The database format was designed for maximum compression of the
schedule data so that as little space as possible is taken up on the
pilot. Other than using Bytes instead of Ints everywhere possible,
the compression is largely due to a run length encoding of train
properties for the trains on each line. These properties are the
difference in starting time from the last train, the bike restriction
stations, and the increment vector. The increment vector needs some
explanation: it is a vector of the increments to the starting time of
the train to get the time at subsequent stations. For BART (and I
would think for other systems with decent schedules) there is a small
number of unique increment vectors for each line. In the
make-pdb-file code, each set of trains with the same properties is
referred to as a block.
Although the application supports both per-day and default transfer
records, make-pdb-file creates only a default transfer record. (The
application will first check if a per-day transfer record exists for
the selected day, and if not, use the default transfer record.) We
can get away with a single transfer record because BART uses the same
10 lines for weekdays and Saturdays, and only 6 of those lines for
Sundays. By ordering lines 0-5 the same for each of the three day
categories, and ensuring that the order of lines 6-9 are the same for
weekdays and Saturdays, the line information for transfers is
consistent across all days. When searching for valid transfers, the
application simply rejects those transfers to or from a line greater
than the number of lines for the current day.
Other Miscellaneous Notes
-------------------------
Restrictions/Limitations:
The fact that some quantities in the code and pdb file are represented
as Bytes or SBytes, and the fact that we use the value 0xff in some
cases to mean invalid, imposes the following restrictions on the data:
- at most 255 stations
- at most 254 minutes difference between a train's first stop on its
line and its last stop on its line
- between -128 and 127 minutes difference between successive trains'
first stops
- at most 15 schedule day categories (due to catgory representation on
the pilot)
- at most 248 lines (due to record numbering)
- at most 255 trains on a line per day
- at most 256 stops on each line
- at most 256 increment vectors per line per day
- in cents, min fare = M*m, max fare = M*(m+x), for M, m, x <= 255.
(see make-pdb-file:gen_fares_info)
Most of these limitations can be removed by changing the necessary
variables in the *.[ch] files from Byte to Int, and changing the
necessary pack call in make-pdb-file to pack a "n" instead of a "c" or
"C". If you do this, be careful about iteration variables as well as
alignment issues!
One other limitation is imposed by the table in which the results are
displayed. Since there are only six columns, we can only display
trips with two transfers. It would be possible (and probably not too
difficult), to add a horizontal scroll feature to the table to present
more than six columns, if one needed to show trips with more than two
transfers.
Send questions, comments, or suggestions to wittman@cs.berkeley.edu.