From: Thibaut GRIDEL Date: Mon, 1 Nov 2010 14:50:45 +0000 (+0100) Subject: Imported Upstream version 1.4.1 X-Git-Url: http://vcs.maemo.org/git/?p=routino;a=commitdiff_plain;h=20283c6cf5c6951cc1f2787492c67a7fb72aee9a Imported Upstream version 1.4.1 --- 20283c6cf5c6951cc1f2787492c67a7fb72aee9a diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..7c79159 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1732 @@ +2010-07-10 Andrew M. Bishop + + Version 1.4.1 released + +2010-07-10 Andrew M. Bishop + + * doc/NEWS.txt: Update NEWS for release. + + * doc/ALGORITHM.txt: + Update documentation for slight modification to algorithm, also add more + information about how preferences etc are handled. + +2010-07-09 Andrew M. Bishop + + * src/Makefile: + Default compilation flags include optimisation and not debugging symbols. + +2010-07-08 Andrew M. Bishop + + * src/nodes.c: + Fix error with finding closest segment to the specified point. + + * src/optimiser.c: + Bug fix for not crashing when finding the middle part of the route. + +2010-07-07 Andrew M. Bishop + + * src/results.c, src/optimiser.c: + Changed the amount of memory allocated for intermediate results => routes much + faster. + + * src/output.c: Remove compilation warning. + + * src/Makefile: + Copy files to web directory like done in other Makefiles. + + * doc/Makefile: + Change location of HTML files in web directory and clean up web directory on distclean. + + * src/xml/Makefile: Stop message being printed when make runs. + + * xml/Makefile: + Fix error from last checkin and clean up web directory on distclean. + +2010-07-06 Andrew M. Bishop + + * src/optimiser.c: + Don't crash if the middle part of the route can't be found but exit cleanly. + +2010-07-05 Andrew M. Bishop + + * src/superx.c: Change the algorithm used to determine supernodes. + +2010-07-03 Andrew M. Bishop + + * xml/routino-translations.xml: + Added German translation [patch from Christoph Eckert]. + + * src/translations.c: + Don't crash if more than one language is in translations.xml but --language + option is not used. + +2010-06-28 Andrew M. Bishop + + * src/router.c: Don't crash if start and finish are the same point. + +2010-06-27 Andrew M. Bishop + + * doc/DATA.txt: New file. + + * doc/ALGORITHM.txt, doc/CONFIGURATION.txt, doc/INSTALL.txt, doc/OUTPUT.txt, doc/README.txt, + doc/TAGGING.txt, doc/USAGE.txt: + Updated documentation to match new web site. + + * doc/Makefile: New file. + + * xml/Makefile: Add some new variables. + +2010-06-26 Andrew M. Bishop + + * xml/routino-profiles.xml, xml/routino-tagging-nomodify.xml, xml/routino-tagging.xml, + xml/routino-translations.xml, src/translations.c: + Changed URLs to http://www.routino.org/ + + * doc/README.txt: *** empty log message *** + + * doc/OUTPUT.txt: Changed URLs to http://www.routino.org/ + +2010-05-31 Andrew M. Bishop + + Version 1.4 released + +2010-05-31 Andrew M. Bishop + + * doc/INSTALL.txt, doc/NEWS.txt, doc/README.txt: + Update for version 1.4. + + * src/xml/Makefile: Make sure that distclean really cleans up. + + * Makefile: Make sure that xml sub-directory is made. + + * src/router.c: + Fix the code that should stop routing if no segment is found. + +2010-05-30 Andrew M. Bishop + + * doc/USAGE.txt: + Add the planetsplitter tagging rules option (and remove the unnecessary options + that it replaces), add the filedumper OSM dump option and add the tagmodifier + program. + + * doc/TAGGING.txt: Describe the new tagging rules. + + * doc/OUTPUT.txt: Note that the HTML and GPX outputs are translated. + + * doc/CONFIGURATION.txt: Add the tagging rules configuration file. + + * doc/ALGORITHM.txt: An update to the current size of the UK database. + + * xml/routino-tagging-nomodify.xml: New file. + + * src/tagmodifier.c: + A tagging XML file must be read (just like planetsplitter). + + * src/filedumper.c: + Add the option to dump a region rather than all and to not output super + segments. + + * src/optimiser.c: Fix printing the number of super-segments tried. + +2010-05-29 Andrew M. Bishop + + * xml/routino-translations.xml, xml/routino-translations.xsd, src/ways.h, src/filedumper.c, + src/osmparser.c, src/output.c, src/translations.c, src/translations.h: + Translate the names given to unnamed roads (the highway type). + + * src/profiles.c, src/profiles.h, src/router.c: + Stricter check on specified profile before routing. + + * src/router.c: Ensure that if no segment is found the routing stops. + + * src/nodes.c: + When finding a closest segment one of the nodes must be within the search + distance. + +2010-05-28 Andrew M. Bishop + + * src/router.c: Make sure that some profiles are loaded. + +2010-05-27 Andrew M. Bishop + + * src/optimiser.c, src/profiles.c: + Fix bug with profile preferences (used incorrectly in route optimisation). + + * src/Makefile, src/filedumper.c, src/types.c, src/types.h: + Add an option to filedumper to dump an OSM format file. + +2010-05-25 Andrew M. Bishop + + * src/xmlparse.l: Fix bug with encoding XML strings. + +2010-05-23 Andrew M. Bishop + + * xml/Makefile: + Make sure that modified files are copied to web directory. + + * src/tagmodifier.c: + Fix bug when filename is specified on command line. + + * src/tagging.c, src/tagging.h, src/tagmodifier.c, src/xmlparse.l, src/osmparser.c: + Fix some memory leaks. + + * src/tagmodifier.c, xml/osm.xsd, xml/routino-osm.xsd, src/osmparser.c: + Add the 'bound' element to the XML parser. + +2010-05-22 Andrew M. Bishop + + * src/functionsx.h, src/osmparser.c, src/planetsplitter.c, src/ways.h, src/waysx.c, + src/waysx.h: + Remove the --transport=, --not-highway= and + --not-property= options from planetsplitter because they can be done + by the tagging.xml file now. + +2010-05-18 Andrew M. Bishop + + * src/Makefile: Add tagmodifier program. + + * src/xmlparse.l: Handle floating point numbers in scientific notation. + + * src/planetsplitter.c: + Read in the tag transformation rules before calling the OSM parser. + + * src/functionsx.h, src/osmparser.c: + Almost completely re-written OSM parser using tagging transformations. + + * src/tagmodifier.c, src/tagging.h, src/tagging.c: New file. + + * xml/Makefile: Copy the tagging rules to the web directory. + + * xml/routino-tagging.xml, xml/routino-tagging.xsd, xml/routino-osm.xsd: + New file. + + * xml/osm.xsd: Small fix for OSM schema. + +2010-05-14 Andrew M. Bishop + + * src/types.c: Remove highway type aliases from HighwayType() function. + + * src/xmlparse.h, src/xmlparse.l: Allow empty strings to be returned. + +2010-05-10 Andrew M. Bishop + + * src/xmlparse.h, src/xmlparse.l: + The line number is now a long integer. + + * src/xml/Makefile: Running 'make test' now compiles everything first. + +2010-04-28 Andrew M. Bishop + + * src/xml/Makefile: Delete zero length file if xsd-to-xmlparser fails. + + * src/nodes.c, src/nodesx.c, src/segments.c, src/segmentsx.c, src/ways.c, src/waysx.c: + Change file format to allow 64-bit off_t type with 32 bit void* type. + + * src/Makefile, src/filedumper.c, src/xml/Makefile: + Compile with _FILE_OFFSET_BITS=64 to get 64-bit fopen() and stat(). + +2010-04-27 Andrew M. Bishop + + * src/output.c: Fix mistake of writing GPX information to wrong file. + + * doc/OUTPUT.txt, doc/CONFIGURATION.txt: New file. + + * doc/TAGGING.txt, doc/USAGE.txt, doc/ALGORITHM.txt, doc/INSTALL.txt, doc/NEWS.txt, + doc/README.txt: + Interim checkin of updated documentation. + +2010-04-24 Andrew M. Bishop + + * src/router.c: + Merged the three functions to output the head/body/tail of the results back into + a single function. Added the '--output-none' option. + + * src/functions.h, src/output.c: + Merged the three functions to output the head/body/tail of the results back into + a single function. + + * xml/routino-translations.xml, xml/routino-translations.xsd, src/output.c, + src/translations.c, src/translations.h: + Added translations for the HTML output. + + * src/xmlparse.h, src/xmlparse.l: Changed functions from const. + + * src/output.c: + Add the copyright information into the translations.xml file instead of the + separate copyright.txt file. Add the translated copyright strings into the + outputs. + + * src/functions.h, src/router.c, src/translations.c, src/translations.h: + Add the copyright information into the translations.xml file instead of the + separate copyright.txt file. + + * src/xmlparse.h, src/xmlparse.l: + Add an option to not convert the XML strings into decoded representations (saves + converting them back later for the translated strings). + +2010-04-23 Andrew M. Bishop + + * src/xml/xsd-to-xmlparser.c, src/translations.c, src/xmlparse.h, src/xmlparse.l, + src/profiles.c: + Pass the tag name to the tag function. + +2010-04-22 Andrew M. Bishop + + * Makefile: Fix bug in makefile. + + * xml/Makefile: Move the translations into the web directory. + + * xml/routino-translations.xml, xml/routino-translations.xsd: New file. + + * src/output.c: Changed HTML output to be useful in web pages. + + * src/xmlparse.l: + Restart properly so that a different file can be read. + +2010-04-13 Andrew M. Bishop + + * src/xml/xsd-to-xmlparser.c, src/profiles.c, src/translations.c: + Name the tag variables and functions after the XSD data type and not the tag + name that uses it. + +2010-04-12 Andrew M. Bishop + + * src/profiles.c, src/translations.c, src/xmlparse.h, src/xmlparse.l, + src/xml/xsd-to-xmlparser.c, src/xml/Makefile: + Change the last parameter to the ParseXML function to be general options. + + * src/Makefile, src/types.h, src/ways.c, src/ways.h: + Move the type checking/printing functions from way.c to type.c. + + * src/types.c: New file. + +2010-04-11 Andrew M. Bishop + + * src/xml/xsd-to-xmlparser.c, src/profiles.c, src/translations.c, src/xmlparse.h, + src/xmlparse.l: + Added helper functions for parsing strings into numbers. + Added macros to perform common error checking. + Change XML parser callback functions to return an error status. + +2010-04-10 Andrew M. Bishop + + * src/router.c: Fix usage information. + + * src/translations.h, src/translations.c: New file. + + * src/output.c: Added translations for GPX and turn/heading. + + * src/Makefile, src/router.c: + Added file of translations and language selection. + +2010-04-09 Andrew M. Bishop + + * src/functions.h, src/planetsplitter.c, src/sorting.c: + Add an option '--sort-ram-size' to specify the RAM to use for sorting - defaults + to 256MB if not using slim mode. + +2010-04-08 Andrew M. Bishop + + * src/xml/Makefile: Fix test program generation and running. + + * src/xmlparse.h, src/xmlparse.l: + Make the strings const and add the number of attributes to the xmltag structure. + Add functions to convert character entities and character references. + + * src/profiles.c, src/xml/xsd-to-xmlparser.c: + Make the strings const and add the number of attributes to the xmltag structure. + +2010-04-07 Andrew M. Bishop + + * xml/Makefile: New file. + +2010-04-06 Andrew M. Bishop + + * src/Makefile: + Remove special lex/flex flags. Remove profiles.o from planetsplitter. + + * src/xml/xsd-to-xmlparser.c: + Don't print anything for attributes that are not set. + + * src/xmlparse.l: + Change error message for bad character in a quoted string. + Make sure attribute values are cleared before calling tag function (for + end-tags). + +2010-04-04 Andrew M. Bishop + + * src/xml/Makefile: Add some XML parsing test cases. + + * src/xml/xsd-to-xmlparser.c: Rename the XML handling function. + + * src/xmlparse.h, src/xmlparse.l, src/profiles.c: Added error checking. + +2010-04-03 Andrew M. Bishop + + * src/functionsx.h, src/osmparser.c, src/planetsplitter.c: + Rename the old ParseXML() function as ParseOSM(). + +2010-04-01 Andrew M. Bishop + + * src/output.c: Wrap GPX descriptions in CDATA. + +2010-03-31 Andrew M. Bishop + + * xml/routino-profiles.xml: New file. + + * src/xml/xsd-to-xmlparser.c, src/profiles.c, src/xmlparse.h, src/xmlparse.l: + Call the XML tag functions for the end tags as well as the start tags. + +2010-03-30 Andrew M. Bishop + + * src/profiles.c, src/profiles.h: + Change the name of the --profile-json and --profile-perl options. + + * src/filedumper.c, src/planetsplitter.c, src/router.c: + Improve the program help messages. + +2010-03-29 Andrew M. Bishop + + * src/files.c, src/functions.h, src/profiles.c, src/profiles.h, src/router.c: + Added command line option to specify a file containing profiles. + Added command line option to select profile by name from loaded set. + Use XML parser to read in the profiles. + + * src/Makefile: Better handling of the xml sub-directory. + + * src/xml/xsd-to-xmlparser.c: + Add the option to ignore unknown attributes. + Print out the skeleton file using static functions and variables. + + * src/xml/Makefile: Keep the intermediate files. + + * src/xmlparse.h, src/xmlparse.l: + Add the option to ignore unknown attributes. + +2010-03-28 Andrew M. Bishop + + * src/profiles.h, src/router.c, src/profiles.c: + Add an option to print out the profiles as XML format. + + * src/xmlparse.h, xml/xsd.xsd, xml/osm.xsd, src/xml/xsd-to-xmlparser.c: + New file. + + * src/Makefile: Added the XML subdirectory and xmlparser.c. + + * src/xmlparse.l, src/xml/Makefile: New file. + +2010-03-20 Andrew M. Bishop + + * src/output.c: Add descriptions to each point in the GPX route file. + + * src/files.c, src/functions.h, src/nodesx.c, src/output.c, src/segmentsx.c, src/waysx.c: + Move the stat() calls to find a file size into a helper function in files.c. + + * src/files.c, src/output.c, src/planetsplitter.c: + Improve the error messages by adding strerror() to them. + + * src/filedumper.c, src/router.c: + Don't check the return value of the functions to load the nodes, segments and + ways because those functions will exit in case of an error. + + * src/nodes.c, src/segments.c, src/ways.c: + Don't check the return value of MapFile() because it will exit in case of an + error. + + * src/planetsplitter.c: + Allow filenames on the planetsplitter command line. + +2010-03-19 Andrew M. Bishop + + * src/waysx.h, src/filedumper.c, src/files.c, src/functions.h, src/nodesx.c, src/nodesx.h, + src/planetsplitter.c, src/segmentsx.c, src/segmentsx.h, src/superx.c, src/waysx.c: + Allow planetsplitter to be run with a --parse-only or --process-only option and + append to existing file or read from existing file. + +2010-03-18 Andrew M. Bishop + + * src/router.c: Fix usage message error and shuffle order. + + * src/output.c, src/router.c: + Allow selection of which outputs are to be created. + +2010-03-17 Andrew M. Bishop + + * src/output.c: Re-order the code for HTML. + +2010-03-15 Andrew M. Bishop + + * src/output.c: Create a simple HTML output. + +2010-03-06 Andrew M. Bishop + + * src/router.c, src/nodes.c: + Speed up start/via/stop point search algorithm. + +2010-03-05 Andrew M. Bishop + + * src/profiles.c: + Change the format of the output for the --help-profile-{pl|js} options. + +2010-01-21 Andrew M. Bishop + + Version 1.3 released + +2010-01-21 Andrew M. Bishop + + * doc/NEWS.txt: Update to latest news. + +2010-01-18 Andrew M. Bishop + + * doc/USAGE.txt, doc/TAGGING.txt, doc/INSTALL.txt: + Updated documentation. + +2010-01-15 Andrew M. Bishop + + * src/router.c, src/functions.h: + Change the test output formats to add turn, node type and bearing information. + +2010-01-13 Andrew M. Bishop + + * src/output.c: + Change the test output formats to add turn, node type and bearing information. + +2009-12-16 Andrew M. Bishop + + * src/router.c: + Added an option to use only nodes and not interpolate a point into a segment. + +2009-12-15 Andrew M. Bishop + + * src/osmparser.c, src/profiles.c, src/types.h, src/ways.c: + Added wheelchair as type of transport. + +2009-12-13 Andrew M. Bishop + + * src/osmparser.c, src/profiles.c, src/types.h, src/ways.c: + Add bridge and tunnel to highway properties. + +2009-12-12 Andrew M. Bishop + + * src/Makefile: + Ignore the error if executables cannot be copied after compiling. + + * src/functions.h, src/nodesx.c, src/segmentsx.c, src/sorting.c, src/waysx.c: + Add some FILESORT_* #defines and use them. + +2009-12-11 Andrew M. Bishop + + * src/functions.h, src/nodesx.c, src/planetsplitter.c, src/segmentsx.c, src/sorting.c, + src/waysx.c, src/waysx.h: + Added a new function to sort variable length data - simplifies the compacting of + ways, reduces memory usage potentially required for it and simplifies the code. + +2009-12-10 Andrew M. Bishop + + * src/waysx.c: + Write out the list of ways without memory mapping anything. + +2009-11-27 Andrew M. Bishop + + * src/osmparser.c, src/profiles.c, src/types.h, src/ways.c: + Add in "multilane" as a new highway property. + +2009-11-25 Andrew M. Bishop + + * src/filedumper.c, src/optimiser.c, src/osmparser.c, src/planetsplitter.c, src/profiles.h, + src/router.c, src/ways.h, src/waysx.c, src/waysx.h: + Store the selected options when parsing (planetsplitter) and display them in the + statistics (filedumper) and check them when routing (router). + +2009-11-23 Andrew M. Bishop + + * src/osmparser.c, src/output.c, src/profiles.c, src/types.h, src/ways.c: + Add in "steps" as a new highway type. + +2009-11-19 Andrew M. Bishop + + * src/optimiser.c, src/router.c: + Made the verbose output consistent between different places. + +2009-11-18 Andrew M. Bishop + + * src/router.c: Fix bug with previous segment-splitting routing. + +2009-11-14 Andrew M. Bishop + + * src/optimiser.c, src/output.c, src/router.c, src/segments.h, src/functions.h, src/nodes.c, + src/nodes.h: + If a selected waypoint is not very close to an existing node then insert a fake + node in the segment that comes closest and use that instead. + +2009-11-13 Andrew M. Bishop + + * src/optimiser.c, src/osmparser.c, src/queue.c, src/results.c, src/results.h, src/types.h: + Added in some more constants with the value ~0. + +2009-11-06 Andrew M. Bishop + + * src/filedumper.c: + Check the values for the --node=, --segment= and --way= options. + +2009-11-03 Andrew M. Bishop + + * src/output.c, src/planetsplitter.c, src/profiles.c, src/profiles.h, src/router.c, + src/types.h, src/ways.c: + Rename Way_Unknown to Way_Count to make more sense and match the properties. + +2009-11-02 Andrew M. Bishop + + * src/osmparser.c: Allow the tag "paved" as well as "surface=paved". + + * src/filedumper.c, src/optimiser.c, src/osmparser.c, src/planetsplitter.c, src/profiles.c, + src/profiles.h, src/router.c, src/types.h, src/ways.c, src/ways.h: + Added the ability to set routing preferences using highway properties. + Initially the only choice is either paved or unpaved but the code has been + updated to allow any number of properties to be added. + +2009-10-27 Andrew M. Bishop + + * src/osmparser.c: + Handle the "designation=..." tag for bridleway, byway and footpath. (Also + change to using a macro for testing if access is allowed and now allow + "destination"). + + * src/osmparser.c, src/profiles.c, src/types.h, src/ways.c, src/ways.h: + Added Moped to the list of transports (and incidentally increased the transport + data type to 16 bits and re-ordered the Way data-type in response). + +2009-10-26 Andrew M. Bishop + + * src/profiles.c: + Ensure that horses and bicycles have a default speed on trunk even though they + have a default preference not to use it. + + * src/osmparser.c, src/profiles.c, src/types.h, src/ways.c: + Re-ordered the types so that Horse comes before Bicycle. + + * src/osmparser.c, src/output.c, src/profiles.c, src/types.h, src/ways.c: + Remove the Bridleway and Footway highway types and use the Path type instead + (also re-ordered the types so that Cycleway comes before Path). + + * src/profiles.c: Remove unneeded spaces at the end of the output. + +2009-10-25 Andrew M. Bishop + + * src/output.c: + Fix bug in code that determines waypoints for abbreviated output. + +2009-10-24 Andrew M. Bishop + + * src/functions.h, src/optimiser.c, src/router.c: + Fix missing segments in output if start and finish points are found by the start + search. + +2009-10-22 Andrew M. Bishop + + * src/files.c, src/nodesx.c, src/segmentsx.c, src/sorting.c, src/superx.c, src/waysx.c: + Added some missing comments and corrected some existing ones. + +2009-10-21 Andrew M. Bishop + + Version 1.2 released + +2009-10-21 Andrew M. Bishop + + * doc/README.txt, doc/USAGE.txt, doc/NEWS.txt: Updated for version 1.2. + +2009-10-20 Andrew M. Bishop + + * src/Makefile: Add sorting.o to the Makefile. + +2009-10-12 Andrew M. Bishop + + * src/waysx.c: When sorting we cannot have NULL pointers now. + + * src/nodesx.c, src/segmentsx.c, src/waysx.c: + Re-order the functions in the file into a more logical order. + No functional changes. + + * src/nodesx.c, src/planetsplitter.c, src/segmentsx.c, src/sorting.c, src/waysx.c: + Rename the tmpdirname variable. + +2009-10-10 Andrew M. Bishop + + * src/nodesx.c, src/osmparser.c, src/segmentsx.c, src/sorting.c, src/waysx.c: + Corrections after running with valgrind. + + * src/planetsplitter.c: Fix early termination test. + + * src/nodesx.c, src/nodesx.h, src/segmentsx.c: + Remove the nodesx->gdata index. + +2009-10-09 Andrew M. Bishop + + * src/nodesx.c, src/segmentsx.c, src/typesx.h, src/waysx.c, src/waysx.h: + Free the nodesx->super array and the segmentsx->firstnode array when finished + with them. Remove wayx->cid and overwrite wayx->id instead. Overwrite + nodex[i]->id=i for later geographically sorted use. + +2009-10-08 Andrew M. Bishop + + * src/nodesx.c, src/planetsplitter.c, src/segmentsx.c, src/segmentsx.h, src/superx.c: + Replace node, segment and way indexes with a single index for a set of segments + containing the location of the first segment for each node. + + * src/nodesx.h: Fix comment. + +2009-10-07 Andrew M. Bishop + + * src/osmparser.c, src/segmentsx.c, src/superx.c: + AppendSegment adds a single segment and not a pair. + + * src/waysx.c: Use heapsort() instead of qsort(). + + * src/nodesx.c, src/nodesx.h, src/planetsplitter.c, src/segmentsx.c, src/segmentsx.h, + src/superx.c, src/waysx.c: + Go back to the version 1.1 method of having each segment listed twice. This + simplifies the lookup of first/next segments at no in-RAM index cost and now + that slim mode has sorting of file contents the balance has tipped back. + +2009-10-04 Andrew M. Bishop + + * src/functions.h, src/sorting.c: + Change the sort function to allow the indexing callback to veto the write. + + * src/nodesx.c: Remove the duplicates when sorting. + + * src/waysx.c: + Sort the ways using the same method as the nodes. Also remove the duplicates. + + * src/nodesx.c: + Use the new sort functions to allow sorting the data in the file without needing + to read (or mmap) the whole file into RAM at the same time. + + * src/functions.h: Add some functions to perform sorting. + + * src/sorting.c: New file. + + * src/queue.c: Fix bug with binary heap sort. + +2009-09-25 Andrew M. Bishop + + * src/queue.c: Add comments describing the algorithm used. + +2009-09-23 Andrew M. Bishop + + * src/nodesx.c, src/waysx.c: + Simplify the de-duplication when sorting and update some comments. + +2009-09-22 Andrew M. Bishop + + * src/nodesx.c, src/nodesx.h: + Remove a leftover from the last change on these files. + + * src/segmentsx.c: Improve the super-segment de-duplication. + +2009-09-21 Andrew M. Bishop + + * src/nodesx.c, src/nodesx.h, src/planetsplitter.c: + Remove the non-highway nodes without re-sorting the whole list again. + +2009-09-17 Andrew M. Bishop + + * src/osmparser.c, src/planetsplitter.c, src/segmentsx.c, src/superx.c, src/waysx.c, + src/waysx.h: + Added the slim mode to Ways as well. + + * src/ways.h: Add padding to Ways structure to allow it to be zeroed. + + * src/nodesx.c: Add some comments when closing and re-opening files. + + * src/files.c, src/functions.h: + The WriteFile function now has a const parameter. + +2009-09-15 Andrew M. Bishop + + * src/nodesx.c, src/nodesx.h, src/planetsplitter.c, src/segmentsx.c: + Some bug fixes and some missing unmap function calls. + +2009-09-07 Andrew M. Bishop + + * src/segmentsx.h, src/superx.c, src/nodesx.c, src/nodesx.h, src/segmentsx.c: + Fixed slim mode for segments and nodes (slim now means mapping only one file + into RAM at a time and none when creating the final output). + +2009-09-06 Andrew M. Bishop + + * src/nodesx.h, src/planetsplitter.c, src/segmentsx.c, src/segmentsx.h, src/superx.c, + src/superx.h, src/nodesx.c: + Slim version of segments code (still very slow and only works on simple cases). + + * src/files.c, src/functions.h: + Remove the delete option from UnmapFile() and make it return NULL. + + * src/filedumper.c: Allow dumping all nodes, segments or ways. + +2009-09-05 Andrew M. Bishop + + * src/nodesx.c: Don't re-sort unnecessarily. + + * src/nodesx.c, src/nodesx.h, src/planetsplitter.c, src/segmentsx.c, src/superx.c: + Improve slim mode for nodes so that no data is not loaded into RAM at all. + + * src/files.c, src/functions.h: Add some more file functions. + +2009-09-03 Andrew M. Bishop + + * src/nodesx.c, src/files.c, src/functions.h: + Remove extra argument from MapFile function. + + * src/nodesx.c, src/nodesx.h, src/planetsplitter.c, src/segmentsx.c, src/superx.c: + Added slim mode (--slim) to planetsplitter for nodes only. + + * src/files.c, src/functions.h: + Changes to mapping and unmapping files for slim mode. + +2009-08-25 Andrew M. Bishop + + * src/planetsplitter.c: Revert the order that the functions are called. + + * src/nodesx.c: Fix for assert statement. + + * src/files.c: Bug fix for mmap(). + +2009-08-20 Andrew M. Bishop + + * src/osmparser.c: Fix bug with memory allocation. + +2009-08-19 Andrew M. Bishop + + * src/nodesx.c, src/nodesx.h, src/planetsplitter.c, src/segmentsx.c, src/segmentsx.h, + src/superx.c, src/waysx.c, src/waysx.h: + Remove "sorted" parameter in data structure and change assert statements. + +2009-08-17 Andrew M. Bishop + + * src/router.c: + Increase to 99 the number of waypoints that can be specified. + +2009-08-15 Andrew M. Bishop + + * src/queue.c: Fix comment. + + * src/Makefile: + Tidy the compilation options to make it easier to turn them on and off. + + * src/router.c: + Remove the --all, --super and --no-output command line options. + Handle the renamed routing functions. + + * src/functions.h, src/optimiser.c: + Rename the routing functions and make FindRoute only find routes with no + super-nodes in them. + + * src/queue.c: + When popping from queue make sure that place in queue is cleared. + + * src/optimiser.c, src/queue.c, src/results.c, src/results.h, src/superx.c: + Optimise the priority queue used for routing. + + * src/filedumper.c: Fix dumping nodes when they are super-nodes. + +2009-07-23 Andrew M. Bishop + + * src/Makefile, src/optimiser.c, src/results.c, src/results.h, src/superx.c: + Split off queue functions into a separate file. + + * src/queue.c: New file. + +2009-07-19 Andrew M. Bishop + + * src/nodesx.c, src/segments.h, src/segmentsx.c, src/ways.h, src/waysx.c, src/filedumper.c, + src/nodes.h: + Include the number of super-nodes, super-segments etc in the database as useful + information to put in the statistics output. + + * src/superx.c: Fix incorrect progress indicator message. + + * src/waysx.c: Fix problem with memory reallocation. + + * src/nodesx.c, src/osmparser.c, src/planetsplitter.c, src/segmentsx.c, src/segmentsx.h, + src/superx.c: + Store only one copy of each segment but index once for each direction. + +2009-07-12 Andrew M. Bishop + + * src/functionsx.h, src/nodesx.c, src/nodesx.h, src/osmparser.c, src/output.c, + src/planetsplitter.c, src/profiles.c, src/results.c, src/segments.c, src/segmentsx.c, + src/segmentsx.h, src/superx.c, src/superx.h, src/ways.h, src/waysx.c, src/waysx.h: + Tidy up and fix comments and include files. + + * src/osmparser.c, src/planetsplitter.c, src/router.c, src/segmentsx.c, src/superx.c, + src/waysx.c, src/filedumper.c, src/nodesx.c, src/optimiser.c: + Check all print statements and made them more consistent and/or accurate. + +2009-07-11 Andrew M. Bishop + + * src/nodesx.c, src/nodesx.h, src/planetsplitter.c, src/segmentsx.c, src/waysx.c, + src/waysx.h: + Free memory at the end of planetsplitter (to aid finding potential leaks + earlier). + +2009-07-09 Andrew M. Bishop + + * src/segmentsx.c: Free memory correctly (really). + + * src/planetsplitter.c, src/waysx.c, src/waysx.h: + Separate the sorting of Ways from compacting of Ways. + + * src/nodes.h, src/nodesx.c, src/nodesx.h, src/segmentsx.c, src/visualiser.c, + src/filedumper.c, src/nodes.c: + Rename structure members after recent changes. + + * src/segmentsx.c: Free memory correctly. + + * src/types.h, src/segmentsx.c: Fix duplicate checking. + + * src/planetsplitter.c: Ensure that variable is reset before using it. + + * src/types.h, src/visualiser.c, src/visualiser.h, src/filedumper.c, src/nodes.c, + src/nodes.h, src/nodesx.c, src/nodesx.h, src/optimiser.c, src/osmparser.c, src/output.c, + src/router.c, src/segments.c, src/segments.h, src/segmentsx.c: + Change from float to double for latitude and longitude. + Store latitude and longitude as an integer type rather than float (higher precision). + +2009-07-08 Andrew M. Bishop + + * src/superx.c: Ensure that variable is reset before using it. + +2009-07-06 Andrew M. Bishop + + * src/visualiser.c: + Print all super-segments within and crossing the border. + Don't display speed limits for tracks and paths unless set. + +2009-07-04 Andrew M. Bishop + + * src/segmentsx.h, src/superx.c, src/waysx.c, src/waysx.h: + Change data structure to avoid calling realloc() each time to allocate more + memory. + +2009-07-02 Andrew M. Bishop + + * src/types.h, src/waysx.c, src/waysx.h: + Handle duplicate ways. + + * src/nodes.c, src/nodesx.c, src/planetsplitter.c, src/profiles.c, src/results.c, + src/segments.c, src/segmentsx.c, src/superx.c, src/superx.h, src/types.h, src/ways.c, + src/waysx.c: + Fix some gcc pedantic warnings. + + * src/files.c, src/nodesx.c, src/osmparser.c, src/results.c, src/router.c, src/segments.c, + src/segmentsx.c, src/superx.c, src/ways.c, src/waysx.c: + Removed unused header files, change assert statements, tidy some code. + +2009-07-01 Andrew M. Bishop + + * src/nodesx.c, src/nodesx.h, src/planetsplitter.c, src/segmentsx.c, src/segmentsx.h, src/superx.c: + Remove the Node structure from the NodeX structure to save memory. + + * src/filedumper.c: + Print latitude and longitude in degrees. + +2009-06-30 Andrew M. Bishop + + * src/segmentsx.h: + Re-order the data in the structure. + + * src/nodesx.c, src/nodesx.h, src/osmparser.c, src/planetsplitter.c, src/segmentsx.c, + src/segmentsx.h, src/superx.c, src/waysx.h: + Remove the Segment structure from the SegmentX structure to save memory. + +2009-06-29 Andrew M. Bishop + + * src/filedumper.c, src/nodes.h, src/nodesx.c, src/segments.c, src/segments.h, + src/segmentsx.c, src/superx.c, src/types.h: + Move the super-segment and normal-segment flags from the nodes to the distance. + Remove the NODE() macro and rename SUPER_FLAG to NODE_SUPER. + + * src/waysx.c: Replace memmove with structure copy. + + * src/nodesx.c, src/segmentsx.c, src/segmentsx.h, src/superx.c: + Rename SegmentsX sdata to ndata. + +2009-06-25 Andrew M. Bishop + + * src/waysx.c, src/waysx.h: Rename part of the structure. + + * src/nodesx.c, src/nodesx.h, src/planetsplitter.c, src/segmentsx.c, src/segmentsx.h, + src/superx.c, src/waysx.h: + Undo part of the previous change - only update the Segment way index at the end. + + * src/waysx.h, src/nodesx.c, src/osmparser.c, src/planetsplitter.c, src/segmentsx.c, + src/segmentsx.h, src/superx.c, src/superx.h, src/typesx.h, src/waysx.c: + Reduce the number of ways in the output by compacting them (sharing the same + information between identical ways). + +2009-06-24 Andrew M. Bishop + + * src/filedumper.c, src/nodes.h: + Allow dumping out of nodes, segments and ways. + +2009-06-15 Andrew M. Bishop + + * src/segmentsx.c, src/superx.c, src/visualiser.c, src/ways.c, src/ways.h: + Rename WaysSame() with WaysCompare() and reverse the sense of the output. + + * src/functionsx.h, src/typesx.h: New file. + + * src/functions.h, src/nodesx.h, src/osmparser.c, src/planetsplitter.c, src/segmentsx.h, + src/superx.h, src/types.h, src/waysx.h: + Put some of types.h into typesx.h (for extended data types). + Put some of functions.h into functionsx.h (for OSM parser). + Change included files to match. + + * src/filedumper.c, src/osmparser.c, src/output.c, src/router.c, src/types.h, src/visualiser.c: + Add a macro for converting degrees to radians and radians to degrees. + + * src/optimiser.c: + Fix weight, height, width, length restriction routing. + + * doc/TAGGING.txt, src/osmparser.c: + Recognise tags "vehicle" and "motor_vehicle". + +2009-06-13 Andrew M. Bishop + + Version 1.1 released + +2009-06-13 Andrew M. Bishop + + * src/nodesx.c, src/planetsplitter.c, src/segmentsx.c, src/segmentsx.h: + Handle nodes that are missing from the .osm file (ignore the segment). + + * src/nodesx.c: + Revert the last change (Print an error message and exit if a node cannot be found). + + * doc/NEWS.txt: New file. + + * src/Makefile: + Delete the executables from the web directory for 'distclean'. + +2009-06-12 Andrew M. Bishop + + * doc/USAGE.txt, doc/INSTALL.txt, doc/README.txt: + Update the documentation. + + * src/Makefile: Copy the executables into the web directory. + +2009-06-08 Andrew M. Bishop + + * src/filedumper.c: Change help text. + + * src/visualiser.c: + Change format of super-node/segment visualiser output. + +2009-06-07 Andrew M. Bishop + + * doc/TAGGING.txt: Updated with imperial to metric conversions. + + * src/Makefile: Added visualiser.c. + + * src/filedumper.c: Now used for data visualisation and statistics. + + * src/visualiser.h, src/visualiser.c: New file. + +2009-06-05 Andrew M. Bishop + + * src/osmparser.c: + Improve parsing of imperial units (mph, feet & inches). + +2009-06-03 Andrew M. Bishop + + * src/nodesx.c: + Print an error message and exit if a node cannot be found. + +2009-05-31 Andrew M. Bishop + + * src/ways.c, src/ways.h, src/waysx.c, src/waysx.h: + Move function from waysx.c to ways.c. + +2009-05-29 Andrew M. Bishop + + * doc/USAGE.txt: + Update usage information with new options and copyright.txt usage. + + * src/nodes.c, src/nodes.h, src/router.c: + Make sure that the chosen "nearest point" is a highway that the profile allows. + +2009-05-23 Andrew M. Bishop + + * src/profiles.c: + Change the default profile; horses are slower, bicycles may be allowed on + footways (and similar). + +2009-05-15 Andrew M. Bishop + + * src/files.c, src/output.c: + Error checking on opening files (to read/write data and to write output). + +2009-05-14 Andrew M. Bishop + + * src/output.c, src/results.c, src/router.c, src/segments.c, src/segmentsx.c, src/superx.c, + src/types.h, src/nodes.c, src/nodesx.c, src/optimiser.c: + Replace ~0 or 0 with NO_NODE value for "no node" condition. + +2009-05-13 Andrew M. Bishop + + * src/output.c: + Remove one more NODE macro and fix an output formatting error. + + * src/nodes.c, src/nodes.h, src/optimiser.c, src/output.c, src/router.c: + Remove some node macros, change some node function arguments. + + * src/optimiser.c, src/profiles.c, src/profiles.h: + Move some common code into the profile. + + * src/superx.c: Remove distance and duration from Result structure. + + * src/output.c: Better junction detection. + + * src/optimiser.c, src/results.c, src/results.h: + Remove distance and duration from Result structure. + +2009-05-09 Andrew M. Bishop + + * src/output.c: + Add better junction detection for deciding on route waypoints. + +2009-05-06 Andrew M. Bishop + + * src/optimiser.c, src/profiles.c, src/profiles.h, src/types.h: + Route using preferences for each highway. + + * src/router.c: Print out longitude then latitude. + +2009-04-30 Andrew M. Bishop + + * src/results.h, src/router.c, src/superx.c, src/types.h, src/optimiser.c, src/osmparser.c, + src/planetsplitter.c, src/profiles.c, src/profiles.h, src/results.c: + First attempt at preferences for highways - uses integer arithmetic and doesn't + work well. + +2009-04-27 Andrew M. Bishop + + * src/functions.h, src/optimiser.c, src/output.c, src/results.c, src/results.h, src/router.c: + Allow generating a route with intermediate waypoints. + +2009-04-24 Andrew M. Bishop + + * src/functions.h, src/output.c, src/router.c: + Split the output functions into separate head/body/tail. + Read in an optional copyright.txt file and include contents in output. + +2009-04-23 Andrew M. Bishop + + * src/profiles.c: Improve Javascript and perl print out. + + * src/filedumper.c, src/files.c, src/functions.h, src/planetsplitter.c, src/router.c: + Move the filename generation to a new function. + +2009-04-22 Andrew M. Bishop + + * src/Makefile, src/functions.h, src/optimiser.c: + Split the function to print the output into a new file. + + * src/output.c: New file. + +2009-04-15 Andrew M. Bishop + + * src/osmparser.c: + Fix for parsing nodes from XML (no effect on results). + +2009-04-12 Andrew M. Bishop + + * doc/USAGE.txt, src/optimiser.c: + Create a GPX route as well as a track. + + * src/ways.c: Changed the license to Affero GPLv3. + +2009-04-10 Andrew M. Bishop + + * src/optimiser.c: + Add a waypoint to the GPX file for the start and finish points. + + * doc/USAGE.txt: + Include more information about the output file formats. + +2009-04-08 Andrew M. Bishop + + Version 1.0 released + +2009-04-08 Andrew M. Bishop + + * Makefile: New file. + + * src/Makefile: Fix dependency file generation. + + * doc/USAGE.txt, doc/TAGGING.txt, doc/README.txt, doc/INSTALL.txt, doc/ALGORITHM.txt: + New file. + + * src/Makefile, src/filedumper.c, src/files.c, src/functions.h, src/nodes.c, src/nodes.h, + src/nodesx.c, src/nodesx.h, src/optimiser.c, src/osmparser.c, src/planetsplitter.c, + src/profiles.c, src/profiles.h, src/results.c, src/results.h, src/router.c, src/segments.c, + src/segments.h, src/segmentsx.c, src/segmentsx.h, src/superx.c, src/superx.h, src/types.h, + src/ways.h, src/waysx.c, src/waysx.h: + Changed the license to Affero GPLv3. + +2009-04-07 Andrew M. Bishop + + * src/planetsplitter.c: Remove the --help-profile command line option. + +2009-03-28 Andrew M. Bishop + + * src/optimiser.c: + Fix file headers (again) and fix segment distance/duration for abbreviated text + output. + +2009-03-24 Andrew M. Bishop + + * src/osmparser.c, src/profiles.c, src/types.h, src/ways.c: + Added highway=path; defaults to foot=yes but also is defaulted for bicycle and + horse transport. + +2009-03-23 Andrew M. Bishop + + * src/optimiser.c: Fixed the header in the output text files. + + * src/osmparser.c: + Add parsing for *=designated allowing passage along a highway. + + * src/profiles.h, src/router.c, src/profiles.c: + Add a function to output default profiles as perl data structures. + +2009-03-21 Andrew M. Bishop + + * src/nodesx.c: + Handle duplicated nodes (e.g. from concatenated input files). + + * src/optimiser.c: Add a header to the output text files. + +2009-03-07 Andrew M. Bishop + + * src/optimiser.c: + Renamed the *.txt output to *-all.txt and added a new shorted *.txt output. + + * src/router.c: Renamed the --no-print option to --no-output. + +2009-03-04 Andrew M. Bishop + + * src/nodes.c: Fix bug with finding nearest node. + +2009-03-03 Andrew M. Bishop + + * src/superx.c: Fix the merging of super-segments. + +2009-03-01 Andrew M. Bishop + + * src/profiles.c, src/profiles.h: + Added more limits (weight, height, width, length). + + * src/segments.c: Use the lower speed from the profile and the way. + + * src/osmparser.c: Added more limits (weight, height, width, length). + Added highway=living_street and highway=services. + + * src/ways.c, src/ways.h, src/optimiser.c, src/router.c, src/segmentsx.c, src/superx.c, + src/types.h: + Added more limits (weight, height, width, length). + + * src/waysx.c, src/waysx.h: + Added a function to test if two ways are the same. + +2009-02-28 Andrew M. Bishop + + * src/nodesx.c: + Round the node location to avoid if falling into the wrong bin. + + * src/nodesx.c, src/planetsplitter.c, src/segmentsx.c, src/waysx.c: + Move print statements from planetsplitter into individual functions. + + * src/Makefile: Compile with optimisation and no profiling. + + * src/profiles.c, src/router.c: + Add new command line options to make it more CGI friendly. + +2009-02-27 Andrew M. Bishop + + * src/profiles.c, src/profiles.h, src/router.c: + Print out Javascript code containing the profiles. + +2009-02-24 Andrew M. Bishop + + * src/segmentsx.h, src/superx.c, src/nodesx.c, src/segments.c, src/segments.h, + src/segmentsx.c: + Remove segment->next1 since it always points at the next segment or nowhere. + + * src/profiles.c: Remove track from valid types for most transports. + +2009-02-15 Andrew M. Bishop + + * src/functions.h, src/optimiser.c, src/router.c: + Change some function names. + + * src/osmparser.c: Add in tests for motorcar=1 etc. + + * src/nodes.c, src/nodes.h, src/router.c: + The search to find a node given the lat/long now searches harder. + + * src/optimiser.c: Better test for failing to find a route. + + * src/router.c: Change --only-super to --super. + + * src/nodesx.c, src/optimiser.c, src/osmparser.c, src/router.c, src/segments.c, + src/segmentsx.c, src/types.h, src/nodes.c: + Store radians rather than degrees. + + * src/segments.c, src/segmentsx.c: + Change to sinf(), cosf(), sqrtf(), asinf() functions. + + * src/optimiser.c: + Set the sortby parameter to the minimum distance/duration consistent with the + travelled distance/duration and the remaining straight line distance with the + fastest possible speed. + + * src/filedumper.c, src/nodes.c, src/nodes.h, src/nodesx.c, src/types.h: + Add macros for handling lat/long to bin conversions. + + * src/osmparser.c: Handle oneway=1 and oneway=-1. + +2009-02-10 Andrew M. Bishop + + * src/results.c, src/results.h: + Added a new 'sortby' entry to the Result. + Changed node_t to index_t. + + * src/router.c: Changed node_t to index_t. + + * src/nodes.c, src/segments.c, src/segments.h: + Change the Distance() function to return distance_t. + +2009-02-08 Andrew M. Bishop + + * src/optimiser.c, src/results.c, src/results.h, src/router.c, src/superx.c: + Calculate quickest or shortest, not both. + + * src/optimiser.c, src/profiles.c, src/router.c: + Give appropriate error messages if start or end of route are not possible. + +2009-02-07 Andrew M. Bishop + + * src/results.c: + Slight speedup by doing a linear search when looking up results and not storing + in sorted order. + + * src/superx.h, src/superx.c, src/waysx.h, src/waysx.c, src/segmentsx.h, src/segmentsx.c, + src/nodesx.h, src/nodesx.c: + New file. + + * src/ways.h, src/Makefile, src/filedumper.c, src/functions.h, src/nodes.c, src/nodes.h, + src/optimiser.c, src/osmparser.c, src/planetsplitter.c, src/router.c, src/segments.c, + src/segments.h, src/types.h, src/ways.c: + Split the extended data types from the normal data types. + + * src/nodes.c: Return NULL if the node cannot be found. + + * src/Makefile, src/filedumper.c, src/optimiser.c, src/router.c: + Add new command line options. + + * src/supersegments.c: Fix some status messages. + + * src/optimiser.c, src/types.h: Routing works with super-nodes now. + +2009-02-06 Andrew M. Bishop + + * src/ways.c, src/segments.c, src/segments.h, src/supersegments.c, src/types.h, src/nodes.c, + src/nodes.h, src/optimiser.c, src/osmparser.c, src/planetsplitter.c, src/functions.h: + Segments now not duplicated in database. + Routing with all nodes works, not with super-nodes. + +2009-02-04 Andrew M. Bishop + + * src/router.c: Fix usage output. + + * src/ways.c, src/ways.h: Only sort once, don't store the index. + + * src/planetsplitter.c, src/router.c: + Use '--*' command line arguments, not '-*'. + + * src/nodes.c, src/router.c, src/segments.c, src/ways.c: + Make sure that nodes, segments and ways could be loaded. + + * src/nodes.h, src/optimiser.c, src/router.c, src/segments.c, src/segments.h, + src/supersegments.c, src/types.h, src/filedumper.c, src/nodes.c: + Sort the nodes geographically and take coordinates as command line arguments. + +2009-02-02 Andrew M. Bishop + + * src/ways.c, src/ways.h, src/nodes.c, src/nodes.h, src/osmparser.c, src/segments.c, + src/segments.h, src/supersegments.c, src/types.h: + More variable and function name changes. + +2009-02-01 Andrew M. Bishop + + * src/profiles.c, src/router.c, src/segments.c, src/segments.h, src/supersegments.c, + src/ways.c, src/ways.h, src/files.c, src/functions.h, src/nodes.c, src/nodes.h, + src/optimiser.c, src/osmparser.c, src/planetsplitter.c, src/filedumper.c: + Rename some variable types. + +2009-01-31 Andrew M. Bishop + + * src/segments.c, src/segments.h, src/supersegments.c, src/types.h, src/ways.c, src/ways.h, + src/functions.h, src/nodes.c, src/nodes.h, src/optimiser.c, src/planetsplitter.c, + src/profiles.h, src/router.c: + Intermediate version during code cleanup. + + * src/optimiser.c, src/planetsplitter.c, src/router.c, src/segments.c, src/segments.h, + src/functions.h, src/nodes.h: + Intermediate checkin, routing now working. + + * src/Makefile: + Don't print out anything when creating the dependencies directory. + + * src/planetsplitter.c, src/router.c: + Add command line options to specify the directory and filename prefix. + +2009-01-30 Andrew M. Bishop + + * src/results.c, src/planetsplitter.c: Remove gcc warning. + + * src/Makefile: Move dependencies to subdir. + + * src/osmparser.c: Remove gcc warning. + +2009-01-29 Andrew M. Bishop + + * src/functions.h, src/nodes.c, src/nodes.h, src/optimiser.c, src/planetsplitter.c, + src/router.c, src/segments.c, src/segments.h, src/supersegments.c: + Intermediate version while transitioning data format for nodes and segments. + +2009-01-28 Andrew M. Bishop + + * src/Makefile, src/functions.h, src/nodes.c, src/nodes.h, src/optimiser.c, src/osmparser.c, + src/planetsplitter.c, src/segments.c, src/segments.h, src/supersegments.c, src/ways.c, + src/ways.h: + Intermediate version while transitioning data format for nodes and segments. + +2009-01-27 Andrew M. Bishop + + * src/Makefile, src/functions.h, src/nodes.c, src/nodes.h, src/optimiser.c, + src/planetsplitter.c, src/router.c, src/segments.c, src/segments.h, src/supersegments.c, + src/ways.c, src/ways.h: + Intermediate version while transitioning data format for nodes and segments. + +2009-01-26 Andrew M. Bishop + + * src/osmparser.c, src/planetsplitter.c, src/segments.c, src/segments.h, + src/supersegments.c, src/ways.c, src/ways.h, src/filedumper.c, src/files.c, src/functions.h, + src/optimiser.c: + Change Segment to contain index of way not its real ID. + Don't store the real way ID to save space. + +2009-01-25 Andrew M. Bishop + + * src/segments.c, src/segments.h: + Slightly speed up the Duration calculation by changing the macro. + + * src/osmparser.c, src/profiles.c, src/ways.c, src/ways.h: + Fix misspelling of Unclassified. + + * src/planetsplitter.c, src/segments.c, src/segments.h, src/supersegments.c, src/ways.h, + src/optimiser.c: + Change the segment->way so that it contains the index of the way, not the id. + + * src/profiles.c, src/profiles.h: New file. + + * src/ways.c, src/ways.h, src/Makefile, src/functions.h, src/optimiser.c, src/osmparser.c, + src/planetsplitter.c, src/router.c, src/segments.c, src/segments.h: + Added profiles to define speed and allowed highways. + Added new options to planetsplitter and router to use the profiles. + +2009-01-24 Andrew M. Bishop + + * src/optimiser.c: Changed some variable names for clarity. + + * src/planetsplitter.c: Print more information about progress. + Don't quit until 99.9% unchanged. + + * src/optimiser.c, src/results.c, src/results.h, src/supersegments.c: + Change the Results structure so that the real data doesn't need to be realloc(). + Add functions to access the first and subsequent elements of the Results structure. + +2009-01-23 Andrew M. Bishop + + * src/osmparser.c, src/planetsplitter.c: + Fix bug with not specifying a method of transport. + + * src/optimiser.c, src/router.c: Proper check that it was unroutable. + + * src/functions.h, src/optimiser.c, src/planetsplitter.c, src/supersegments.c: + Remove "iteration" as function argument. + + * src/functions.h, src/optimiser.c, src/osmparser.c, src/planetsplitter.c, src/router.c, + src/ways.c, src/ways.h: + Add command line options to planetsplitter and router. + Select transport type (must be allowed on way for parsing). + Select highway types (ignore when parsing or routing). + + * src/ways.h, src/functions.h, src/optimiser.c, src/osmparser.c, src/router.c, + src/segments.c, src/segments.h, src/ways.c: + Add enumerated type Transport. + Replace variables of AllowType with Transport where more appropriate. + Replace AllowType with Allowed. + Replace WayType with Highway. + + * src/osmparser.c: Only include ways that are not Way_Unknown type. + + * src/osmparser.c: Include permissive access. + + * src/functions.h, src/optimiser.c, src/results.c, src/results.h, src/router.c: + Create a large or small results structure depending on how many nodes are + expected. + +2009-01-22 Andrew M. Bishop + + * src/results.h: Increase the number of bins to 64k. + + * src/optimiser.c, src/osmparser.c, src/segments.c, src/segments.h, src/supersegments.c: + Remove INVALID_DISTANCE and INVALID_DURATION. + + * src/optimiser.c, src/osmparser.c, src/supersegments.c, src/ways.c, src/ways.h: + Removed the Way_TYPE() macro. + + * src/results.c, src/results.h, src/optimiser.c: + Move queue functions into results.c. + + * src/filedumper.c, src/nodes.c, src/nodes.h, src/planetsplitter.c, src/router.c: + Nodes, Segments, Ways - Nodes, Segments, Ways. + + * src/filedumper.c, src/nodes.c, src/nodes.h, src/segments.c, src/segments.h, src/ways.c, + src/ways.h: + Remove the choice of indexed or non-indexed data structures. + +2009-01-21 Andrew M. Bishop + + * src/optimiser.c: + Various small speed-ups including not-reversing direction. + + * src/functions.h, src/optimiser.c, src/osmparser.c, src/router.c, src/segments.c, + src/segments.h, src/supersegments.c, src/ways.c, src/ways.h: + Calculate way speeds at routing time. + + * src/supersegments.c: + Add reverse-oneway segments when creating supernodes. + Check incoming oneway streets as well as outgoing ones. + + * src/osmparser.c: Don't change speed on roundabouts. + +2009-01-20 Andrew M. Bishop + + * src/planetsplitter.c: + Add command line options for skipping parsing and iteration limit. + + * src/optimiser.c, src/osmparser.c, src/segments.c, src/segments.h, src/supersegments.c: + Remove duration from segment, calculate duration depending on speed. + +2009-01-19 Andrew M. Bishop + + * src/functions.h, src/optimiser.c, src/planetsplitter.c, src/supersegments.c: + Iteratively calculate the super-segments. + + * src/ways.h: Redefine Way_TYPE() to include one-way status. + +2009-01-18 Andrew M. Bishop + + * src/optimiser.c, src/supersegments.c: + Fix problems with way-type matching and duplicated/missing super-segments. + + * src/functions.h, src/optimiser.c, src/router.c: Print out a GPX file. + + * src/optimiser.c, src/filedumper.c, src/functions.h, src/planetsplitter.c, src/router.c, + src/segments.c, src/segments.h, src/supersegments.c, src/ways.c, src/ways.h: + Added Super-Ways and allow user to select method of transport. + + * src/segments.c: Fix for changes made to ways. + + * src/supersegments.c: + Ensure that supernodes are inserted wherever the way type changes. + + * src/osmparser.c: Fill in the extra way information. + + * src/ways.h: + Store more information about a way (allowed modes of transport). + + * src/filedumper.c: Fix output printing. + + * src/router.c: Print an error if no route can be found. + + * src/optimiser.c: + Fix bugs when start and/or finish nodes are supernodes. + +2009-01-17 Andrew M. Bishop + + * src/Makefile: Add the option to create assembler output files. + + * src/optimiser.c, src/results.c, src/results.h, src/supersegments.c: + Change the contents of the results data structure. + + * src/router.c: Added an option to not print the result. + +2009-01-16 Andrew M. Bishop + + * src/optimiser.c, src/results.h, src/router.c: + Speed optimisation by changing the contents of the Results structure. + + * src/optimiser.c: + Don't bother calculating the distance to go, it takes too long. + +2009-01-14 Andrew M. Bishop + + * src/planetsplitter.c: Remove bad segments and non-way nodes. + + * src/nodes.c, src/nodes.h: Remove nodes which are not in highways. + Fix the sorting and create indexes after sorting, not before saving. + + * src/segments.c, src/segments.h: + Remove bad segments (repeated consecutive nodes and duplicate segments). + Fix the sorting and create indexes after sorting, not before saving. + + * src/supersegments.c: Use invalid distances properly. + + * src/ways.c: + Fix the sort algorithm and update the indexes after sorting, not before saving. + + * src/optimiser.c: Fix the bug with merging the results. + Fix the bug with not clearing the results structure properly. + + * src/osmparser.c: + Add segments that correspond to the wrong way along one-way routes with an + invalid distance. + +2009-01-11 Andrew M. Bishop + + * src/functions.h, src/optimiser.c, src/router.c: + Routes correctly using super-nodes (not Lands End to John O'Groats though). + + * src/filedumper.c, src/functions.h, src/optimiser.c, src/planetsplitter.c, src/router.c, + src/segments.h, src/supersegments.c: + Replace Junction with SuperNode. + + * src/nodes.c, src/nodes.h, src/segments.h, src/ways.c, src/ways.h: + Some small changes to the nodes, segments and ways functions. + + * src/Makefile, src/filedumper.c, src/functions.h, src/optimiser.c, src/planetsplitter.c, + src/results.h, src/router.c, src/segments.c, src/segments.h, src/supersegments.c: + Working version with supersegments and junctions. + +2009-01-10 Andrew M. Bishop + + * src/ways.c, src/ways.h, src/osmparser.c, src/segments.c: + Store more information about ways. + + * src/results.h, src/results.c: New file. + + * src/Makefile, src/optimiser.c: + Move the results data type into new files. + + * src/nodes.h, src/segments.h, src/ways.h: + Increase the increment for the indexed array case. + + * src/ways.h, src/Makefile, src/filedumper.c, src/functions.h, src/nodes.c, src/nodes.h, + src/optimiser.c, src/osmparser.c, src/planetsplitter.c, src/router.c, src/segments.c, + src/segments.h, src/supersegments.c, src/ways.c: + About to add the super-segment functionality using Segments data type to hold + them. + + * src/functions.h, src/types.h: + Changed after nodes, ways and segment changes. + +2009-01-09 Andrew M. Bishop + + * src/segments.h: New file. + + * src/segments.c: + Changed the format of the segments data type to match the nodes. + + * src/nodes.h: Enable indexed arrays. + + * src/ways.h: New file. + + * src/ways.c: + Changed the format of the ways data type to match the nodes. + + * src/nodes.c, src/nodes.h: + Changed the format of the nodes data type again. + +2009-01-07 Andrew M. Bishop + + * src/nodes.h: New file. + + * src/nodes.c: Lots of modifications: + Two data structures - in memory (pointers) and in file (array). + Data is hashed into multiple bins. + Each function takes a nodes structure as an argument. + +2009-01-06 Andrew M. Bishop + + * src/supersegments.c: New file. + + * src/Makefile, src/filedumper.c, src/functions.h, src/planetsplitter.c, src/types.h: + Added SuperSegments data type, but it does nothing yet. + + * src/optimiser.c: + Tried to optimise the Queue data type. It was slower than the original. + +2009-01-05 Andrew M. Bishop + + * src/filedumper.c: Print out the longest segment. + + * src/optimiser.c: + Some optimisations. Increase the number of result bins and change + find_insert_result() into insert_result(). + +2009-01-04 Andrew M. Bishop + + * src/optimiser.c: Introduced some new data types to simplify the code. + + * src/filedumper.c: Print more useful information. + + * src/segments.c, src/types.h, src/ways.c, src/filedumper.c, src/functions.h, src/nodes.c, + src/optimiser.c, src/osmparser.c, src/planetsplitter.c: + Changed the node, way and segment functions and data types. + Removed 'alloced', shortened the prototype array. + Remove the automatic sorting of the data. + Added assert statements. + +2009-01-03 Andrew M. Bishop + + * src/ways.c: New file. + + * src/router.c, src/types.h, src/Makefile, src/filedumper.c, src/functions.h, + src/optimiser.c, src/osmparser.c, src/planetsplitter.c: + Added the ways to the output. + +2009-01-02 Andrew M. Bishop + + * src/optimiser.c, src/osmparser.c, src/segments.c, src/types.h: + Added macros to convert between distance/km and duration/hours/minutes. + Shortened the Segment data type with shorter distances and durations. + +2009-01-01 Andrew M. Bishop + + * src/functions.h, src/nodes.c, src/planetsplitter.c, src/segments.c, src/types.h: + Remove the functions to initialise the node and segment arrays. + + * src/optimiser.c, src/router.c, src/Makefile: Print out the results. + +2008-12-31 Andrew M. Bishop + + * src/types.h, src/segments.c, src/router.c, src/planetsplitter.c, src/osmparser.c, + src/optimiser.c, src/nodes.c, src/functions.h, src/files.c, src/filedumper.c, src/Makefile: + New file. + diff --git a/INSTALL.txt b/INSTALL.txt new file mode 120000 index 0000000..b0385da --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1 @@ +doc/INSTALL.txt \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b6ee933 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +# $Header: /home/amb/routino/RCS/Makefile,v 1.3 2010/05/31 12:44:43 amb Exp $ +# +# Makefile +# +# Part of the Routino routing software. +# +# This file Copyright 2009-2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +FILES=$(wildcard */Makefile) +DIRS=$(foreach f,$(FILES),$(dir $f)) + +######## + +all: + for dir in $(DIRS); do \ + ( cd $$dir && $(MAKE) $@ ); \ + done + +######## + +clean: + for dir in $(DIRS); do \ + ( cd $$dir && $(MAKE) $@ ); \ + done + +######## + +distclean: clean + for dir in $(DIRS); do \ + ( cd $$dir && $(MAKE) $@ ); \ + done diff --git a/NEWS.txt b/NEWS.txt new file mode 120000 index 0000000..7a887e7 --- /dev/null +++ b/NEWS.txt @@ -0,0 +1 @@ +doc/NEWS.txt \ No newline at end of file diff --git a/README.txt b/README.txt new file mode 120000 index 0000000..253de0c --- /dev/null +++ b/README.txt @@ -0,0 +1 @@ +doc/README.txt \ No newline at end of file diff --git a/agpl-3.0.txt b/agpl-3.0.txt new file mode 100644 index 0000000..dba13ed --- /dev/null +++ b/agpl-3.0.txt @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/doc/ALGORITHM.txt b/doc/ALGORITHM.txt new file mode 100644 index 0000000..2432a88 --- /dev/null +++ b/doc/ALGORITHM.txt @@ -0,0 +1,212 @@ + Routino : Algorithm + =================== + + + This page describes the development of the algorithm that is used in + Routino for finding routes. + + +Simplest Algorithm +------------------ + + The algorithm to find a route is fundamentally simple: Start at the + beginning, follow all possible routes and keep going until you reach + the end. + + While this method does work, it isn't fast. To be able to find a route + quickly needs a different algorithm, one that can find the correct + answer without wasting time on routes that lead nowhere. + + +Improved Algorithm +------------------ + + The simplest way to do this is to follow all possible segments from the + starting node to the next nearest node (an intermediate node in the + complete journey). For each node that is reached store the shortest + route from the starting node and the length of that route. The list of + intermediate nodes needs to be maintained in order of shortest overall + route on the assumption that there is a straight line route from here + to the end node. + At each point the intermediate node that has the shortest potential + overall journey time is processed before any other node. From the first + node in the list follow all possible segments and place the newly + discovered nodes into the same list ordered in the same way. This will + tend to constrain the list of nodes examined to be the ones that are + between the start and end nodes. If at any point you reach a node that + has already been reached by a longer route then you can discard that + route since the newly discovered route is shorter. Conversely if the + previously discovered route is shorter then discard the new route. + At some point the end node will be reached and then any routes with + potential lengths longer than this actual route can be immediately + discarded. The few remaining potential routes must be continued until + they are found to be shorter or have no possibility of being shorter. + The shortest possible route is then found. + + At all times when looking at a node only those segments that are + possible by the chosen means of transport are followed. This allows the + type of transport to be handled easily. When finding the quickest route + the same rules apply except that criterion for sorting is the shortest + potential route (assuming that from each node to the end is the fastest + possible type of highway). + + This method also works, but again it isn't very fast. The problem is + that the complexity is proportional to the number of nodes or segments + in all routes examined between the start and end nodes. Maintaining the + list of intermediate nodes in order is the most complex part. + + +Final Algorithm +--------------- + + The final algorithm that is implemented in the router is basically the + one above but with an important difference. Instead of finding a long + route among a data set of 8,000,000 nodes (number of highway nodes in + UK at beginning of 2010) it finds one long route in a data set of + 1,000,000 nodes and a few hundred very short routes in the full data + set. Since the time taken to find a route is proportional to the number + of nodes the main route takes 1/10th of the time and the very short + routes take almost no time at all. + + The solution to making the algorithm fast is therefore to discard most + of the nodes and only keep the interesting ones. In this case a node is + deemed to be interesting if it is the junction of two segments with + different properties. In the algorithm these are classed as + super-nodes. Starting at each super-node a super-segment is generated + that finishes on another super-node and contains the shortest path + along segments with identical properties (and these properties are + inherited by the super-segment). The point of choosing the shortest + route is that since all segments considered have identical properties + they will be treated identically when properties are taken into + account. This decision making process can be repeated until the only + the most important and interesting nodes remain. + + To find a route between a start and finish point now comprises the + following steps (assuming a shortest route is required): + + 1. Find all shortest routes from the start point along normal segments + and stopping when super-nodes are reached. + 2. Find all shortest routes from the end point backwards along normal + segments and stopping when super-nodes are reached. + 3. Find the shortest route along super-segments from the set of + super-nodes in step 1 to the set of super-nodes in step 2 (taking + into account the lengths found in steps 1 and 2 between the + start/finish super-nodes and the ultimate start/finish point). + 4. For each super-segment in step 3 find the shortest route between + the two end-point super-nodes. + + This multi-step process is considerably quicker than using all nodes + but gives a result that still contains the full list of nodes that are + visited. There are some special cases though, for example very short + routes that do not pass through any super-nodes, or routes that start + or finish on a super-node. In these cases one or more of the steps + listed can be removed or simplified. + +Routing Preferences + + One of the important features of Routino is the ability to select a + route that is optimum for a set of criteria such as preferences for + each type of highway, speed limits and other restrictions and highway + properties. + + All of these features are handled by assigning a score to each segment + while calculating the route and trying to minimise the score rather + than simply minimising the length. + + Segment length + When calculating the shortest route the length of the segment is + the starting point for the score. + + Speed preference + When calculating the quickest route the time taken calculated + from the length of the segment and the lower of the highway's + own speed limit and the user's speed preference for the type of + highway is the starting point for the score. + + Oneway restriction + If a highway has the oneway property in the opposite direction + to the desired travel and the user's preference is to obey + oneway restrictions then the segment is ignored. + + Weight, height, width & length limits + If a highway has one of these limits and its value is less than + the user's specified requirement then the segment is ignored. + + Highway preference + The highway preference specified by the user is a percentage, + these are scaled so that the most preferred highway type has a + weighted preference of 1.0 (0% always has a weighted preference + of 0.0). The calculated score for a segment is divided by this + weighted preference. + + Highway properties + The other highway properties are specified by the user as a + percentage and each highway either has that property or not. The + user's property preference is scaled into the range 0.0 (for 0%) + to 2.0 (for 100%) to give a weighted preference, a second + "non-property" weighted preference is calcuated in the same way + after subtracting the user's preference from 100%. If a segment + has this property then the calculated score is divided by the + weighted preference, if the segment does not have this property + then it is divided by the non-property weighted preference. + +Implementation +-------------- + + The hardest part of implementing this router is the data organisation. + The arrangement of the data to minimise the number of operations + required to follow a route from one node to another is much harder than + designing the algorithm itself. + + The final implementation uses a separate table for nodes, segments and + ways. Each table individually is implemented as a C-language data + structure that is written to disk by a program which parses the + OpenStreetMap XML data file. In the router these data structures are + memory mapped so that the operating system handles the problems of + loading the needed data blocks from disk. + + Each node contains a latitude and longitude and they are sorted + geographically so that converting a latitude and longitude coordinate + to a node is fast as well as looking up the coordinate of a node. The + node also contains the location in the array of segments for the first + segment that uses that node. + Each segment contains the location of the two nodes as well as the way + that the segment came from. The location of the next segment that uses + one of the two nodes is also stored; the next segment for the other + node is the following one in the array. The length of the segment is + also pre-computed and stored. + Each way has a name, a highway type, a list of allowed types of + traffic, a speed limit, any weight, height, width or length + restrictions and the highway properties. + + The super-nodes are mixed in with the nodes and the super-segments are + mixed in with the segments. For the nodes they are the same as the + normal nodes, so just a flag is needed to indicate that they are super. + The super-segments are in addition to the normal segments so they + increase the database size (by about 10%) and are also marked with a + flag. + + +Practicalities +-------------- + + At the time of writing (April 2010) the OpenStreetMap data for Great + Britain (taken from GeoFabrik) contains: + * 14,675,098 nodes + + 8,767,521 are highway nodes + + 1,120,297 are super-nodes + * 1,876,822 ways + + 1,412,898 are highways + o 9,316,328 highway segments + o 1,641,009 are super-segments + * 60,572 relations + + The database files when generated are 41.5 MB for nodes, 121.6 MB for + segments and 12.6 MB for ways and are stored uncompressed. By having at + least 200 MB or RAM available the routing can be performed with no disk + accesses (once the data has been read once). + + +-------- + +Copyright 2008-2010 Andrew M. Bishop. diff --git a/doc/CONFIGURATION.txt b/doc/CONFIGURATION.txt new file mode 100644 index 0000000..fa6ae48 --- /dev/null +++ b/doc/CONFIGURATION.txt @@ -0,0 +1,177 @@ + Routino : Configuration + ======================= + + + New in version 1.4 of Routino is the use of configuration files to + allow more information to be provided to the programs at run-time. The + configuration files that are used are: + * Tagging transformation rules for the planetsplitter program. + * Routing profiles for the router program. + * Output translations for the router program. + + In keeping with the nature of the input and output files the + configuration files are also XML files. Each of the files uses a custom + defined XML schema and an XSD file is provided for each of them. + + +Tag Transformation Rules +------------------------ + + The default name of the tagging transformation rules XML configuration + file is tagging.xml in the same directory as the generated database + files. Other filenames can be specified on the command line using the + --tagging option. When processing the input it is possible to have a + different set of tagging rules for each file; for example different + rules for different countries. + + The tagging rules allow modifying the highway tags in the source file + so that the routing can be performed on a simpler set of tags. This + removes the special case tagging rules from the source code into the + configuration file where they can be easily modified. Part of the + provided tagging.xml file showing the rules for motorway_link and + motorway highway types. + + + + + + + + + + + + + + + + + + + + + + + +... + + + + + The rules all have the same format; an if element for matching the + input and some set or output elements to either change the input tags + or create an output tag. The k and v attributes have the same meaning + as the attributes with the same names in the OSM XML file - the tag key + and tag value. + + An if rule that has both k and v specified is only applied if a tag + exists in the input that matches both. An if rule that has only the k + attribute is applied if a tag with that key exists and an if rule that + has only the v attribute is applied to all tags with that value. + + For the set and output elements the tag that is created in the input or + output tag set uses the k and v attributes specified. If one or both + are not specified then the original ones are used. + + +Routing Profiles +---------------- + + The default name of the routing profiles XML configuration file is + profiles.xml in the same directory as the database files. Other + filenames can be specified on the command line using the --tagging + option. + + The purpose of this configuration file is to allow easy modification of + the routing parameters so that they do not all need to be specified on + the command line. In versions of Routino before version 1.4 the default + routing parameters (preferred highways, preferred speeds etc) were + contained in the source code, now they are in a configuration file. + When calculating a route the --profile option selects the named profile + from the configuration file. + + Part of the provided profiles.xml file showing the parameters for + transport on foot is shown below: + + + + + + +... + + + + + +... + + + + + + + + + + + + + + + + + + + +... + +... + + + +Output Translations +------------------- + + The default name of the output translations XML configuration file is + translations.xml in the same directory as the database files. Other + filenames can be specified on the command line using the --translations + option. + + The generated HTML and GPX output files (described in the next section) + are created using the fragments of text that are defined in this file. + Additional languages can be added to the file and are selected using + the --language option to the router. If no language is specified the + first one in the file is used. + + Part of the provided translations.xml file showing some of the English + language (en) translations is shown below: + + + + + +... + + + +... + + + +... + + + +... + + +... + + + + + +-------- + +Copyright 2010 Andrew M. Bishop. diff --git a/doc/DATA.txt b/doc/DATA.txt new file mode 100644 index 0000000..8cd61ed --- /dev/null +++ b/doc/DATA.txt @@ -0,0 +1,115 @@ + Routino : Data + ============== + + + A router relies on data to be able to find a route. + + +OpenStreetMap Data +------------------ + + The data that is collected by the OpenStreetMap project consists of + nodes, ways and relations. + + Node + A node is a point that has a latitude and longitude and + attributes that describe what type of point it is (part of a way + or a place of interest for example). + + Way + A way is a collection of nodes that when joined together define + something (for example a road, a ralway, a boundary, a building, + a lake etc). The ways also have attributes that define them + (speed limits, type of road and restrictions for example). + + Relation + A relation is a collection of items (usually ways) that are + related to each other for some reason (highways that make up a + route for example). + + The OpenStreetMap Wiki explains the data much better than I can. + + +Router Data +----------- + + The information that is needed by a routing algorithm is only a subset + of the information that is collected by the OpenStreetMap project. For + routing what is required is information about the location of roads (or + other highways), the connections between the highways and the + properties of those highways. + + Location of highways (nodes) + The locations of things is provided by the nodes from the + OpenStreetMap data. The nodes are the only things that have + coordinates in OpenStreetMap and everything else is made up by + reference to them. Not all of the nodes are useful, only the + ones that are part of highways. The location of the nodes is + stored but none of the other attributes are currently used by + the router. + + Location of highways (ways) + The location of the highways is defined in the OpenStreetMap + data by the ways. Only the highway ways are useful and the other + ways are discarded. What remains is lists of nodes that join + together to form a section of highway. This is further split + into segments which are individual parts of a way connected by + two nodes. + + Properties of highways (tags) + The ways that belong to highways are extracted from the data in + the previous step and for each way the useful information for + routing is stored. For the router the useful information is the + type of highway, the speed limit, the allowed types of transport + and other restrictions (one-way, min height, max weight etc). + + Connections between highways + The connections between highways are defined in the + OpenStreetMap data by ways that share nodes. Since the ways may + join in the middle and not just the ends it is the segments + defined above that are not part of the OpenStreetMap data that + are most important. + + The information that is extracted from the OpenStreetMap data is stored + in an optimised way that allows the routing to be performed quickly. + + +Interpreting Data Tags +---------------------- + + The tags are the information that is attached to the nodes and ways in + OpenStreetMap. The router needs to interpret these tags and use them + when deciding what type of traffic can use a highway (for example). + + There are no well defined rules in OpenStreetMap about tagging, but + there is guidance on the OpenStreetMap Wiki "Map_Features" page. This + describes a set of recommended tags but these are not universally used + so it is up to each application how to interpret them. + + The tagging rules that the router uses are very important in + controlling how the router works. With Routino the data tags can be + modified when the data is imported to allow customisation of the + information used for routing. + + +Problems With OpenStreetMap Data +-------------------------------- + + The route that can be found is only as good as the data that is + available. This is not intended as a criticism of the OpenStreetMap + data; it is generally good. + + There are some problems that are well known and which affect the + router. For example highways might be missing because nobody has mapped + them. A highway may be wrongly tagged with incorrect properties, or a + highway might be missing important tags for routing (e.g. speed + limits). There can also be problems with highways that should join but + don't because they do not share nodes. + + A lot of these problems can be found using the interactive data + visualiser that uses the same Routino rouing database. + + +-------- + +Copyright 2008-2010 Andrew M. Bishop. diff --git a/doc/INSTALL.txt b/doc/INSTALL.txt new file mode 100644 index 0000000..123f02c --- /dev/null +++ b/doc/INSTALL.txt @@ -0,0 +1,158 @@ + Routino : Installation + ====================== + + +Compilation +----------- + + This program has been written to run on Linux, no cross-platform + compatibility has been specifically included but on the other hand + nothing platform specific has been knowingly included either. + + Any information on improving the compilation process on anything other + than 32-bit x86 Linux is welcome. + + No external libraries are required and the programs are written in + standard C language. + + To compile the programs just type 'make'. + + +Installation +------------ + + After compilation the executable files are copied into the directory + web/bin and the default XML configuration files are copied into the + directory web/data. This is in preparation for using the supplied + example web pages but is also a useful location to copy the files from + for normal use. + + The executable files are called 'planetsplitter', 'router' and 'filedumper' + (also 'tagmodifier' for debugging tag modifications). They can be copied + to any location and need no special installation environment. + + The default configuration files are called 'profiles.xml', 'tagging.xml' + and 'translations.xml'. The names of the configuration files can be + specified on the command line but by default are also looked for in the + directory that contains the routing database. + + +Example Web Page +---------------- + + The directory 'web' contains a set of files that can be used to create a + working set of web pages with interfaces to the routing algorithm. + + The files in the 'web' directory will require copying to a location that + is accessible by a web server. After copying the files some of them + need to be edited; search through the files for lines that contain the + words "EDIT THIS" and make appropriate edits. The files that need + editing are 'paths.pl' (to set the directory paths) and 'router.js' and + 'visualiser.js' to limit the range of the visible map (latitude, + longitude and zoom). + + +Configuration of web files +-------------------------- + + The assumption in this description is that the whole of the directory + called web is copied into a directory that is accessible by an Apache + web server. + + ************************************************************************** + **** This is not a secure configuration but an easy one to configure. **** + **** Only the directory 'www' should be accessible by the web server. **** + **** Do not use this configuration unmodified in a public web server. **** + ************************************************************************** + + The directory structure is as follows: + + web/ + | + + /bin/ <- The Routino executable files (when compiled). + | + + /data/ <- The Routino database and default configuration + | files. + | + + /results/ <- An empty directory to store the results. + | + + /www/ <- The files that must be available to the web + | server are below this level. + | + + /openlayers/ <- A directory to hold the OpenLayers scripts. + | + + /routino/ <- The main HTML, Javascript, CSS and CGI files. + + + The directory 'bin' will be filled by running the compilation process. + For a secure installation the 'bin' directory should be outside of the + web server, the file 'www/routino/paths.pl' contains the path to the 'bin' + directory. + + The directory 'data' must contain the Routino database and is also the + default location for the configuration files. The routing database is + created by downloading the OSM files for the region of interest and + running the 'planetsplitter' program. There is a script in the directory + that will download the OSM files and create the required database. The + script should be edited to set the names of the files to be downloaded. + For a secure installation the 'data' directory should be outside of the + web server, the file 'www/routino/paths.pl' contains the path to the 'data' + directory. + + The directory 'results' is a temporary directory that it used to hold the + GPX and text files generated by the Routino router. The directory must + be writable by the web server process since it is the CGI scripts that + are run by the web server that writes the results here. For a secure + installation the results directory should be outside of the web server, + the file 'www/routino/paths.pl' contains the path to the results + directory. + + The directory 'www' and its sub-directories are the only ones that need + to be within the web server accessible directory. + + The directory 'www/openlayers' must be filled with the openlayers + Javascript library that can be downloaded from + http://www.openlayers.org/. (This version of Routino has been tested + with OpenLayers library version 2.8). The files must be installed so + that the file 'www/openlayers/OpenLayers.js' and the directories + 'www/openlayers/img/', 'www/openlayers/theme/' all exist. There is a script + in the directory that will automatically download and organise the + files. + + The directory 'www/routino' contains the main HTML, Javascript and CSS + files as well as the CGI scripts that perform the server-side + functions. The description below lists all of the files that contain + editable information. + + paths.pl + This contains the names of the directories that contain the + executable files, router database and temporary results. + + router.pl + This file contains the filename prefix for the routing database + files (only needed if planetsplitter is run with the --prefix + option). + + router.js + The parameters in this file control the boundary of the visible + map (defaults to UK), the minimum and maximum zoom levels + (defaults to between 4 and 15 inclusive) and the source of map + tiles (defaults to the main OpenStreetMap tile server). + + visualiser.js + The same parameters as in router.js are in this file. + + +Configuration of web server +--------------------------- + + The file 'www/routino/.htaccess' contains all of the Apache configuration + options that are required to get the example web pages running. The + only problem is that because of the way that the "AllowOverride" option + works one of the configuration options has been commented out. This + must be enabled in the main Apache server configuration file. + + +-------- + +Copyright 2008-2010 Andrew M. Bishop. diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..5bc7047 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,48 @@ +# $Header: /home/amb/routino/doc/RCS/Makefile,v 1.2 2010/07/07 17:27:03 amb Exp $ +# +# Documentation directory Makefile +# +# Part of the Routino routing software. +# +# This file Copyright 2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +WEBDIR=../web/www/routino/documentation + +FILES=html/* + +######## + +all : + -@[ -d $(WEBDIR) ] && \ + for file in $(FILES); do \ + if [ ! -f $(WEBDIR)/`basename $$file` ] || [ $$file -nt $(WEBDIR)/`basename $$file` ]; then \ + echo cp $$file $(WEBDIR) ;\ + cp -f $$file $(WEBDIR) ;\ + fi ;\ + done + +######## + +clean: + rm -f *~ + rm -f html/*~ + rm -f $(WEBDIR)/*~ + +######## + +distclean: clean + rm -f $(WEBDIR)/* diff --git a/doc/NEWS.txt b/doc/NEWS.txt new file mode 100644 index 0000000..a003671 --- /dev/null +++ b/doc/NEWS.txt @@ -0,0 +1,177 @@ +Version 1.4.1 of Routino released : Sat Jul 10 2010 +--------------------------------------------------- + +Bug fixes: + Don't crash if start and finish are the same point. + Don't crash if several translations but --language option not used. + Don't crash if middle part of route cannot be found. + Don't allocate so much memory for intermediate nodes; routes much faster. + Fix problem with finding closest segment to the specified point. + +Documentation: + Provide HTML versions of the documentation (copy to web directory at install). + Change URL for website to http://www.routino.org/. + +Configuration Files: + Added German translations. + +planetsplitter + Slight change to algorithm for finding super-nodes. + +Web pages: + Provide HTML versions of the documentation. + Change URL for website to http://www.routino.org/. + Provide updated HTML files, the same as on the website. + Change to OpenLayers v2.9.1 and build custom version if Python available. + + +Version 1.4 of Routino released : Mon May 31 2010 +------------------------------------------------- + +Bug fixes: + Speed up start/via/stop point within segment search algorithm. + If no segment is found don't try routing but exit with error. + Improve the error messages by adding operating system error info to them. + Rewrite of tagging rules fixes bug with wheelchair access allow/deny. + Files greater than 2GB can be read/written on 32-bit systems. + Fix bug with profile preferences when optimising a route. + Stricter check on profile validity before starting routing. + +planetsplitter + Add --parse-only and --process-only options (for incremental parsing). + Allow filenames to be specified on command line (default is still stdin). + Improved the '--help' information to describe all options. + Remove --transport, --not-highway, --not-property options (use config file). + Use tag transformation rules in configuration file not hard-coded. + +router + Removed compiled-in profiles and use profiles loaded from XML file. + Improved the '--help' information to describe all options. + Change the name of the --profile-json and --profile-perl options. + Allow selection of the outputs to generate (or none). + Added HTML route instructions output. + GPX route file contains instructions at each waypoint. + Read in XML file of translated words/phrases for outputs. + Added options to specify file of translations and language to use. + Remove copyright.txt file and put information into translations file. + +filedumper + Improved the '--help' information to describe all options. + Added the option to dump an OSM file containing database contents. + +Web Pages + Combined generic map CSS into one file (not copied in two). + Much better support for IE6/7/8 with browser detection but not perfect. + Re-organised and tidied up the Javascript. + Added button next to waypoints to centre it on map. + Added button next to waypoints to set as home location (uses browsser cookie). + Create shorter URLs for custom map (ignore default values). + Reduced and clarified the amount of editing to customise the Javascript. + Made it easier to translate by moving text out of Javascript (not visualiser). + Prepared for translated versions of web page (Apache Multiviews). + Added option to select language of output. + Use HTML output from router to get translated instructions. + + +Version 1.3 of Routino released : Thu Jan 21 2010 +------------------------------------------------- + +Bug fixes: + Ensure output even if the distance between two adjacent route points is small. + Correct the determination of waypoints for abbreviated output. + Check the command line values for filedumper --dump options. + Made the verbose output consistent between different places. + +OSM tagging + Recognise "designation" tag to determine designated paths. + Recognise "steps" tag to determine the highway type. + Recognise "wheelchair" tag to determine if wheelchairs are allowed on highway. + Recognise "moped" tag to determine if mopeds are allowed on a highway. + Recognise "surface" and "paved" tags to determine if a highway is paved. + Recognise "lanes" tag to determine if a highway has multiple lanes. + Recognise "bridge" tag to determine if a highway is a bridge. + Recognise "tunnel" tag to determine if a highway is a tunnel. + +New Features + Remove "bridleway" and "footway" highway types and use "path" highway instead. + Added "steps" as a new highway type separate from the "path" type. + Added "wheelchair" and "moped" to the list of possible transports. + Added "paved", "multilane", "bridge", "tunnel" to list of highway properties. + +Web Pages + Updated for new features listed above. + Added popup to display instructions for each step in route on mouse-over. + Added buttons next to waypoints for: add / remove / move up / move down. + Highlight user selectable parts of form in yellow on mouse-over. + A few small changes, improved CSS, improved Javascript. + +router + For each waypoint choose closest point on a segment and not just closest node. + Added the ability to set preferences based on highway properties. + Changed the text output formats to include bearing and turn information. + + +Version 1.2 of Routino released : Wed Oct 21 2009 +------------------------------------------------- + +OSM tagging + Recognise tags "vehicle" and "motor_vehicle". + Handle duplicate ways in the input OSM file (e.g. concatenation of 2 files). + +Database + Identical ways are combined to reduce database size (~80% fewer ways stored). + +Routing + Fix weight, height, width, length restriction routing. + Allow up to 99 waypoints to be specified instead of 9. + +Visualiser + Don't display speed limits for tracks and paths unless a value is set. + Draw all super-segments that cross the selected boundary. + +Web Pages + A few small changes, improved CSS, improved Javascript. + Changed marker colour when waypoint not selected. + +planetsplitter + Optional slim mode uses minimal memory at the expense of temporary files. + +router + Less CPU time for routing (~30% less). + +filedumper + Allow dumping individual nodes, segments and ways (for debug). + + +Version 1.1 of Routino released : Sat Jun 13 2009 +------------------------------------------------- + +Inputs + Improve parsing of OSM file (imperial units). + Ignore nodes that are missing from the input OSM file. + +Outputs + Create GPX route files as well as GPX track files. + Read in an optional copyright.txt file and include contents in output. + Make better choices about what to output in the abbreviated text file. + +Routing + Allow generating a route with intermediate waypoints. + Use preferences for highway types instead of yes/no choice. + Choice of closest node to start/finish points ensures transport allowed. + +Visualiser + Added data extraction function for viewing routing database data. + +Web Pages + Include full set of web pages for creating customised online router. + +Documentation + Included NEWS.txt file. + Included documentation for installation of web pages. + + +Version 1.0 of Routino released : Wed Apr 08 2009 +------------------------------------------------- + +First version. diff --git a/doc/OUTPUT.txt b/doc/OUTPUT.txt new file mode 100644 index 0000000..4ebd742 --- /dev/null +++ b/doc/OUTPUT.txt @@ -0,0 +1,250 @@ + Routino : Output + ================ + + + There are three different formats of output from the router, HTML, GPX + (GPS eXchange) XML format and plain text with a total of five possible + output files: + * HTML route instructions for each interesting junction. + * GPX track file containing every node. + * GPX route file with waypoints at interesting junctions. + * Plain text description with the interesting junctions. + * Plain text file with every node. + + The "interesting junctions" referred to above are junctions where the + route changes to a different type of highway, more than two highways of + the same type meet, or where the route meets but does not take a more + major highway. When the route follows a major road this definition + eliminates all junctions with minor roads. + + The output files are written to the current directory and are named + depending on the selection of shortest or quickest route. For the + shortest route the file names are "shortest.html", + "shortest-track.gpx", "shortest-route.gpx", "shortest.txt" and + "shortest-all.txt", for the quickest route the names are + "quickest.html", "quickest-track.gpx", "quickest-route.gpx", + "quickest.txt" and "quickest-all.txt". + + The HTML file and GPX files are written out according to the selected + language using the translations contained in the translations.xml + configuration file. + + +HTML Route Instructions +----------------------- + + The HTML route instructions file contains one line for each of the + interesting junctions in the route and one line for the highway that + connects them. + + An example HTML file output is below (some parts are missing, for + example the style definitions): + + + + + + + +Shortest Route +... + + +

Shortest Route

+ +
51.524677 -0.127896 +
Start:At Waypoint, head South-East + +
Follow:Russell Square for 0.391 km, 0.5 min [0.4 km, 0 minutes] +... +
Total:6.3 km, 5 minutes +
Stop:Waypoint +
+ + + + The coordinates are included in the file but are not visible because of + the style definitions. + + +GPX Track File +-------------- + + The GPX track file contains a track with all of the individual nodes + that the route passes through. + + An example GPX track file output is below: + + + + +Creator : Routino - http://www.routino.org/ + +http://creativecommons.org/licenses/by-sa/2.0/ + + + +Shortest route +Shortest route between 'start' and 'finish' waypoints + + +... + + + + + + + +GPX Route File +-------------- + + The GPX route file contains a route (ordered set of waypoints) with all + of the interesting junctions that the route passes through. + + An example GPX route file output is below: + + + + +Creator : Routino - http://www.routino.org/ + +http://creativecommons.org/licenses/by-sa/2.0/ + + + +Shortest route +Shortest route between 'start' and 'finish' waypoints +START +South-East on 'Russell Square' for 0.391 km, 0.5 min +TRIP001 +South-East on 'Russell Square' for 0.055 km, 0.1 min +... +FINISH +Total Journey 6.3 km, 5 minutes + + + + +Text File +--------- + + The text file format contains one entry for all of the interesting + junctions in the route and is intended to be easy to interpret. + + An example text file output is below: + +# Creator : Routino - http://www.routino.org/ +# Source : Based on OpenStreetMap data from http://www.openstreetmap.org/ +# License : http://creativecommons.org/licenses/by-sa/2.0/ +# +#Latitude Longitude Section Section Total Total Point Turn Bearing Highway +# Distance Duration Distance Duration Type + 51.524677 -0.127896 0.000 km 0.0 min 0.0 km 0 min Waypt +3 + 51.521815 -0.124577 0.391 km 0.5 min 0.4 km 0 min Junct +0 +3 Russell Square +... + 51.478353 -0.103561 0.598 km 0.4 min 6.2 km 5 min Junct +2 -3 Camberwell New Road (A202) + 51.478244 -0.103652 0.013 km 0.0 min 6.3 km 5 min Waypt Vassall Road + + The text file output contains a header (indicated by the lines starting + with '#') and then one line for each junction. Each line contains the + information for the route up to that point and the direction to go + next. For each of the lines the individual fields contain the + following: + + Latitude - Location of the point (degrees) + + Longitude - Location of the point (degrees) + + Section Distance - The distance travelled on the section of the journey + that ends at this point (defined on this line). + + Section Duration - The duration of travel on the section of the journey + that ends at this point (defined on this line). + + Total Distance - The total distance travelled up to this point. + + Total Duration - The total duration of travel up to this point. + + Point Type - The type of point; either a waypoint Waypt or junction + Junct. + + Turn - The direction to turn at this point (missing for the first point + since the journey has not started yet and the last point because it has + finished). This can take one of nine values between -4 and +4 defined + by: 0 = Straight, +2 = Right, -2 = Left and +/-4 = Reverse. + + Bearing - The direction to head at this point (missing for the last point + since the journey has finished). This can take one of nine values + between -4 and +4 defined by: 0 = North, +2 = East, -2 = West and +/-4 + = South. + + Highway - The name (or description) of the highway to follow (missing on + the first line). + + The individual items are separated by tabs but some of the items + contain spaces as well. + + +All Nodes Text File +------------------- + + The all nodes text file format contains one entry for each of the nodes + on the route. + + An example all nodes text file output is below: + +# Creator : Routino - http://www.routino.org/ +# Source : Based on OpenStreetMap data from http://www.openstreetmap.org/ +# License : http://creativecommons.org/licenses/by-sa/2.0/ +# +#Latitude Longitude Node Type Segment Segment Total Total Speed Bearing Highway +# Dist Durat'n Dist Durat'n + 51.524677 -0.127896 7485978* Waypt 0.000 0.00 0.00 0.0 + 51.523830 -0.126993 7485047* Junct 0.113 0.14 0.11 0.1 96 146 Woburn Place +... + 51.478353 -0.103561 7576939* Junct 0.104 0.07 6.25 5.0 96 126 Camberwell New Road (A202) + 51.478244 -0.103652 7581605 Waypt 0.013 0.01 6.26 5.0 64 207 Vassall Road + + The all nodes text file output is similar to the text file output + except that a line is printed for each of the nodes rather than just + the interesting junctions. For each of the lines the individual fields + contain the following: + + Latitude - Location of the point in degrees. + + Longitude - Location of the point in degrees. + + Node - The internal node number and an indicator "*" if the node is a + super-node. + + Type - The type of point; a waypoint Waypt, junction Junct, change of + highway Change or intermediate node Inter. + + Segment Distance - The distance travelled on the segment defined on this + line. + + Segment Duration - The duration of travel on the segment defined on this + line. + + Total Distance - The total distance travelled up to this point. + + Total Duration - The total duration of travel up to this point. + + Speed - The speed of travel on the segment defined on this line (missing + on the first line). + + Bearing - The direction that the segment defined on this line travels in + degrees (missing on the first line). + + Highway - The name (or description) of the highway segment (missing on + the first line). + + +-------- + +Copyright 2008-2010 Andrew M. Bishop. diff --git a/doc/README.txt b/doc/README.txt new file mode 100644 index 0000000..75fe606 --- /dev/null +++ b/doc/README.txt @@ -0,0 +1,147 @@ + Routino : OpenStreetMap Routing Software + ======================================== + + + Routino is an application for finding a route between two points using + the dataset of topographical information collected by + http://www.OpenStreetMap.org. + + Starting from the raw OpenStreetMap data (in the form of the '.osm' XML + files available on the internet) a custom database is generated that + contains the information useful for routing. With this database and two + points specified by latitude and longitude an optimum route (either + shortest or quickest) is determined. The route is calculated for + OpenStreetMap highways (roads, paths etc) using one of the common forms + of transport defined in OpenStreetMap (foot, bicycle, horse, motorcar, + motorbike etc). + + When processing the OpenStreetMap data the types of highways are + recorded and these set default limits on the types of traffic allowed. + More specific information about permissions for different types of + transport are also recorded as are maximum speed limits. Further + restrictions like oneway streets, weight, height, width and length + limits are also included where specified. Additionally a set of + properties of each highway are also recorded. The processing of the + input file is controlled by a configuration file which determines the + information that is used. + + When calculating a route the type of transport to be used is taken into + account to ensure that the known restrictions are followed. Each of the + different highway types can further be allowed or disallowed depending + on preferences. For each type of highway a default speed limit is + defined (although the actual speed used will be the lowest of the + default and any specified in the original data). To make use of the + information about restrictions the weight, height, width and length of + the transport can also be specified. Further preferences about road + properties (e.g. paved or not) can also be selected. + + The result of calculating the route can be presented in several + different ways. An HTML file can be produced that contains a + description of the route to take with instructions for each of the + important junctions. The contents of the file are created based on a + set of translations specified in a configuration file. The route is + also available in a GPX (GPS eXchange) XML format. format file + containing either every point and highway segment (a track file) or + just a waypoint and translated instructions for the important junctions + (a route file). Additionally there are two plain text files that + contain all data points or just the important ones (intended for + debugging and further processing). + + One of the design aims of Routino was to make the software are flexible + as possible in selecting routing preferences but also have a sensible + set of default values. Another design aim was that finding the optimum + route should be very fast and most of the speed increases come from the + carefully chosen and optimised data format. + + +Disclaimer +---------- + + The route that is calculated by this software is only as good as the + input data. + + Routino comes with ABSOLUTELY NO WARRANTY for the software itself or + the route that is calculated by it. + + +Demonstration +------------- + + A live demonstration of the router for the UK is available on the + internet: + + http://www.routino.org/uk/router.html + + The source code download available also includes a set of files that can + be used to create your own interactive map. + + The interactive map is made possible by use of the OpenLayers Javascript + library from http://www.openlayers.org/. + + +Documentation +------------- + + The algorithm used is described in the file ALGORITHM.txt and some + notes about the limitations of the data is in DATA.txt. + + The configuration files and in particular the default set of rules for + processing the OpenStreetMap data tags are described in detail in + CONFIGURATION.txt and TAGGING.txt. The format of the output files + generated are described in OUTPUT.txt. + + Detailed information about how to use the programs is available in the + file USAGE.txt and how to install it is in INSTALL.txt. + + +Status +------ + + Version 1.0 of Routino was released on 8th April 2009. + Version 1.1 of Routino was released on 13th June 2009. + Version 1.2 of Routino was released on 21st October 2009. + Version 1.3 of Routino was released on 21st January 2010. + Version 1.4 of Routino was released on 31st May 2010. + + +License +------- + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + It is important to note that for this program I have decided to use the + Affero GPLv3 instead of just using the GPL. This license adds + additional requirements to anybody who provides a networked service + using this software. + + +Copyright +--------- + + Routino is copyright Andrew M. Bishop 2008-2010. + + Contact amb@gedanken.demon.co.uk for any questions or queries. + + +Homepage +-------- + + The latest information about the program can be found on the homepage: + + http://www.routino.org/ + + +Download +-------- + + The program can be downloaded from: + + http://www.routino.org/download/ + + +-------- + +Copyright 2008-2010 Andrew M. Bishop. diff --git a/doc/TAGGING.txt b/doc/TAGGING.txt new file mode 100644 index 0000000..6c23d8c --- /dev/null +++ b/doc/TAGGING.txt @@ -0,0 +1,352 @@ + Routino : Tagging Rules + ======================= + + + The different tags and attributes in the OSM format XML that are used + by Routino are described below. + + An important change for version 1.4 of Routino is that the tags in the + input file are first processed according to a set of rules defined in a + configuration file. This means that the information presented here is + in two parts; firstly the tags that are recognised by Routino after + pre-processing and secondly the transformations in the default + configuration file. + + +Tags Recognised After Processing +-------------------------------- + + This section describes the tags that are recognised by Routino after + the tag transformations have been applied. This is therefore a much + reduced set of tags compared to the original OSM data and also includes + tags which are specific to Routino. + + In all cases of tag processing values of true, yes, 1 are recognised as + being affirmative and any other value is ignored. + + +Node Tags And Attributes +------------------------ + + None of the node tags are used but the node attributes id, latitude and + longitude of the node. The id atribute is required to associate the + node with the ways and the position attributes are required to locate + the node. + + +Way Tags And Attributes +----------------------- + + The tags from the ways in the data are the ones that provide most of + the information for routing. The id attribute is used only so that the + many segments associated with a way can be share a set of tags taken + from the way. + +The highway Tag +- - - - - - - - + + The most important tag that is used from a way is the highway tag. This + defines the type of highway that the way represents. Any way that does + not have a highway tag is discarded. + + There are more highway types defined than are used by the router. The + subset that the router uses are: + * motorway + * trunk + * primary + * secondary + * tertiary + * unclassified + * residential + * service + * track + * cycleway + * path (1) + * steps (2) + + Note 1: This changed in version 1.3 of Routino - the bridleway and + footway types were included within the path highway type. + Note 2: This changed in version 1.3 of Routino - the steps type was + separated from the footway type. + +Transport Specific Tags +- - - - - - - - - - - - + + One tag is recognised for each of the different modes of transport: + foot, horse, bicycle, wheelchair, moped, motorbike, motorcar, goods, + hgv and psv. These indicate whether the specific type of transport is + allowed on the highway or not. + +The name Tag +- - - - - - + + The name tag is used to provide the label for the highway when printing + the results. + +The ref Tag +- - - - - - + + The ref tag is used to provide the label for the highway when printing + the results. + +The junction Tag +- - - - - - - - + + The junction tag is used to check if a highway is (part of) a + roundabout. This tag is used for information to label the highway if no + other name is provided. + +The multilane Tag +- - - - - - - - - + + The multilane tag is used to identify whether a highway has multiple + lanes for traffic and this sets one of the highway properties. There is + not normally a multilane tag but one needs to be added by the tag + processing transformations. Values of true, yes, 1 are recognised. + +The paved Tag +- - - - - - - + + The paved tag is used to identify whether a highway is paved or not, + this is one of the available highway properties. A paved tag may exist + in the original data but normally the surface tag needs to be + transformed into the paved tag. + +The bridge Tag +- - - - - - - + + The bridge tag is used to identify whether a highway is a bridge and + therefore set one of the available properties. + +The tunnel Tag +- - - - - - - + + The tunnel tag is used to identify whether a highway is a tunnel and + therefore set one of the available properties. + +The oneway Tag +- - - - - - - + + The oneway tag is used to specify that traffic is only allowed to + travel in one direction. + +The maxspeed Tag +- - - - - - - - + + The maxspeed tag is used to specify the maximum speed limit on the + highway; this is always measured in km/hr in OpenStreetMap data. If the + tag value contains "mph" then it is assumed to be a value in those + units and converted to km/hr. + +The maxweight Tag +- - - - - - - - - + + The maxweight tag is used to specify the maximum weight of any traffic + on the way. In other words this must be set to the heaviest weight + allowed on the way (for example a bridge) in tonnes. If the tag value + contains "kg" then it is assumed that the value is in these units and + converted to tonnes. + +The maxheight Tag +- - - - - - - - - + + The maxheight tag is used to specify the maximum height of any traffic + on the way. In other words this must be set to the lowest height of + anything above the way (like a bridge) in metres. If the tag value + contains a measurement in feet or feet and inches then attempts are + made to convert this to metres. + +The maxwidth Tag +- - - - - - - - + + The maxwidth tag is used to specify the maximum width of any traffic on + the way. This must be set to the minimum width of the contraints at the + wayside in metres. If the tag value contains a measurement in feet or + feet and inches then attempts are made to convert this to metres. + +The maxlength Tag +- - - - - - - - - + + The maxlength tag is used to specify the maximum length of any traffic + on the way (usually from a traffic sign) in metres. If the tag value + contains a measurement in feet or feet and inches then attempts are + made to convert this to metres. + + +Relation Tags And Attributes +---------------------------- + + Currently no relation tags or attributes are used. + + +Tag Transformations +------------------- + + This section describes the set of tag transformations that are + contained in the default configuration file. The configuration file + tagging rules are applied in sequence and this section of the document + is arranged in the same order. + + +Node Tag Transformations +------------------------ + + No transformations are applicable since no node tags are recognised. + + +Way Tag Transformations +----------------------- + +Highway Defaults +- - - - - - - - + + The first part of the tag transformations is to decide on defaults for + each type of highway. This uses the highway tag in the OSM file and + maps it into one of the highway tags that are recognised by Routino, + defining the default allowed transport types and adding a number of + properties. + + The first part of the transformation is to convert the highway tag into + one that is recognised by Routino. + + Original tag Transformed tag + ------------ --------------- + bridleway path + byway track + footway path + living_street residential + minor unclassified + pedestrian path + road unclassified + services service + unsurfaced track + unpaved track + walkway path + + The type of highway also determines the defaults for the types of + transport allowed on the highway. The default assumptions are as shown + in the table below. + + Highway foot horse wheelchair bicycle moped motorbike motorcar goods hgv psv + ------- ---- ----- ---------- ------- ----- --------- -------- ----- --- --- + motorway no no no no no yes yes yes yes yes + trunk no no no yes yes yes yes yes yes yes + primary yes yes yes yes yes yes yes yes yes yes + secondary yes yes yes yes yes yes yes yes yes yes + tertiary yes yes yes yes yes yes yes yes yes yes + unclassified yes yes yes yes yes yes yes yes yes yes + residential yes yes yes yes yes yes yes yes yes yes + service yes yes yes yes yes yes yes yes yes yes + track yes yes yes yes no no no no no no + cycleway yes no yes yes no no no no no no + path yes yes(1) yes yes(1) no no no no no no + steps yes no yes no no no no no no no + + Note 1: A path allows bicycle or horse access by default only if + actually labelled as a highway of type "bridleway" or certain values of + the designation tag (described below). + + Finally for the highway tag a number of properties are added depending + on the highway type. + + Highway Properties + ------- ---------- + motorway paved, oneway, multilane + trunk paved + primary paved + secondary paved + tertiary paved + unclassified paved + residential paved + service paved + track paved (1) + cycleway paved + path paved (2) + steps + + Note 1: A track is paved only if it is tagged as tracktype=grade1. + Note 2: A path is paved only if it was originally tagged as + highway=walkway or highway=pedestrian. + +Generic Access Permissions +- - - - - - - - - - - - - + + The access tag is used to specify the default access restrictions on + the way. If the tag value is "no" or "private" then all transport types + are denied access (later tag transformation rules may add specific + transport types back again). + +Other Access Permissions +- - - - - - - - - - - - + + A tag named vehicle means any of the bicycle, moped, motorbike, + motorcar, goods, hgv and psv transport types. A tag named motor_vehicle + is transformed to mean any vehicle except a bicycle. + + The designation tag is used as an alternative method of identifying the + legal right of way on a path (in the UK at least). The tag + transformations convert these tags into a set of allowed transport + types as shown below. + + Designation tag Equivalent access permissions + --------------- ----------------------------- + bridleway or foot=yes, wheelchair=yes, horse=yes, + public_bridleway bicycle=yes + restricted_byway foot=yes, wheelchair=yes, horse=yes, + bicycle=yes + byway foot=yes, wheelchair=yes, horse=yes, + bicycle=yes, moped=yes, motorbike=yes, + motorcar=yes + footpath or foot=yes, wheelchair=yes + public_footpath + +Specific Access Permissions +- - - - - - - - - - - - - - + + The final part of the access permissions is to use the specific + transport type tags. + + One tag is recognised for each of the different modes of transport: + foot, horse, bicycle, wheelchair, moped, motorbike, motorcar, goods, + hgv and psv. These indicate whether the specific type of transport is + allowed on the highway or not. + +Highway Properties +- - - - - - - - - + + If there is a surface tag then the highway is assumed to be unpaved + unless the tag value matches one of the following: paved, asphalt or + concrete. + + Support for the obsolete paved tag is also provided and the highway is + paved if this is set to a true value. + + The lanes tag is used to identify whether a highway has multiple lanes + for traffic or not (the number of lanes is not important in this case, + only whether it is more than one) this sets one of the highway + properties. + + The bridge and tunnel tags are copied directly from the input to the + output. + +Highway Restrictions +- - - - - - - - - - + + The oneway, maxspeed, maxweight, maxheight, maxwidth and maxlength are + copied directly from the input to the output without modification. + +Highway Names and References +- - - - - - - - - - - - - - + + The name and ref tags are copied directly from the input to the output. + + +Relation Tag Transformations +---------------------------- + + No transformations are applicable since no relation tags are recognised. + + +-------- + +Copyright 2008-2010 Andrew M. Bishop. diff --git a/doc/USAGE.txt b/doc/USAGE.txt new file mode 100644 index 0000000..48721bd --- /dev/null +++ b/doc/USAGE.txt @@ -0,0 +1,425 @@ + Routino : Usage + =============== + + + There are four programs that make up this software. The first one takes + the planet.osm datafile from OpenStreetMap (or other source of data + using the same formats) and converts it into a local database. The + second program uses the database to determine an optimum route between + two points. The third program allows visualisation of the data and + statistics to be extracted. The fourth program is a test program for + the tag transformations. + + +planetsplitter +-------------- + + This program reads in the OSM format XML file and splits it up to + create the database that is used for routing. + + Usage: planetsplitter [--help] + [--dir=] [--prefix=] + [--slim] [--sort-ram-size=] + [--tmpdir=] + [--parse-only | --process-only] + [--max-iterations=] + [--tagging=] + [ ...] + + --help + Prints out the help information. + + --dir= + Sets the directory name in which to save the results. Defaults + to the current directory. + + --prefix= + Sets the filename prefix for the files that are created. + Defaults to no prefix. + + --slim + Selects a mode of operation that uses less memory and will + therefore work where virtual memory is very limited or + unavailable. Selecting this option will cause raw data to be + held in disk files with only indexes in RAM. Not using this + option will still use disk files but only for sequential access + and the files are memory mapped for random access. + + --sort-ram-size= + Specifies the amount of RAM (in MB) to use for sorting the data. + If not specified then 64 MB will be used if the '--slim' option + is specified or 256 MB otherwise. + + --tmpdir= + Specifies the name of the directory to store the temporary disk + files. If not specified then it defaults to either the value of + the --dir option or the current directory. + + --parse-only + Parse the input files and store them in a temporary file but + don't process the data into a routing database. + + --process-only + Don't read in any files but process the existing temporary file + into the routing database. + + --max-iterations= + The maximum number of iterations to use when generating + super-nodes and super-segments. Defaults to 10 which is normally + enough. + + --tagging= + The name of the XML file containing the tagging rules (defaults + to 'tagging.xml' with '--dirname' and '--prefix' options). + + ... + Specifies the filename(s) to read data from, by default data is + read from the standard input. + + Note: In version 1.4 of Routino the --transport, --not-highway and + --not-property options have been removed. The same functionality can be + achieved by editing the tagging rules file to not output unwwanted + data. + + Example usage: + +./planetsplitter --dir=data --prefix=gb great_britain.osm + + This will generate the output files 'data/gb-nodes.mem', + 'data/gb-segments.mem' and 'data/gb-ways.mem'. + + +router +------ + + This program performs the calculation of the optimum routes using the + database generated by the planetsplitter program. + + Usage: router [--help | --help-profile | --help-profile-xml | + --help-profile-json | --help-profile-perl ] + [--dir=] [--prefix=] + [--profiles=] [--translations=] + [--exact-nodes-only] + [--quiet] + [--output-html] + [--output-gpx-track] [--output-gpx-route] + [--output-text] [--output-text-all] + [--output-none] + [--profile=] + [--transport=] + [--shortest | --quickest] + --lon1= --lat1= + --lon2= --lon2= + [ ... --lon99= --lon99=] + [--highway-= ...] + [--speed-= ...] + [--property-= ...] + [--oneway=(0|1)] + [--weight=] + [--height=] [--width=] [--length=] + + --help + Prints out the help information. + + --help-profile + Prints out the selected transport profile (type, speed limits, + highway preferences etc.) + + --help-profile-xml + Prints out all the loaded profiles as an XML file in the same + format that can be loaded in. + + --help-profile-json + Prints out all the loaded profiles in JavaScript Object Notation + (JSON) format for use in the interactive webpage. + + --help-profile-perl + Prints out all the loaded profiles as a Perl object for use in + the router CGI. + + --dir= + Sets the directory name in which to read the local database. + Defaults to the current directory. + + --prefix= + Sets the filename prefix for the files in the local database. + Defaults to no prefix. + + --profiles= + Sets the filename containing the list of profiles in XML format. + If the file doesn't exist then dirname, prefix and + "profiles.xml" will be combined and used, if that doesn't exist + then the command line must contain all relevant profile + information. + + --translations= + Sets the filename containing the list of translations in XML + format for the output files. If the file doesn't exist then + dirname, prefix and "translations.xml" will be combined and + used, if that doesn't exist then no file will be read and no + language can be selected. + + --exact-nodes-only + When processing the specified latitude and longitude points only + select the nearest node instead of finding the nearest point + within a segment (quicker but less accurate unless the points + are already near nodes). + + --quiet + Don't generate any screen output while running (useful for + running in a script). + + --language= + Select the language specified from the file of translations. If + this option is not given and the file exists then the first + language in the file will be used. If this option is not given + and no file exists the compiled-in default language (English) + will be used. + + --output-html + --output-gpx-track + --output-gpx-route + --output-text + --output-text-all + Generate the selected output file formats (HTML, GPX track file, + GPX route file, plain text route and/or plain text with all + nodes). If no output is specified then all are generated, + specifying any automatically disables those not specified. + + --output-none + Do not generate any output or read in any translations files. + + --profile= + Specifies the name of the profile to use. + + --transport= + Select the type of transport to use, can be set to: + + + foot = Foot + + horse = Horse + + wheelchair = Wheelchair + + bicycle = Bicycle + + moped = Moped (Small motorbike, limited speed) + + motorbike = Motorbike + + motorcar = Motorcar + + goods = Goods (Small lorry, van) + + hgv = HGV (Heavy Goods Vehicle - large lorry) + + psv = PSV (Public Service Vehicle - bus, coach) + + Defaults to 'motorcar', this option also selects the default + profile information if the '--profile' option is not given and a + profile matching the transport name is found. + + --shortest + Find the shortest route between the waypoints. + + --quickest + Find the quickest route between the waypoints. + + --lon1=, --lat1= + --lon2=, --lat2= + ... --lon99=, --lat99= + The location of the waypoints that make up the start, middle and + end points of the route. Up to 99 waypoints can be specified and + the route will pass through each of the specified ones in + sequence. The algorithm will use the closest node or point + within a segment that allows the specified traffic type. + + --highway-= + Selects the percentage preference for using each particular type + of highway. The value of can be selected from: + + + motorway = Motorway + + trunk = Trunk + + primary = Primary + + secondary = Secondary + + tertiary = Tertiary + + unclassified = Unclassified + + residential = Residential + + service = Service + + track = Track + + cycleway = Cycleway + + path = Path + + steps = Steps + + Default value depends on the profile selected by the --transport + option. + + --speed-= + Selects the speed limit in km/hour for each type of highway. + Default value depends on the profile selected by the --transport + option. + + --property-= + Selects the percentage preference for using each particular + highway property The value of can be selected from: + + + paved = Paved (suitable for normal wheels) + + multilane = Multiple lanes + + bridge = Bridge + + tunnel = Tunnel + + Default value depends on the profile selected by the --transport + option. + + --oneway=[0|1] + Selects if the direction of oneway streets are to be obeyed + (useful to not obey them when walking). Default value depends on + the profile selected by the --transport option. + + --weight= + Specifies the weight of the mode of transport in tonnes; ensures + that the weight limit on the highway is not exceeded. Default + value depends on the profile selected by the --transport option. + + --height= + Specifies the height of the mode of transport in metres; ensures + that the height limit on the highway is not exceeded. Default + value depends on the profile selected by the --transport option. + + --width= + Specifies the width of the mode of transport in metres; ensures + that the width limit on the highway is not exceeded. Default + value depends on the profile selected by the --transport option. + + --length= + Specifies the length of the mode of transport in metres; ensures + that the length limit on the highway is not exceeded. Default + value depends on the profile selected by the --transport option. + + The meaning of the parameter in the command line options + is slightly different for the highway preferences and the property + preferences. For the highway preference consider the choice between two + possible highways between the start and finish when looking for the + shortest route. If highway A has a preference of 100% and highway B has + a preference of 90% then highway A will be chosen even if it is up to + 11% longer (100/90 = 111%). For the highway properties each highway + either has a particular property or not. If the preference for highways + with the property is 60% then the preference for highways without the + property is 40%. The overall preference for the highway is the product + of the highway preference and the preference for highways with (or + without) each property that the highway has (or doesn't have). + + Example usage (motorbike journey, scenic route, not very fast): + + ./router --dir=data --prefix=gb --transport=motorbike --highway-motorway=0 \ + --highway-trunk=0 --speed-primary=80 --speed-secondary=80 --quickest + + This will use the files 'data/gb-nodes.mem', 'data/gb-segments.mem' and + 'data/gb-ways.mem' to find the quickest route by motorbike not using + motorways or trunk roads and not exceeding 80 km/hr. + + +filedumper +---------- + + This program is used to extract statistics from the database, extract + particular information for visualisation purposes or for dumping the + database contents. + + Usage: filedumper [--help] + [--dir=] [--prefix=] + [--statistics] + [--visualiser --latmin= --latmax= + --lonmin= --lonmax= + --data=] + [--dump [--node= ...] + [--segment= ...] + [--way= ...]] + [--dump-osm [--no-super] + [--latmin= --latmax= + --lonmin= --lonmax=]] + + --help + Prints out the help information. + + --dir= + Sets the directory name in which to read the local database. + Defaults to the current directory. + + --prefix= + Sets the filename prefix for the files in the local database. + + --statistics + Prints out statistics about the database files. + + --visualiser + Selects a data visualiser mode which will output a set of data + according to the other parameters below. + + --latmin= --latmax= + The range of latitudes to print the data for. + + --lonmin= --lonmax= + The range of longitudes to print the data for. + + --data= + The type of data to output, can be selected + from: + + o junctions = segment count at each junction. + o super = super-node and super-segments. + o oneway = oneway segments. + o speed = speed limits. + o weight = weight limits. + o height = height limits. + o width = width limits. + o length = length limits. + + --dump + Selects a data dumping mode which allows looking at individual + items in the databases (specifying 'all' instead of a number + dumps all of them). + + --node= + Prints the information about the selected node number + (internal number, not the node id number in the original + source file). + + --segment= + Prints the information about the selected segment number. + + --way= + Prints the information about the selected way number + (internal number, not the way id number in the original + source file). + + --osm-dump + Dumps the contents of the database as an OSM format XML file, + the whole database will be dumped unless the latitude and + longitude ranges are specified. + + --no-super + The super segments will not be output. + + --latmin= --latmax= + The range of latitudes to dump the data for. + + --lonmin= --lonmax= + The range of longitudes to dump the data for. + +tagmodifier +----------- + + This program is used to run the tag transformation process on an OSM + XML file for test purposes. + + Usage: tagmodifier [--help] + [--tagging=] + [] + + --help + Prints out the help information. + + --tagging= + The name of the XML file containing the tagging rules (defaults + to 'tagging.xml' in the current directory). + + ... + Specifies the filename to read data from, by default data is + read from the standard input. + + +-------- + +Copyright 2008-2010 Andrew M. Bishop. diff --git a/doc/html/algorithm.html b/doc/html/algorithm.html new file mode 100644 index 0000000..cec599f --- /dev/null +++ b/doc/html/algorithm.html @@ -0,0 +1,266 @@ + + + + + + +Routino : Algorithm + + + + + + + + +
+ +

Routino : Algorithm

+ +
+
+ + + + + +
+ +

Algorithms

+ +This page describes the development of the algorithm that is used in Routino for +finding routes. + +

Simplest Algorithm

+ +The algorithm to find a route is fundamentally simple: Start at the beginning, +follow all possible routes and keep going until you reach the end. +

+While this method does work, it isn't fast. To be able to find a route quickly +needs a different algorithm, one that can find the correct answer without +wasting time on routes that lead nowhere. + +

Improved Algorithm

+ +The simplest way to do this is to follow all possible segments from the starting +node to the next nearest node (an intermediate node in the complete journey). +For each node that is reached store the shortest route from the starting node +and the length of that route. The list of intermediate nodes needs to be +maintained in order of shortest overall route on the assumption that there is a +straight line route from here to the end node. +
+At each point the intermediate node that has the shortest potential overall +journey time is processed before any other node. From the first node in the +list follow all possible segments and place the newly discovered nodes into the +same list ordered in the same way. This will tend to constrain the list of +nodes examined to be the ones that are between the start and end nodes. If at +any point you reach a node that has already been reached by a longer route then +you can discard that route since the newly discovered route is shorter. +Conversely if the previously discovered route is shorter then discard the new +route. +
+At some point the end node will be reached and then any routes with potential +lengths longer than this actual route can be immediately discarded. The few +remaining potential routes must be continued until they are found to be shorter +or have no possibility of being shorter. The shortest possible route is then +found. +

+At all times when looking at a node only those segments that are possible by the +chosen means of transport are followed. This allows the type of transport to be +handled easily. When finding the quickest route the same rules apply except +that criterion for sorting is the shortest potential route (assuming that from +each node to the end is the fastest possible type of highway). +

+This method also works, but again it isn't very fast. The problem is that the +complexity is proportional to the number of nodes or segments in all routes +examined between the start and end nodes. Maintaining the list of intermediate +nodes in order is the most complex part. + +

Final Algorithm

+ +The final algorithm that is implemented in the router is basically the one above +but with an important difference. Instead of finding a long route among a data +set of 8,000,000 nodes (number of highway nodes in UK at beginning of 2010) it +finds one long route in a data set of 1,000,000 nodes and a few hundred very +short routes in the full data set. Since the time taken to find a route is +proportional to the number of nodes the main route takes 1/10th of the time and +the very short routes take almost no time at all. +

+The solution to making the algorithm fast is therefore to discard most of the +nodes and only keep the interesting ones. In this case a node is deemed to be +interesting if it is the junction of two segments with different properties. In +the algorithm these are classed as super-nodes. Starting at each +super-node a super-segment is generated that finishes on another +super-node and contains the shortest path along segments with identical +properties (and these properties are inherited by the super-segment). The point +of choosing the shortest route is that since all segments considered have +identical properties they will be treated identically when properties are taken +into account. This decision making process can be repeated until the only the +most important and interesting nodes remain. +

+Original data
+Iteration 1
+Iteration 2
+

+To find a route between a start and finish point now comprises the following +steps (assuming a shortest route is required): +

    +
  1. Find all shortest routes from the start point along normal segments and + stopping when super-nodes are reached. +
  2. Find all shortest routes from the end point backwards along normal + segments and stopping when super-nodes are reached. +
  3. Find the shortest route along super-segments from the set of super-nodes + in step 1 to the set of super-nodes in step 2 (taking into account the lengths + found in steps 1 and 2 between the start/finish super-nodes and the ultimate + start/finish point). +
  4. For each super-segment in step 3 find the shortest route between the two + end-point super-nodes. +
+This multi-step process is considerably quicker than using all nodes but gives a +result that still contains the full list of nodes that are visited. There are +some special cases though, for example very short routes that do not pass +through any super-nodes, or routes that start or finish on a super-node. In +these cases one or more of the steps listed can be removed or simplified. + +

Routing Preferences

+ +One of the important features of Routino is the ability to select a route that +is optimum for a set of criteria such as preferences for each type of highway, +speed limits and other restrictions and highway properties. +

+All of these features are handled by assigning a score to each segment while +calculating the route and trying to minimise the score rather than simply +minimising the length. +

+
Segment length +
When calculating the shortest route the length of the segment is the + starting point for the score. +
Speed preference +
When calculating the quickest route the time taken calculated from the + length of the segment and the lower of the highway's own speed limit and the + user's speed preference for the type of highway is the starting point for the + score. +
Oneway restriction +
If a highway has the oneway property in the opposite direction to the + desired travel and the user's preference is to obey oneway restrictions then + the segment is ignored. +
Weight, height, width & length limits +
If a highway has one of these limits and its value is less than the user's + specified requirement then the segment is ignored. +
Highway preference +
The highway preference specified by the user is a percentage, these are + scaled so that the most preferred highway type has a weighted preference of + 1.0 (0% always has a weighted preference of 0.0). The calculated score for a + segment is divided by this weighted preference. +
Highway properties +
The other highway properties are specified by the user as a percentage and + each highway either has that property or not. The user's property preference + is scaled into the range 0.0 (for 0%) to 2.0 (for 100%) to give a weighted + preference, a second "non-property" weighted preference is calcuated in the + same way after subtracting the user's preference from 100%. If a segment has + this property then the calculated score is divided by the weighted preference, + if the segment does not have this property then it is divided by the + non-property weighted preference. +
+ +

Implementation

+ +The hardest part of implementing this router is the data organisation. The +arrangement of the data to minimise the number of operations required to follow +a route from one node to another is much harder than designing the algorithm +itself. +

+The final implementation uses a separate table for nodes, segments and ways. +Each table individually is implemented as a C-language data structure that is +written to disk by a program which parses the OpenStreetMap XML data file. In +the router these data structures are memory mapped so that the operating system +handles the problems of loading the needed data blocks from disk. +

+Each node contains a latitude and longitude and they are sorted geographically +so that converting a latitude and longitude coordinate to a node is fast as well +as looking up the coordinate of a node. The node also contains the location in +the array of segments for the first segment that uses that node. +
+Each segment contains the location of the two nodes as well as the way that the +segment came from. The location of the next segment that uses one of the two +nodes is also stored; the next segment for the other node is the following one +in the array. The length of the segment is also pre-computed and stored. +
+Each way has a name, a highway type, a list of allowed types of traffic, a speed +limit, any weight, height, width or length restrictions and the highway +properties. +

+The super-nodes are mixed in with the nodes and the super-segments are mixed in +with the segments. For the nodes they are the same as the normal nodes, so just +a flag is needed to indicate that they are super. The super-segments are in +addition to the normal segments so they increase the database size (by about +10%) and are also marked with a flag. + +

Practicalities

+ +At the time of writing (April 2010) the OpenStreetMap data for Great Britain +(taken from +GeoFabrik +) contains: +
    +
  • 14,675,098 nodes +
      +
    • 8,767,521 are highway nodes +
    • 1,120,297 are super-nodes +
    +
  • 1,876,822 ways +
      +
    • 1,412,898 are highways +
        +
      • 9,316,328 highway segments +
      • 1,641,009 are super-segments +
      +
    +
  • 60,572 relations +
+ +The database files when generated are 41.5 MB for nodes, 121.6 MB for segments +and 12.6 MB for ways and are stored uncompressed. By having at least 200 MB or +RAM available the routing can be performed with no disk accesses (once the data +has been read once). + + +
+ + + + + + + + + + + + diff --git a/doc/html/configuration.html b/doc/html/configuration.html new file mode 100644 index 0000000..98fa009 --- /dev/null +++ b/doc/html/configuration.html @@ -0,0 +1,256 @@ + + + + + + +Routino : Configuration + + + + + + + + +
+ +

Routino : Configuration

+ +
+
+ + + + + +
+ +

XML Configuration Files

+ +New in version 1.4 of Routino are the use of configuration files to allow more +information to be provided to the programs at run-time. The configuration files +that are used are: +
    +
  • Tagging transformation rules for the planetsplitter program. +
  • Routing profiles for the router program. +
  • Output translations for the router program. +
+ +In keeping with the nature of the input and output files the configuration files +are also XML files. Each of the files uses a custom defined XML schema and an +XSD file is provided for each of them. + +

Tag Transformation Rules

+ +The default name of the tagging transformation rules XML configuration file +is tagging.xml in the same directory as the generated database files. +Other filenames can be specified on the command line using +the --tagging option. When processing the input it is possible to have +a different set of tagging rules for each file; for example different rules for +different countries. + +

+ +The tagging rules allow modifying the highway tags in the source file so that +the routing can be performed on a simpler set of tags. This removes the special +case tagging rules from the source code into the configuration file where they +can be easily modified. Part of the provided tagging.xml file showing the rules +for motorway_link and motorway highway types. + +

+<?xml version="1.0" encoding="utf-8"?>
+<routino-tagging>
+
+  <way>
+
+    <if k="highway" v="motorway_link">
+      <set v="motorway"/>
+    </if>
+
+    <if k="highway" v="motorway">
+      <output k="highway"/>
+
+      <output k="motorbike"  v="yes"/>
+      <output k="motorcar"   v="yes"/>
+      <output k="goods"      v="yes"/>
+      <output k="hgv"        v="yes"/>
+      <output k="psv"        v="yes"/>
+
+      <output k="paved"      v="yes"/>
+      <output k="multilane"  v="yes"/>
+      <output k="oneway"     v="yes"/>
+    </if>
+...
+  <way>
+
+</routino-tagging>
+
+ +The rules all have the same format; an if element for matching the +input and some set or output elements to either change the +input tags or create an output tag. The k and v attributes +have the same meaning as the attributes with the same names in the OSM XML file +- the tag key and tag value. + +

+ +An if rule that has both k and v specified is only +applied if a tag exists in the input that matches both. An if rule +that has only the k attribute is applied if a tag with that key exists +and an if rule that has only the v attribute is applied to all +tags with that value. + +

+ +For the set and output elements the tag that is created in the +input or output tag set uses the k and v attributes specified. +If one or both are not specified then the original ones are used. + + +

Routing Profiles

+ +The default name of the routing profiles XML configuration file +is profiles.xml in the same directory as the database files. Other +filenames can be specified on the command line using the --tagging +option. + +

+ +The purpose of this configuration file is to allow easy modification of the +routing parameters so that they do not all need to be specified on the command +line. In versions of Routino before version 1.4 the default routing parameters +(preferred highways, preferred speeds etc) were contained in the source code, +now they are in a configuration file. When calculating a route +the --profile option selects the named profile from the configuration +file. + +

+ +Part of the provided profiles.xml file showing the parameters for transport on +foot is shown below: + +

+<?xml version="1.0" encoding="UTF-8" ?>
+<routino-profiles>
+
+  <profile name="foot" transport="foot">
+    <speeds>
+...
+      <speed highway="cycleway"      kph="4" />
+      <speed highway="path"          kph="4" />
+      <speed highway="steps"         kph="4" />
+    </speeds>
+    <preferences>
+...
+      <preference highway="cycleway"      percent="95" />
+      <preference highway="path"          percent="100" />
+      <preference highway="steps"         percent="80" />
+    </preferences>
+    <properties>
+      <property type="paved"      percent="50" />
+      <property type="multilane"  percent="25" />
+      <property type="bridge"     percent="50" />
+      <property type="tunnel"     percent="50" />
+    </properties>
+    <restrictions>
+      <oneway obey="0" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+  <profile name="horse" transport="horse">
+...
+  </profile>
+...
+</routino-profiles>
+
+ + +

Output Translations

+ +The default name of the output translations XML configuration file +is translations.xml in the same directory as the database files. Other +filenames can be specified on the command line using the --translations +option. + +

+ +The generated HTML and GPX output files (described in the next section) are +created using the fragments of text that are defined in this file. Additional +languages can be added to the file and are selected using +the --language option to the router. If no language is specified the +first one in the file is used. + +

+ +Part of the provided translations.xml file showing some of the English language +(en) translations is shown below: + +

+<?xml version="1.0" encoding="utf-8"?>
+<routino-translations>
+
+  <language lang="en">
+...
+    <turn direction="-4" string="Very sharp left" />
+    <turn direction="-3" string="Sharp left" />
+    <turn direction="-2" string="Left" />
+...
+    <heading direction="-4" string="South" />
+    <heading direction="-3" string="South-West" />
+    <heading direction="-2" string="West" />
+...
+    <route type="shortest" string="Shortest" />
+    <route type="quickest" string="Quickest" />
+    <output-html>
+...
+    </output-html>
+    <output-gpx>
+...
+    </output-gpx>
+  </language>
+</routino-translations>
+
+ +
+ + + + + + + + + + + + diff --git a/doc/html/data.html b/doc/html/data.html new file mode 100644 index 0000000..52f74aa --- /dev/null +++ b/doc/html/data.html @@ -0,0 +1,165 @@ + + + + + + +Routino : Data + + + + + + + + +
+ +

Routino : Data

+ +
+
+ + + + + +
+ +

Data

+ +A router relies on data to be able to find a route. + +

OpenStreetMap Data

+ +The data that is collected by the OpenStreetMap project consists of +nodes, ways and relations. +
+
Node +
A node is a point that has a latitude and longitude and attributes that + describe what type of point it is (part of a way or a place of interest for + example). +
Way +
A way is a collection of nodes that when joined together define something + (for example a road, a ralway, a boundary, a building, a lake etc). The + ways also have attributes that define them (speed limits, type of road and + restrictions for example). +
Relation +
A relation is a collection of items (usually ways) that are related to + each other for some reason (highways that make up a route for example). +
+ +The +OpenStreetMap Wiki +explains the data much better than I can. + +

Router Data

+ +The information that is needed by a routing algorithm is only a subset of the +information that is collected by the OpenStreetMap project. For routing what is +required is information about the location of roads (or other highways), the +connections between the highways and the properties of those highways. +
+
Location of highways (nodes) +
The locations of things is provided by the nodes from the OpenStreetMap + data. The nodes are the only things that have coordinates in + OpenStreetMap and everything else is made up by reference to them. Not + all of the nodes are useful, only the ones that are part of highways. The + location of the nodes is stored but none of the other attributes are + currently used by the router. +
Location of highways (ways) +
The location of the highways is defined in the OpenStreetMap data by the + ways. Only the highway ways are useful and the other ways are discarded. + What remains is lists of nodes that join together to form a section of + highway. This is further split into segments which are + individual parts of a way connected by two nodes. +
Properties of highways (tags) +
The ways that belong to highways are extracted from the data in the + previous step and for each way the useful information for routing is + stored. For the router the useful information is the type of highway, the + speed limit, the allowed types of transport and other restrictions + (one-way, min height, max weight etc). +
Connections between highways +
The connections between highways are defined in the OpenStreetMap data by + ways that share nodes. Since the ways may join in the middle and not just + the ends it is the segments defined above that are not part of the + OpenStreetMap data that are most important. +
+ +The information that is extracted from the OpenStreetMap data is stored in an +optimised way that allows the routing to be performed quickly. + +

Interpreting Data Tags

+ +The tags are the information that is attached to the nodes and ways in +OpenStreetMap. The router needs to interpret these tags and use them when +deciding what type of traffic can use a highway (for example). +

+ +There are no well defined rules in OpenStreetMap about tagging, but there is +guidance on the +OpenStreetMap Wiki "Map_Features" +page. This describes a set of recommended tags but these are not universally used +so it is up to each application how to interpret them. +

+ +The tagging rules that the router +uses are very important in controlling how the router works. With Routino the +data tags can be modified when the data is imported to allow customisation of +the information used for routing. + + +

Problems With OpenStreetMap Data

+ +The route that can be found is only as good as the data that is available. This +is not intended as a criticism of the OpenStreetMap data; it is generally good. +

+There are some problems that are well known and which affect the router. For +example highways might be missing because nobody has mapped them. A highway may +be wrongly tagged with incorrect properties, or a highway might be missing +important tags for routing (e.g. speed limits). There can also be problems +with highways that should join but don't because they do not share nodes. +

+A lot of these problems can be found using the interactive data visualiser that +uses the same Routino rouing database. + + +

+ + + + + + + + + + + + diff --git a/doc/html/example0.png b/doc/html/example0.png new file mode 100644 index 0000000..4401486 Binary files /dev/null and b/doc/html/example0.png differ diff --git a/doc/html/example1.png b/doc/html/example1.png new file mode 100644 index 0000000..be0048c Binary files /dev/null and b/doc/html/example1.png differ diff --git a/doc/html/example2.png b/doc/html/example2.png new file mode 100644 index 0000000..c4746d8 Binary files /dev/null and b/doc/html/example2.png differ diff --git a/doc/html/index.html b/doc/html/index.html new file mode 100644 index 0000000..2450127 --- /dev/null +++ b/doc/html/index.html @@ -0,0 +1,124 @@ + + + + + + +Routino : Documentation + + + + + + + + +
+ +

Routino : Documentation

+ +
+
+ + + + + +
+ + +

Data

+ +A good router relies on good data and the +OpenStreetMap +data is a good source. There are however a number of things that need to be +considered about +the data used. + + +

Tagging

+ +In addition to the raw data the way that are tags are used is also important. +With Routino the +tagging rules +are contained in a configuration file and can easily be customised to change the +interpretation of each tag. + + +

Program Usage

+ +There are four programs that make up this software, two create the routing +database and use the information in it and the other two perform additional functions. +Full instructions +for using the four programs are provided. + + +

Configuration Files

+ +When the programs are run they read in one or more +configuration files. +These files contain information about the routing preferences (types of highways, +prefered speeds etc), tagging rules and translation information for the outputs. + + +

Output Files

+ +The final result of running the router is one or more +output files +that contain the calculated route. + + +

Algorithm

+ +The algorithm that is used by +Routino takes the OpenStreetMap data and creates a local database of the +important information for rapid routing. + + +

Installation

+ +The Routino source code comes with a set of files that can be used to create +a working server very easily. The full information about +installation +describes how to compile the programs and install them. + + +
+ + + + + + + + + + + + diff --git a/doc/html/installation.html b/doc/html/installation.html new file mode 100644 index 0000000..faa752f --- /dev/null +++ b/doc/html/installation.html @@ -0,0 +1,243 @@ + + + + + + +Routino : Installation + + + + + + + + +
+ +

Routino : Installation

+ +
+
+ + + + + +
+ + +

Compilation

+ +This program has been written to run on Linux, no cross-platform compatibility +has been specifically included but on the other hand nothing platform specific +has been knowingly included either. + +

+ +Any information on improving the compilation process on anything other than +32-bit x86 Linux is welcome. + +

+ +No external libraries are required and the programs are written in standard C +language. + +

+ +To compile the programs just type 'make'. + + +

Installation

+ +After compilation the executable files are copied into the directory +web/bin and the default XML configuration files are copied into the +directory web/data. This is in preparation for using the supplied +example web pages but is also a useful location to copy the files from for +normal use. + +

+ +The executable files are called planetsplitter, router and +filedumper (also tagmodifier for debugging tag modifications). +They can be copied to any location and need no special installation environment. + +

+ +The default configuration files are called profiles.xml, +tagging.xml and translations.xml. The names of the +configuration files can be specified on the command line but by default are also +looked for in the directory that contains the routing database. + + +

Example Web Page

+ +The directory web contains a set of files that can be used to create a +working set of web pages with interfaces to the routing algorithm. + +

+ +The files in the web directory will require copying to a location that +is accessible by a web server. After copying the files some of them need to be +edited; search through the files for lines that contain the words "EDIT THIS" +and make appropriate edits. The files that need editing are paths.pl +(to set the directory paths) and router.js and visualiser.js +to limit the range of the visible map (latitude, longitude and zoom). + + +

Configuration of web files

+ +The assumption in this description is that the whole of the directory called +web is copied into a directory that is accessible by an Apache web +server. + +

+ +This is not a secure configuration but an easy one to configure. +
+Only the directory www should be accessible by the web server. +
+Do not use this configuration unmodified in a public web server. + +

+ +The directory structure is as follows: + +

+   web/
+    |
+    + /bin/                    <- The Routino executable files (when compiled).
+    |
+    + /data/                   <- The Routino database and default configuration
+    |                             files.
+    |
+    + /results/                <- An empty directory to store the results.
+    |
+    + /www/                    <- The files that must be available to the web
+        |                         server are below this level.
+        |
+        + /openlayers/         <- A directory to hold the OpenLayers scripts.
+        |
+        + /routino/            <- The main HTML, Javascript, CSS and CGI files.
+            |
+            + /documentation/  <- The HTML version of the Routino documentation.
+
+ +The directory bin will be filled by running the compilation process. +For a secure installation the bin directory should be outside of the +web server, the file www/routino/paths.pl contains the path to +the bin directory. + +

+ +The directory data must contain the Routino database and is also the +default location for the configuration files. The routing database is created +by downloading the OSM files for the region of interest and running the +planetsplitter program. There is a script in the directory that will download +the OSM files and create the required database. The script should be edited to +set the names of the files to be downloaded. For a secure installation +the data directory should be outside of the web server, the +file www/routino/paths.pl contains the path to the data +directory. + +

+ +The directory results is a temporary directory that it used to hold the +GPX and text files generated by the Routino router. The directory must be +writable by the web server process since it is the CGI scripts that are run by +the web server that writes the results here. For a secure installation +the results directory should be outside of the web server, the file +www/routino/paths.pl contains the path to the results directory. + +

+ +The directory www and its sub-directories are the only ones that need +to be within the web server accessible directory. + +

+ +The directory www/openlayers must be filled with the openlayers +Javascript library that can be downloaded from http://www.openlayers.org/. +(This version of Routino has been tested with OpenLayers library version 2.9.1). +The files must be installed so that the file www/openlayers/OpenLayers.js +and the directories www/openlayers/img/, www/openlayers/theme/ +all exist. There is a script in the directory that will automatically download +the files, create an optimised "OpenLayers.js" and copy the files to the required +locations. + +

+ +The directory www/routino contains the main HTML, Javascript and CSS +files as well as the CGI scripts that perform the server-side routing functions. +The description below lists all of the files that contain editable information. + +

+
paths.pl +
This contains the names of the directories that contain the executable + files, router database and temporary results. +
router.pl +
This file contains the filename prefix for the routing database files + (only needed if planetsplitter is run with the --prefix option). +
router.js +
The parameters in this file control the boundary of the visible map + (defaults to UK), the minimum and maximum zoom levels (defaults to between + 4 and 15 inclusive) and the source of map tiles (defaults to the main + OpenStreetMap tile server). +
visualiser.js +
The same parameters as in router.js are in this file. +
+ +

+ +The directory www/routino/documentation contains the HTML version of +the Routino documentation. + + +

Configuration of web server

+ +The file www/routino/.htaccess contains all of the Apache configuration +options that are required to get the example web pages running. The only +problem is that because of the way that the AllowOverride option works +one of the configuration options has been commented out. This must be enabled +in the main Apache server configuration file. + + +
+ + + + + + + + + + + + diff --git a/doc/html/output.html b/doc/html/output.html new file mode 100644 index 0000000..566d4ac --- /dev/null +++ b/doc/html/output.html @@ -0,0 +1,364 @@ + + + + + + +Routino : Output + + + + + + + + +
+ +

Routino : Output

+ +
+
+ + + + + +
+ +

Router Output

+ +There are three different formats of output from the router, HTML, +GPX (GPS eXchange) XML format +and plain text with a total of five possible output files: +
    +
  • HTML route instructions for each interesting junction. +
  • GPX track file containing every node. +
  • GPX route file with waypoints at interesting junctions. +
  • Plain text description with the interesting junctions. +
  • Plain text file with every node. +
+ +The "interesting junctions" referred to above are junctions where the route +changes to a different type of highway, more than two highways of the same type +meet, or where the route meets but does not take a more major highway. When the +route follows a major road this definition eliminates all junctions with minor +roads. + +

+ +The output files are written to the current directory and are named depending on +the selection of shortest or quickest route. For the shortest route the file +names are "shortest.html", "shortest-track.gpx", "shortest-route.gpx", +"shortest.txt" and "shortest-all.txt", for the quickest route the names are +"quickest.html", "quickest-track.gpx", "quickest-route.gpx", "quickest.txt" and +"quickest-all.txt". + +

+ +The HTML file and GPX files are written out according to the selected language +using the translations contained in the translations.xml configuration file. + + + +

HTML Route Instructions

+ +The HTML route instructions file contains one line for each of the interesting +junctions in the route and one line for the highway that connects them. + +

+ +An example HTML file output is below (some parts are missing, for example the +style definitions): + +

+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<!-- Creator : Routino - http://www.routino.org/ -->
+<!-- Source : Based on OpenStreetMap data from http://www.openstreetmap.org/ -->
+<!-- License : http://creativecommons.org/licenses/by-sa/2.0/ -->
+<HEAD>
+<TITLE>Shortest Route</TITLE>
+...
+</HEAD>
+<BODY>
+<H1>Shortest Route</H1>
+<table>
+<tr class='c'><td class='l'><td class='r'>51.524677 -0.127896
+<tr class='n'><td class='l'>Start:<td class='r'>At <span class='w'>Waypoint</span>, head <span class='b'>South-East</span>
+
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Russell Square</span> for <span class='d'>0.391 km, 0.5 min</span> [<span class='j'>0.4 km, 0 minutes</span>]
+...
+<tr class='t'><td class='l'>Total:<td class='r'><span class='j'>6.3 km, 5 minutes</span>
+<tr><td class='l'>Stop:<td class='r'><span class='w'>Waypoint</span>
+</table>
+</BODY>
+</HTML>
+
+ +The coordinates are included in the file but are not visible because of the +style definitions. + +

GPX Track File

+ +The GPX track file contains a track with all of the individual nodes that the +route passes through. + +

+ +An example GPX track file output is below: + +

+<?xml version="1.0" encoding="UTF-8"?>
+<gpx version="1.1" creator="Routino" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
+<metadata>
+<desc>Creator : Routino - http://www.routino.org/</desc>
+<copyright author="Based on OpenStreetMap data from http://www.openstreetmap.org/">
+<license>http://creativecommons.org/licenses/by-sa/2.0/</license>
+</copyright>
+</metadata>
+<trk>
+<name>Shortest route</name>
+<desc>Shortest route between 'start' and 'finish' waypoints</desc>
+<trkpt lat="51.524677" lon="-0.127896"/>
+<trkpt lat="51.523830" lon="-0.126993"/>
+...
+<trkpt lat="51.478353" lon="-0.103561"/>
+<trkpt lat="51.478244" lon="-0.103652"/>
+</trkseg>
+</trk>
+</gpx>
+
+ + +

GPX Route File

+ +The GPX route file contains a route (ordered set of waypoints) with all of the +interesting junctions that the route passes through. + +

+ +An example GPX route file output is below: + +

+<?xml version="1.0" encoding="UTF-8"?>
+<gpx version="1.1" creator="Routino" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
+<metadata>
+<desc>Creator : Routino - http://www.routino.org/</desc>
+<copyright author="Based on OpenStreetMap data from http://www.openstreetmap.org/">
+<license>http://creativecommons.org/licenses/by-sa/2.0/</license>
+</copyright>
+</metadata>
+<rte>
+<name>Shortest route</name>
+<desc>Shortest route between 'start' and 'finish' waypoints</desc>
+<rtept lat="51.524677" lon="-0.127896"><name>START</name>
+<desc>South-East on 'Russell Square' for 0.391 km, 0.5 min</desc></rtept>
+<rtept lat="51.521815" lon="-0.124577"><name>TRIP001</name>
+<desc>South-East on 'Russell Square' for 0.055 km, 0.1 min</desc></rtept>
+...
+<rtept lat="51.478244" lon="-0.103652"><name>FINISH</name>
+<desc>Total Journey 6.3 km, 5 minutes</desc></rtept>
+</rte>
+</gpx>
+
+ + +

Text File

+ +The text file format contains one entry for all of the interesting junctions in +the route and is intended to be easy to interpret. + +

+ +An example text file output is below: + +

+# Creator : Routino - http://www.routino.org/
+# Source : Based on OpenStreetMap data from http://www.openstreetmap.org/
+# License : http://creativecommons.org/licenses/by-sa/2.0/
+#
+#Latitude	Longitude	Section 	Section 	Total   	Total   	Point	Turn	Bearing	Highway
+#        	         	Distance	Duration	Distance	Duration	Type 	    	       	       
+ 51.524677	  -0.127896	 0.000 km	 0.0 min	  0.0 km	   0 min	Waypt		 +3	
+ 51.521815	  -0.124577	 0.391 km	 0.5 min	  0.4 km	   0 min	Junct	 +0	 +3	Russell Square
+...
+ 51.478353	  -0.103561	 0.598 km	 0.4 min	  6.2 km	   5 min	Junct	 +2	 -3	Camberwell New Road (A202)
+ 51.478244	  -0.103652	 0.013 km	 0.0 min	  6.3 km	   5 min	Waypt			Vassall Road
+
+ +

+ +The text file output contains a header (indicated by the lines starting with +'#') and then one line for each junction. Each line contains the information +for the route up to that point and the direction to go next. + +For each of the lines the individual fields contain the following: + + + + + + + + + + + + + +
Item + Description +
Latitude + Location of the point (degrees) +
Longitude + Location of the point (degrees) +
Section Distance + The distance travelled on the section of the journey that ends at this + point (defined on this line). +
Section Duration + The duration of travel on the section of the journey that ends at this + point (defined on this line). +
Total Distance + The total distance travelled up to this point. +
Total Duration + The total duration of travel up to this point. +
Point Type + The type of point; either a waypoint Waypt or + junction Junct. +
Turn + The direction to turn at this point (missing for the first point since + the journey has not started yet and the last point because it has + finished). This can take one of nine values between -4 and +4 defined by: + 0 = Straight, +2 = Right, -2 = Left and +/-4 + = Reverse. +
Bearing + The direction to head at this point (missing for the last point since + the journey has finished). This can take one of nine values between -4 + and +4 defined by: 0 = North, +2 = East, -2 + = West and +/-4 = South. +
Highway + The name (or description) of the highway to follow (missing on the first + line). +
+ +

+ +The individual items are separated by tabs but some of the items contain spaces +as well. + + +

All Nodes Text File

+ +The all nodes text file format contains one entry for each of the nodes on the +route. + +

+ +An example all nodes text file output is below: + +

+# Creator : Routino - http://www.routino.org/
+# Source : Based on OpenStreetMap data from http://www.openstreetmap.org/
+# License : http://creativecommons.org/licenses/by-sa/2.0/
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ 51.524677	  -0.127896	 7485978*	Waypt	0.000	 0.00	 0.00	  0.0			
+ 51.523830	  -0.126993	 7485047*	Junct	0.113	 0.14	 0.11	  0.1	 96	 146	Woburn Place
+...
+ 51.478353	  -0.103561	 7576939*	Junct	0.104	 0.07	 6.25	  5.0	 96	 126	Camberwell New Road (A202)
+ 51.478244	  -0.103652	 7581605 	Waypt	0.013	 0.01	 6.26	  5.0	 64	 207	Vassall Road
+
+ +

+ +The all nodes text file output is similar to the text file output except that a +line is printed for each of the nodes rather than just the interesting junctions. + +For each of the lines the individual fields contain the following: + + + + + + + + + + + + + + +
Item + Description +
Latitude + Location of the point in degrees. +
Longitude + Location of the point in degrees. +
Node + The internal node number and an indicator "*" if the node is a super-node. +
Type + The type of point; a waypoint Waypt, junction Junct, + change of highway Change or intermediate node Inter. +
Segment Distance + The distance travelled on the segment defined on this line. +
Segment Duration + The duration of travel on the segment defined on this line. +
Total Distance + The total distance travelled up to this point. +
Total Duration + The total duration of travel up to this point. +
Speed + The speed of travel on the segment defined on this line (missing on the + first line). +
Bearing + The direction that the segment defined on this line travels in degrees + (missing on the first line). +
Highway + The name (or description) of the highway segment (missing on the first + line). +
+ + +

+ + + + + + + + + + + + diff --git a/doc/html/style.css b/doc/html/style.css new file mode 100644 index 0000000..535e062 --- /dev/null +++ b/doc/html/style.css @@ -0,0 +1,391 @@ +/* +// Routino web page style sheet. +// +// Part of the Routino routing software. +// +// This file Copyright 2008-2010 Andrew M. Bishop +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +*/ + + +/*----------------------------------*/ +/* Body HTML formatting */ +/*----------------------------------*/ + +BODY +{ + /* fonts and text styles */ + + font-family: sans-serif; + font-size: medium; + + /* margins, borders, padding and sizes */ + + padding: 0; + + margin: 0; +} + +A.ext +{ + /* fonts and text styles */ + + text-decoration: underline; +} + +PRE +{ + /* fonts and text styles */ + + font-family: monospace; +} + +PRE.boxed +{ + /* margins, borders, padding and sizes */ + + padding: 0.5em; + + border: solid; + border-width: thin; +} + + +/*-----------------------------------*/ +/* Header HTML formatting */ +/*-----------------------------------*/ + +DIV.header +{ + /* margins, borders, padding and sizes */ + + padding: 0; + padding-top: 0.5em; + padding-bottom: 0.5em; + + border-width: 0; + border-bottom: solid; + border-bottom-width: thin; + + margin: 0; + + /* floats */ + + clear: left; +} + +DIV.header HR /* Horizontal rule, only visible without CSS */ +{ + display: none; +} + +DIV.header H1 +{ + /* fonts and text styles */ + + font-size: xx-large; + + font-weight: bold; + + text-decoration: underline; + + /* margins, borders, padding and sizes */ + + padding: 0.25em; + + border: 0; + + margin: 0; +} + + +/*-----------------------------------*/ +/* Footer HTML formatting */ +/*-----------------------------------*/ + +DIV.footer +{ + /* fonts and text styles */ + + font-size: small; + + /* margins, borders, padding and sizes */ + + padding: 0; + padding-top: 0.5em; + padding-bottom: 0.5em; + + border-width: 0; + border-top: solid; + border-top-width: thin; + + margin: 0; + + /* floats */ + + clear: left; +} + +DIV.footer HR /* Horizontal rule, only visible without CSS */ +{ + display: none; +} + + +/*-----------------------------------*/ +/* Content HTML formatting */ +/*-----------------------------------*/ + +DIV.content +{ + /* margins, borders, padding and sizes */ + + padding: 0.5em; + + border-width: 0; +} + +DIV.content H1 +{ + /* fonts and text styles */ + + font-size: xx-large; + font-weight: bold; + + /* margins, borders, padding and sizes */ + + padding: 0; + + margin-top: 1em; + margin-bottom: 0.25em; +} + +DIV.content H2 +{ + /* fonts and text styles */ + + font-size: x-large; + font-weight: bold; + + /* margins, borders, padding and sizes */ + + padding: 0; + + margin-top: 0.75em; + margin-bottom: 0.25em; +} + +DIV.content H3 +{ + /* fonts and text styles */ + + font-size: large; + font-weight: bold; + + /* margins, borders, padding and sizes */ + + padding: 0; + + margin-top: 0.75em; + margin-bottom: 0.25em; +} + +DIV.content H4 +{ + /* fonts and text styles */ + + font-size: medium; + font-weight: bold; + + /* margins, borders, padding and sizes */ + + padding: 0; + + margin-top: 0.5em; + margin-bottom: 0.125em; +} + +DIV.content OL, DIV.content UL, DIV.content DIR, DIV.content MENU, DIV.content DL +{ + /* margins, borders, padding and sizes */ + + padding-top: 0; + padding-bottom: 0; + + margin-top: 0.25em; + margin-bottom: 0.25em; +} + +DIV.content UL UL, DIV.content UL OL, DIV.content UL DL, DIV.content OL UL, DIV.content OL OL, DIV.content OL DL, DIV.content DL UL, DIV.content DL OL, DIV.content DL DL +{ + /* margins, borders, padding and sizes */ + + padding-top: 0; + padding-bottom: 0; + + margin-top: 0; + margin-bottom: 0; +} + +DIV.content FORM +{ + /* margins, borders, padding and sizes */ + + padding: 0.5em; + + margin: 0.5em; +} + +DIV.content INPUT +{ + /* margins, borders, padding and sizes */ + + padding: 0; + + border: 1px solid; + + margin: 1px; +} + +DIV.content BUTTON +{ + /* margins, borders, padding and sizes */ + + padding: 0; + + border: 1px solid; + + margin: 1px; +} + +DIV.content INPUT.left +{ + /* text alignment */ + + text-align: left; +} + +DIV.content INPUT.center +{ + /* text alignment */ + + text-align: center; +} + +DIV.content INPUT.right +{ + /* text alignment */ + + text-align: right; +} + +DIV.content TABLE +{ + /* margins, borders, padding and sizes */ + + padding: 0; + + border: 2px solid; + + margin: 0; + margin-left: auto; + margin-right: auto; + + border-collapse: collapse; +} + +DIV.content TABLE.noborder +{ + /* margins, borders, padding and sizes */ + + margin-left: auto; + margin-right: auto; + + border: 0; +} + +DIV.content TABLE.noborder-left +{ + /* margins, borders, padding and sizes */ + + margin-left: 0; + margin-right: auto; + + border: 0; +} + +DIV.content CAPTION +{ + /* position */ + + caption-side: bottom; + + /* text alignment */ + + text-align: center; + + /* fonts and text styles */ + + font-weight: bold; +} + +DIV.content TD, DIV.content TH +{ + /* margins, borders, padding and sizes */ + + border: 1px solid; +} + +DIV.content TABLE.noborder TD, DIV.content TABLE.noborder TH +{ + /* margins, borders, padding and sizes */ + + border: 0; +} + +DIV.content TABLE.noborder-left TD, DIV.content TABLE.noborder-left TH +{ + /* margins, borders, padding and sizes */ + + border: 0; +} + +DIV.content TD.left, DIV.content TH.left, DIV.content TR.left +{ + /* text alignment */ + + text-align: left; +} + +DIV.content TD.center, DIV.content TH.center, DIV.content TR.center +{ + /* text alignment */ + + text-align: center; +} + +DIV.content TD.right, DIV.content TH.right, DIV.content TR.right +{ + /* text alignment */ + + text-align: right; +} + +DIV.content IMG +{ + /* margins, borders, padding and sizes */ + + border: 0px; +} diff --git a/doc/html/tagging.html b/doc/html/tagging.html new file mode 100644 index 0000000..5af6812 --- /dev/null +++ b/doc/html/tagging.html @@ -0,0 +1,658 @@ + + + + + + +Routino : Tagging Rules + + + + + + + + +
+ +

Routino : Tagging Rules

+ +
+
+ + + + + +
+ +

Tags And Attributes

+ +The different tags and attributes in the +OSM +format XML that are used by Routino are described below. + +

+ +An important change for version 1.4 of Routino is that the tags in the input +file are first processed according to a set of rules defined in a configuration +file. This means that the information presented here is in two parts; firstly +the tags that are recognised by Routino after pre-processing and secondly the +transformations in the default configuration file. + + +

Tags Recognised After Processing

+ +This section describes the tags that are recognised by Routino after the tag +transformations have been applied. This is therefore a much reduced set of tags +compared to the original OSM data and also includes tags which are specific to +Routino. + +

+ +In all cases of tag processing values of true, yes, 1 +are recognised as being affirmative and any other value is ignored. + + +

Node Tags And Attributes

+ +None of the node tags are used but the node attributes id, latitude +and longitude of the node. The id atribute is required to associate the +node with the ways and the position attributes are required to locate the node. + + +

Way Tags And Attributes

+ +The tags from the ways in the data are the ones that provide most of the +information for routing. The id attribute is used only so that the +many segments associated with a way can be share a set of tags taken from the +way. + + +

The highway Tag

+ +The most important tag that is used from a way is the highway tag. +This defines the type of highway that the way represents. Any way that does not +have a highway tag is discarded. + +

+ +There are more highway types defined than are used by the router. The subset +that the router uses are: + +

    +
  • motorway +
  • trunk +
  • primary +
  • secondary +
  • tertiary +
  • unclassified +
  • residential +
  • service +
  • track +
  • cycleway +
  • path (1) +
  • steps (2) +
+ +

+ + + Note 1: This changed in version 1.3 of Routino - the bridleway and footway + types were included within the path highway type. +
+ Note 2: This changed in version 1.3 of Routino - the steps type was separated + from the footway type. +
+ + +

Transport Specific Tags

+ +One tag is recognised for each of the different modes of transport: foot, +horse, bicycle, wheelchair, moped, +motorbike, motorcar, goods, hgv +and psv. These indicate whether the specific type of transport is +allowed on the highway or not. + + +

The name Tag

+ +The name tag is used to provide the label for the highway when printing +the results. + + +

The ref Tag

+ +The ref tag is used to provide the label for the highway when printing +the results. + + +

The junction Tag

+ +The junction tag is used to check if a highway is (part of) a +roundabout. This tag is used for information to label the highway if no other +name is provided. + + +

The multilane Tag

+ +The multilane tag is used to identify whether a highway has multiple +lanes for traffic and this sets one of the highway properties. There is not +normally a multilane tag but one needs to be added by the tag +processing transformations. Values of true, yes, 1 +are recognised. + + +

The paved Tag

+ +The paved tag is used to identify whether a highway is paved or not, +this is one of the available highway properties. A paved tag may exist +in the original data but normally the surface tag needs to be +transformed into the paved tag. + + +

The bridge Tag

+ +The bridge tag is used to identify whether a highway is a bridge and +therefore set one of the available properties. + + +

The tunnel Tag

+ +The tunnel tag is used to identify whether a highway is a tunnel and +therefore set one of the available properties. + + +

The oneway Tag

+ +The oneway tag is used to specify that traffic is only allowed to +travel in one direction. + + +

The maxspeed Tag

+ +The maxspeed tag is used to specify the maximum speed limit on the +highway; this is always measured in km/hr in OpenStreetMap data. If the tag +value contains "mph" then it is assumed to be a value in those units and +converted to km/hr. + + +

The maxweight Tag

+ +The maxweight tag is used to specify the maximum weight of any traffic +on the way. In other words this must be set to the heaviest weight allowed on +the way (for example a bridge) in tonnes. If the tag value contains "kg" then +it is assumed that the value is in these units and converted to tonnes. + + +

The maxheight Tag

+ +The maxheight tag is used to specify the maximum height of any traffic +on the way. In other words this must be set to the lowest height of anything +above the way (like a bridge) in metres. If the tag value contains a +measurement in feet or feet and inches then attempts are made to convert this to +metres. + + +

The maxwidth Tag

+ +The maxwidth tag is used to specify the maximum width of any traffic on +the way. This must be set to the minimum width of the contraints at the wayside +in metres. If the tag value contains a measurement in feet or feet and inches +then attempts are made to convert this to metres. + + +

The maxlength Tag

+ +The maxlength tag is used to specify the maximum length of any traffic +on the way (usually from a traffic sign) in metres. If the tag value contains a +measurement in feet or feet and inches then attempts are made to convert this to +metres. + + +

Relation Tags And Attributes

+ +Currently no relation tags or attributes are used. + + +

Tag Transformations

+ +This section describes the set of tag transformations that are contained in the +default configuration file. The configuration file tagging rules are applied in +sequence and this section of the document is arranged in the same order. + + +

Node Tag Transformations

+ +No transformations are applicable since no node tags are recognised. + + +

Way Tag Transformations

+ + +

Highway Defaults

+ +The first part of the tag transformations is to decide on defaults for each type +of highway. This uses the highway tag in the OSM file and maps it into one of +the highway tags that are recognised by Routino, defining the default allowed +transport types and adding a number of properties. + +

+ +The first part of the transformation is to convert the highway tag into one that +is recognised by Routino. + +

+ + + + + + + + + + + + + + + +
Mapping of equivalent highway types
Original tag + Transformed tag +
bridleway + path +
byway + track +
footway + path +
living_street + residential +
minor + unclassified +
pedestrian + path +
road + unclassified +
services + service +
unsurfaced + track +
unpaved + track +
walkway + path +
+ +

+ +The type of highway also determines the defaults for the types of transport +allowed on the highway. The default assumptions are as shown in the table +below. + +

+ + + + + + + + + + + + + + + + +
Transport types on different highway types
Highway + foot + horse + bicycle + wheelchair + moped + motorbike + motorcar + goods + hgv + psv +
motorway + no + no + no + no + no + yes + yes + yes + yes + yes +
trunk + no + no + no + yes + yes + yes + yes + yes + yes + yes +
primary + yes + yes + yes + yes + yes + yes + yes + yes + yes + yes +
secondary + yes + yes + yes + yes + yes + yes + yes + yes + yes + yes +
tertiary + yes + yes + yes + yes + yes + yes + yes + yes + yes + yes +
unclassified + yes + yes + yes + yes + yes + yes + yes + yes + yes + yes +
residential + yes + yes + yes + yes + yes + yes + yes + yes + yes + yes +
service + yes + yes + yes + yes + yes + yes + yes + yes + yes + yes +
track + yes + yes + yes + yes + no + no + no + no + no + no +
cycleway + yes + no + yes + yes + no + no + no + no + no + no +
path + yes + yes (1) + yes + yes (1) + no + no + no + no + no + no +
steps + yes + no + no + no + no + no + no + no + no + no +
+ +

+ + + Note 1: A path allows bicycle or horse access by default only if actually + labelled as a highway of type "bridleway" or certain values of + the designation tag (described below). + + +

+ +Finally for the highway tag a number of properties are added depending on the +highway type. + +

+ + + + + + + + + + + + + + + + +
Properties on different highway types
Highway + Properties +
motorway + paved, oneway, multilane +
trunk + paved +
primary + paved +
secondary + paved +
tertiary + paved +
unclassified + paved +
residential + paved +
service + paved +
track + paved (1) +
cycleway + paved +
path + paved (2) +
steps + +
+ +

+ + + Note 1: A track is paved only if it is tagged as tracktype=grade1. +
+ Note 2: A path is paved only if it was originally tagged as highway=walkway or + highway=pedestrian. +
+ + +

Generic Access Permissions

+ +The access tag is used to specify the default access restrictions on +the way. If the tag value is "no" or "private" then all transport types are +denied access (later tag transformation rules may add specific transport types +back again). + + +

Other Access Permissions

+ +A tag named vehicle means any of the bicycle, moped, +motorbike, motorcar, goods, hgv +and psv transport types. A tag named motor_vehicle is +transformed to mean any vehicle except a bicycle. + +

+ +The designation tag is used as an alternative method of identifying the +legal right of way on a path (in the UK at least). The tag transformations +convert these tags into a set of allowed transport types as shown below. + +

+ + + + + + + + +
Aliasing of designation types
Designation tag + Equivalent access permissions +
bridleway or public_bridleway + foot=yes, wheelchair=yes, horse=yes, bicycle=yes +
restricted_byway + foot=yes, wheelchair=yes, horse=yes, bicycle=yes +
byway + foot=yes, wheelchair=yes, horse=yes, bicycle=yes, moped=yes, motorbike=yes, motorcar=yes +
footpath or public_footpath + foot=yes, wheelchair=yes +
+ + +

Specific Access Permissions

+ +The final part of the access permissions is to use the specific transport type +tags. + +

+ +One tag is recognised for each of the different modes of transport: foot, +horse, bicycle, wheelchair, moped, +motorbike, motorcar, goods, hgv +and psv. These indicate whether the specific type of transport is +allowed on the highway or not. + + +

Highway Properties

+ +If there is a surface tag then the highway is assumed to be unpaved unless the +tag value matches one of the following: paved, asphalt +or concrete. + +

+ +Support for the obsolete paved tag is also provided and the highway is +paved if this is set to a true value. + +

+ +The lanes tag is used to identify whether a highway has multiple lanes +for traffic or not (the number of lanes is not important in this case, only +whether it is more than one) this sets one of the highway properties. + +

+ +The bridge and tunnel tags are copied directly from the input +to the output. + + +

Highway Restrictions

+ +The oneway, maxspeed, maxweight, maxheight, +maxwidth and maxlength are copied directly from the input to +the output without modification. + + +

Highway Names and References

+ +The name and ref tags are copied directly from the input to +the output. + + +

Relation Tag Transformations

+ +No transformations are applicable since no relation tags are recognised. + +
+ + + + + + + + + + + + diff --git a/doc/html/usage.html b/doc/html/usage.html new file mode 100644 index 0000000..dc75888 --- /dev/null +++ b/doc/html/usage.html @@ -0,0 +1,443 @@ + + + + + + +Routino : Usage + + + + + + + + +
+ +

Routino : Usage

+ +
+
+ + + + + +
+ +

Program Usage

+ +There are four programs that make up this software. The first one takes the +planet.osm datafile from OpenStreetMap (or other source of data using the same +formats) and converts it into a local database. The second program uses the +database to determine an optimum route between two points. The third program +allows visualisation of the data and statistics to be extracted. The fourth +program is a test program for the tag transformations. + +

planetsplitter

+ +This program reads in the OSM format XML file and splits it up to create the +database that is used for routing. + +
+Usage: planetsplitter [--help]
+                      [--dir=<dirname>] [--prefix=<name>]
+                      [--slim] [--sort-ram-size=<size>]
+                      [--tmpdir=<dirname>]
+                      [--parse-only | --process-only]
+                      [--max-iterations=<number>]
+                      [--tagging=<filename>]
+                      [<filename.osm> ...]
+
+ +
+
--help +
Prints out the help information. +
--dir=<dirname> +
Sets the directory name in which to save the results. + Defaults to the current directory. +
--prefix=<name> +
Sets the filename prefix for the files that are created. + Defaults to no prefix. +
--slim +
Selects a mode of operation that uses less memory and will therefore work + where virtual memory is very limited or unavailable. Selecting this option + will cause raw data to be held in disk files with only indexes in RAM. Not + using this option will still use disk files but only for sequential access + and the files are memory mapped for random access. +
--sort-ram-size=<size> +
Specifies the amount of RAM (in MB) to use for sorting the data. If not + specified then 64 MB will be used if the '--slim' option is specified or 256 + MB otherwise. +
--tmpdir=<dirname> +
Specifies the name of the directory to store the temporary disk files. If + not specified then it defaults to either the value of the --dir option or the + current directory. +
--parse-only +
Parse the input files and store them in a temporary file but don't process + the data into a routing database. +
--process-only +
Don't read in any files but process the existing temporary file into the + routing database. +
--max-iterations=<number> +
The maximum number of iterations to use when generating super-nodes and + super-segments. Defaults to 10 which is normally enough. +
--tagging=<filename> +
The name of the XML file containing the tagging rules (defaults to + 'tagging.xml' with '--dirname' and '--prefix' options). +
<filename.osm> ... +
Specifies the filename(s) to read data from, by default data is read from + the standard input. +
+ +

+Note: In version 1.4 of Routino the --transport, --not-highway and +--not-property options have been removed. The same functionality can be +achieved by editing the tagging rules file to not output unwwanted data. + +

+Example usage: + +

+./planetsplitter --dir=data --prefix=gb great_britain.osm
+
+ +This will generate the output files 'data/gb-nodes.mem', 'data/gb-segments.mem' +and 'data/gb-ways.mem'. + + +

router

+ +This program performs the calculation of the optimum routes using the database +generated by the planetsplitter program. + +
+Usage: router [--help | --help-profile | --help-profile-xml |
+                        --help-profile-json | --help-profile-perl ]
+              [--dir=<dirname>] [--prefix=<name>]
+              [--profiles=<filename>] [--translations=<filename>]
+              [--exact-nodes-only]
+              [--quiet]
+              [--output-html]
+              [--output-gpx-track] [--output-gpx-route]
+              [--output-text] [--output-text-all]
+              [--output-none]
+              [--profile=<name>]
+              [--transport=<transport>]
+              [--shortest | --quickest]
+              --lon1=<longitude> --lat1=<latitude>
+              --lon2=<longitude> --lon2=<latitude>
+              [ ... --lon99=<longitude> --lon99=<latitude>]
+              [--highway-<highway>=<preference> ...]
+              [--speed-<highway>=<speed> ...]
+              [--property-<property>=<preference> ...]
+              [--oneway=(0|1)]
+              [--weight=<weight>]
+              [--height=<height>] [--width=<width>] [--length=<length>]
+
+ +
+
--help +
Prints out the help information. +
--help-profile +
Prints out the selected transport profile (type, speed limits, highway + preferences etc.) +
--help-profile-xml +
Prints out all the loaded profiles as an XML file in the same format that + can be loaded in. +
--help-profile-json +
Prints out all the loaded profiles in JavaScript Object Notation (JSON) + format for use in the interactive webpage. +
--help-profile-perl +
Prints out all the loaded profiles as a Perl object for use in the router + CGI. +
--dir=<dirname> +
Sets the directory name in which to read the local database. + Defaults to the current directory. +
--prefix=<name> +
Sets the filename prefix for the files in the local database. + Defaults to no prefix. +
--profiles=<filename> +
Sets the filename containing the list of profiles in XML format. If the + file doesn't exist then dirname, prefix and "profiles.xml" will be combined + and used, if that doesn't exist then the command line must contain all + relevant profile information. +
--translations=<filename> +
Sets the filename containing the list of translations in XML format for + the output files. If the file doesn't exist then dirname, prefix and + "translations.xml" will be combined and used, if that doesn't exist then no + file will be read and no language can be selected. +
--exact-nodes-only +
When processing the specified latitude and longitude points only select + the nearest node instead of finding the nearest point within a segment + (quicker but less accurate unless the points are already near nodes). +
--quiet +
Don't generate any screen output while running (useful for running in a script). +
--language=<lang> +
Select the language specified from the file of translations. If this + option is not given and the file exists then the first language in the file + will be used. If this option is not given and no file exists the + compiled-in default language (English) will be used. +
--output-html +
--output-gpx-track +
--output-gpx-route +
--output-text +
--output-text-all +
Generate the selected output file formats (HTML, GPX track file, GPX route + file, plain text route and/or plain text with all nodes). If no output is + specified then all are generated, specifying any automatically disables those + not specified. +
--output-none +
Do not generate any output or read in any translations files. +
--profile=<name> +
Specifies the name of the profile to use. +
--transport=<transport> +
Select the type of transport to use, <transport> can be set to: +
    +
  • foot = Foot +
  • horse = Horse +
  • wheelchair = Wheelchair +
  • bicycle = Bicycle +
  • moped = Moped (Small motorbike, limited speed) +
  • motorbike = Motorbike +
  • motorcar = Motorcar +
  • goods = Goods (Small lorry, van) +
  • hgv = HGV (Heavy Goods Vehicle - large lorry) +
  • psv = PSV (Public Service Vehicle - bus, coach) +
+ Defaults to 'motorcar', this option also selects the default profile + information if the '--profile' option is not given and a profile matching + the transport name is found. +
--shortest +
Find the shortest route between the waypoints. +
--quickest +
Find the quickest route between the waypoints. +
--lon1=<longitude>, --lat1=<latitude> +
--lon2=<longitude>, --lat2=<latitude> +
... --lon99=<longitude>, --lat99=<latitude> +
The location of the waypoints that make up the start, middle and end + points of the route. Up to 99 waypoints can be specified and the route will + pass through each of the specified ones in sequence. The algorithm will use + the closest node or point within a segment that allows the specified traffic + type. +
--highway-<highway>=<preference> +
Selects the percentage preference for using each particular type of + highway. The value of <highway> can be selected from: +
    +
  • motorway = Motorway +
  • trunk = Trunk +
  • primary = Primary +
  • secondary = Secondary +
  • tertiary = Tertiary +
  • unclassified = Unclassified +
  • residential = Residential +
  • service = Service +
  • track = Track +
  • cycleway = Cycleway +
  • path = Path +
  • steps = Steps +
+ Default value depends on the profile selected by the --transport option. +
--speed-<highway>=<speed> +
Selects the speed limit in km/hour for each type of highway. Default + value depends on the profile selected by the --transport option. +
--property-<property>=<preference> +
Selects the percentage preference for using each particular highway + property + The value of <property> can be selected from: +
    +
  • paved = Paved (suitable for normal wheels) +
  • multilane = Multiple lanes +
  • bridge = Bridge +
  • tunnel = Tunnel +
+ Default value depends on the profile selected by the --transport option. +
--oneway=[0|1] +
Selects if the direction of oneway streets are to be obeyed (useful to not + obey them when walking). Default value depends on the profile selected by + the --transport option. +
--weight=<weight> +
Specifies the weight of the mode of transport in tonnes; ensures that the + weight limit on the highway is not exceeded. Default value depends on the + profile selected by the --transport option. +
--height=<height> +
Specifies the height of the mode of transport in metres; ensures that the + height limit on the highway is not exceeded. Default value depends on the + profile selected by the --transport option. +
--width=<width> +
Specifies the width of the mode of transport in metres; ensures that the + width limit on the highway is not exceeded. Default value depends on the + profile selected by the --transport option. +
--length=<length> +
Specifies the length of the mode of transport in metres; ensures that the + length limit on the highway is not exceeded. Default value depends on the + profile selected by the --transport option. +
+ +

+The meaning of the <preference> parameter in the command line options is +slightly different for the highway preferences and the property preferences. +For the highway preference consider the choice between two possible highways +between the start and finish when looking for the shortest route. If highway A +has a preference of 100% and highway B has a preference of 90% then highway A +will be chosen even if it is up to 11% longer (100/90 = 111%). For the highway +properties each highway either has a particular property or not. If the +preference for highways with the property is 60% then the preference for +highways without the property is 40%. The overall preference for the highway is +the product of the highway preference and the preference for highways with (or +without) each property that the highway has (or doesn't have). + +

+Example usage (motorbike journey, scenic route, not very fast): + +

+./router --dir=data --prefix=gb --transport=motorbike --highway-motorway=0 \
+         --highway-trunk=0 --speed-primary=80 --speed-secondary=80 --quickest
+
+ +This will use the files 'data/gb-nodes.mem', 'data/gb-segments.mem' and +'data/gb-ways.mem' to find the quickest route by motorbike not using motorways +or trunk roads and not exceeding 80 km/hr. + + +

filedumper

+ +This program is used to extract statistics from the database, extract particular +information for visualisation purposes or for dumping the database contents. + +
+Usage: filedumper [--help]
+                  [--dir=<dirname>] [--prefix=<name>]
+                  [--statistics]
+                  [--visualiser --latmin=<latmin> --latmax=<latmax>
+                                --lonmin=<lonmin> --lonmax=<lonmax>
+                                --data=<data-type>]
+                  [--dump [--node=<node> ...]
+                          [--segment=<segment> ...]
+                          [--way=<way> ...]]
+                  [--dump-osm [--no-super]
+                              [--latmin=<latmin> --latmax=<latmax>
+                               --lonmin=<lonmin> --lonmax=<lonmax>]]
+
+ +
+
--help +
Prints out the help information. +
--dir=<dirname> +
Sets the directory name in which to read the local database. + Defaults to the current directory. +
--prefix=<name> +
Sets the filename prefix for the files in the local database. +
--statistics +
Prints out statistics about the database files. +
--visualiser +
Selects a data visualiser mode which will output a set of data according + to the other parameters below. +
+
--latmin=<latmin> --latmax=<latmax> +
The range of latitudes to print the data for. +
--lonmin=<lonmin> --lonmax=<lonmax> +
The range of longitudes to print the data for. +
--data=<data-type> +
The type of data to output, <data-type> can be selected from: +
    +
  • junctions = segment count at each junction. +
  • super = super-node and super-segments. +
  • oneway = oneway segments. +
  • speed = speed limits. +
  • weight = weight limits. +
  • height = height limits. +
  • width = width limits. +
  • length = length limits. +
+
+
--dump +
Selects a data dumping mode which allows looking at individual items in + the databases (specifying 'all' instead of a number dumps all of them). +
+
--node=<node> +
Prints the information about the selected node number (internal + number, not the node id number in the original source file). +
--segment=<segment> +
Prints the information about the selected segment number. +
--way=<way> +
Prints the information about the selected way number (internal + number, not the way id number in the original source file). +
+
--osm-dump +
Dumps the contents of the database as an OSM format XML file, the whole + database will be dumped unless the latitude and longitude ranges are + specified. +
+
--no-super +
The super segments will not be output. +
--latmin=<latmin> --latmax=<latmax> +
The range of latitudes to dump the data for. +
--lonmin=<lonmin> --lonmax=<lonmax> +
The range of longitudes to dump the data for. +
+
+ + +

tagmodifier

+ +This program is used to run the tag transformation process on an OSM XML file +for test purposes. + +
+Usage: tagmodifier [--help]
+                   [--tagging=<filename>]
+                   [<filename.osm>]
+
+ +
+
--help +
Prints out the help information. +
--tagging=<filename> +
The name of the XML file containing the tagging rules (defaults to + 'tagging.xml' in the current directory). +
<filename.osm> ... +
Specifies the filename to read data from, by default data is read from + the standard input. +
+ +
+ + + + + + + + + + + + diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..49e583e --- /dev/null +++ b/src/Makefile @@ -0,0 +1,154 @@ +# $Header: /home/amb/routino/src/RCS/Makefile,v 1.36 2010/07/09 17:43:00 amb Exp $ +# +# Source code Makefile +# +# Part of the Routino routing software. +# +# This file Copyright 2008-2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Programs + +CC=gcc +LD=gcc + +LEX=flex + +# Program options + +CFLAGS=-Wall -Wmissing-prototypes +#CFLAGS+= -Wextra -pedantic -std=c99 +LDFLAGS=-lm -lc + +CFLAGS+= -O3 +#CFLAGS+= -O0 -g +#CFLAGS+= -pg +#CFLAGS+= --coverage + +LDFLAGS+= +#LDFLAGS+= -pg -static +#LDFLAGS+= --coverage + +LEXFLAGS= + +# Required to use stdio with files > 2GiB on 32-bit system. + +FLAGS64=-D_FILE_OFFSET_BITS=64 + +# Compilation targets + +C=$(wildcard *.c) +D=$(foreach f,$(C),$(addprefix .deps/,$(addsuffix .d,$(basename $f)))) + +EXE=planetsplitter router filedumper tagmodifier + +WEBDIR=../web/bin + +######## + +all : $(EXE) + -@[ -d $(WEBDIR) ] && \ + for file in $(EXE); do \ + if [ ! -f $(WEBDIR)/$$file ] || [ $$file -nt $(WEBDIR)/$$file ]; then \ + echo cp $$file $(WEBDIR) ;\ + cp -f $$file $(WEBDIR) ;\ + fi ;\ + done + @cd xml && $(MAKE) CC="$(CC)" LD="$(LD)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" + +######## + +PLANETSPLITTER_OBJ=planetsplitter.o \ + nodesx.o segmentsx.o waysx.o superx.o \ + ways.o types.o \ + files.o \ + results.o queue.o sorting.o \ + xmlparse.o tagging.o osmparser.o + +planetsplitter : $(PLANETSPLITTER_OBJ) + $(LD) $(PLANETSPLITTER_OBJ) -o $@ $(LDFLAGS) + +######## + +ROUTER_OBJ=router.o \ + nodes.o segments.o ways.o types.o \ + files.o profiles.o xmlparse.o \ + optimiser.o output.o results.o queue.o translations.o + +router : $(ROUTER_OBJ) + $(LD) $(ROUTER_OBJ) -o $@ $(LDFLAGS) + +######## + +FILEDUMPER_OBJ=filedumper.o \ + nodes.o segments.o ways.o types.o \ + files.o xmlparse.o \ + visualiser.o + +filedumper : $(FILEDUMPER_OBJ) + $(LD) $(FILEDUMPER_OBJ) -o $@ $(LDFLAGS) + +######## + +TAGMODIFIER_OBJ=tagmodifier.o \ + files.o \ + xmlparse.o tagging.o + +tagmodifier : $(TAGMODIFIER_OBJ) + $(LD) $(TAGMODIFIER_OBJ) -o $@ $(LDFLAGS) + +######## + +xmlparse.c : xmlparse.l + $(LEX) $(LEXFLAGS) $< + -@mv lex.yy.c xmlparse.c + @echo Created xmlparse.c + +######## + +%.o : %.c + $(CC) -c $(CFLAGS) $(FLAGS64) $< -o $@ -MMD -MP -MF $(addprefix .deps/,$(addsuffix .d,$(basename $<))) + +######## + +clean: + rm -f *.o + rm -f *~ + rm -f xmlparse.c + cd xml && $(MAKE) clean + +######## + +distclean: clean + -[ -d ../web/bin ] && cd ../web/bin/ && rm -f $(EXE) + -rm -f $(EXE) + -rm -f $(D) + -rm -fr .deps + cd xml && $(MAKE) distclean + +######## + +.deps : .FORCE + @[ -d .deps ] || mkdir $@ + +$(D) : .deps + @touch $@ + +include $(D) + +######## + +.FORCE : diff --git a/src/filedumper.c b/src/filedumper.c new file mode 100644 index 0000000..463ab19 --- /dev/null +++ b/src/filedumper.c @@ -0,0 +1,674 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/filedumper.c,v 1.43 2010/05/30 12:52:16 amb Exp $ + + Memory file dumper. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "functions.h" +#include "visualiser.h" +#include "nodes.h" +#include "segments.h" +#include "ways.h" +#include "xmlparse.h" + + +/* Local functions */ + +static void print_node(Nodes* nodes,index_t item); +static void print_segment(Segments *segments,index_t item); +static void print_way(Ways *ways,index_t item); + +static void print_head_osm(void); +static void print_node_osm(Nodes* nodes,index_t item); +static void print_segment_osm(Segments *segments,index_t item,Ways *ways); +static void print_tail_osm(void); + +static char *RFC822Date(time_t t); + +static void print_usage(int detail); + + +/*++++++++++++++++++++++++++++++++++++++ + The main program for the file dumper. + ++++++++++++++++++++++++++++++++++++++*/ + +int main(int argc,char** argv) +{ + Nodes *OSMNodes; + Segments *OSMSegments; + Ways *OSMWays; + int arg; + char *dirname=NULL,*prefix=NULL; + char *nodes_filename,*segments_filename,*ways_filename; + int option_statistics=0; + int option_visualiser=0,coordcount=0; + double latmin=0,latmax=0,lonmin=0,lonmax=0; + char *option_data=NULL; + int option_dump=0; + int option_dump_osm=0,option_no_super=0; + + /* Parse the command line arguments */ + + for(arg=1;argnumber); + printf("Number(super)=%9d\n",OSMNodes->snumber); + printf("\n"); + + printf("Lat bins= %4d\n",OSMNodes->latbins); + printf("Lon bins= %4d\n",OSMNodes->lonbins); + printf("\n"); + + printf("Lat zero=%5d (%8.4f deg)\n",OSMNodes->latzero,radians_to_degrees(latlong_to_radians(bin_to_latlong(OSMNodes->latzero)))); + printf("Lon zero=%5d (%8.4f deg)\n",OSMNodes->lonzero,radians_to_degrees(latlong_to_radians(bin_to_latlong(OSMNodes->lonzero)))); + + /* Examine the segments */ + + printf("\n"); + printf("Segments\n"); + printf("--------\n"); + printf("\n"); + + printf("sizeof(Segment)=%9d Bytes\n",sizeof(Segment)); + printf("Number(total) =%9d\n",OSMSegments->number); + printf("Number(super) =%9d\n",OSMSegments->snumber); + printf("Number(normal) =%9d\n",OSMSegments->nnumber); + + /* Examine the ways */ + + printf("\n"); + printf("Ways\n"); + printf("----\n"); + printf("\n"); + + printf("sizeof(Way) =%9d Bytes\n",sizeof(Way)); + printf("Number(compacted)=%9d\n",OSMWays->number); + printf("Number(original) =%9d\n",OSMWays->onumber); + printf("\n"); + + printf("Total names =%9ld Bytes\n",(long)buf.st_size-sizeof(Ways)-OSMWays->number*sizeof(Way)); + printf("\n"); + + printf("Included transports: %s\n",AllowedNameList(OSMWays->allow)); + printf("Included properties: %s\n",PropertiesNameList(OSMWays->props)); + } + + /* Print out internal data */ + + if(option_dump) + { + index_t item; + + for(arg=1;argnumber;item++) + print_node(OSMNodes,item); + } + else if(!strncmp(argv[arg],"--node=",7)) + { + item=atoi(&argv[arg][7]); + + if(item>=0 && itemnumber) + print_node(OSMNodes,item); + else + printf("Invalid node number; minimum=0, maximum=%d.\n",OSMNodes->number-1); + } + else if(!strcmp(argv[arg],"--segment=all")) + { + for(item=0;itemnumber;item++) + print_segment(OSMSegments,item); + } + else if(!strncmp(argv[arg],"--segment=",10)) + { + item=atoi(&argv[arg][10]); + + if(item>=0 && itemnumber) + print_segment(OSMSegments,item); + else + printf("Invalid segment number; minimum=0, maximum=%d.\n",OSMSegments->number-1); + } + else if(!strcmp(argv[arg],"--way=all")) + { + for(item=0;itemnumber;item++) + print_way(OSMWays,item); + } + else if(!strncmp(argv[arg],"--way=",6)) + { + item=atoi(&argv[arg][6]); + + if(item>=0 && itemnumber) + print_way(OSMWays,item); + else + printf("Invalid way number; minimum=0, maximum=%d.\n",OSMWays->number-1); + } + } + + /* Print out internal data in XML format */ + + if(option_dump_osm) + { + if(coordcount>0 && coordcount!=4) + { + fprintf(stderr,"The --dump-osm option must have all of --latmin, --latmax, --lonmin, --lonmax or none.\n"); + exit(1); + } + + print_head_osm(); + + if(coordcount) + { + int32_t latminbin=latlong_to_bin(radians_to_latlong(latmin))-OSMNodes->latzero; + int32_t latmaxbin=latlong_to_bin(radians_to_latlong(latmax))-OSMNodes->latzero; + int32_t lonminbin=latlong_to_bin(radians_to_latlong(lonmin))-OSMNodes->lonzero; + int32_t lonmaxbin=latlong_to_bin(radians_to_latlong(lonmax))-OSMNodes->lonzero; + int latb,lonb,llbin; + index_t node; + + /* Loop through all of the nodes. */ + + for(latb=latminbin;latb<=latmaxbin;latb++) + for(lonb=lonminbin;lonb<=lonmaxbin;lonb++) + { + llbin=lonb*OSMNodes->latbins+latb; + + if(llbin<0 || llbin>(OSMNodes->latbins*OSMNodes->lonbins)) + continue; + + for(node=OSMNodes->offsets[llbin];nodeoffsets[llbin+1];node++) + { + double lat=latlong_to_radians(bin_to_latlong(OSMNodes->latzero+latb)+off_to_latlong(OSMNodes->nodes[node].latoffset)); + double lon=latlong_to_radians(bin_to_latlong(OSMNodes->lonzero+lonb)+off_to_latlong(OSMNodes->nodes[node].lonoffset)); + + if(lat>latmin && latlonmin && lonOtherNode(segment,node)) + if(!option_no_super || IsNormalSegment(segment)) + print_segment_osm(OSMSegments,IndexSegment(OSMSegments,segment),OSMWays); + + segment=NextSegment(OSMSegments,segment,node); + } + } + } + } + } + else + { + index_t item; + + for(item=0;itemnumber;item++) + print_node_osm(OSMNodes,item); + + for(item=0;itemnumber;item++) + if(!option_no_super || IsNormalSegment(LookupSegment(OSMSegments,item))) + print_segment_osm(OSMSegments,item,OSMWays); + } + + print_tail_osm(); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out the contents of a node from the routing database. + + Nodes *nodes The set of nodes to use. + + index_t item The node index to print. + ++++++++++++++++++++++++++++++++++++++*/ + +static void print_node(Nodes* nodes,index_t item) +{ + Node *node=LookupNode(nodes,item); + double latitude,longitude; + + GetLatLong(nodes,item,&latitude,&longitude); + + printf("Node %d\n",item); + printf(" firstseg=%d\n",SEGMENT(node->firstseg)); + printf(" latoffset=%d lonoffset=%d (latitude=%.6f longitude=%.6f)\n",node->latoffset,node->lonoffset,radians_to_degrees(latitude),radians_to_degrees(longitude)); + if(IsSuperNode(nodes,item)) + printf(" Super-Node\n"); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out the contents of a segment from the routing database. + + Segments *segments The set of segments to use. + + index_t item The segment index to print. + ++++++++++++++++++++++++++++++++++++++*/ + +static void print_segment(Segments *segments,index_t item) +{ + Segment *segment=LookupSegment(segments,item); + + printf("Segment %d\n",item); + printf(" node1=%d node2=%d\n",segment->node1,segment->node2); + printf(" next2=%d\n",segment->next2); + printf(" way=%d\n",segment->way); + printf(" distance=%d (%.3f km)\n",DISTANCE(segment->distance),distance_to_km(DISTANCE(segment->distance))); + if(IsSuperSegment(segment) && IsNormalSegment(segment)) + printf(" Super-Segment AND normal Segment\n"); + else if(IsSuperSegment(segment) && !IsNormalSegment(segment)) + printf(" Super-Segment\n"); + if(IsOnewayTo(segment,segment->node1)) + printf(" One-Way from node2 to node1\n"); + if(IsOnewayTo(segment,segment->node2)) + printf(" One-Way from node1 to node2\n"); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out the contents of a way from the routing database. + + Ways *ways The set of ways to use. + + index_t item The way index to print. + ++++++++++++++++++++++++++++++++++++++*/ + +static void print_way(Ways *ways,index_t item) +{ + Way *way=LookupWay(ways,item); + + printf("Way %d\n",item); + printf(" name=%s\n",WayNameHighway(ways,way)); + printf(" type=%02x (%s%s%s)\n",way->type,HighwayName(HIGHWAY(way->type)),way->type&Way_OneWay?",One-Way":"",way->type&Way_Roundabout?",Roundabout":""); + printf(" allow=%02x (%s)\n",way->allow,AllowedNameList(way->allow)); + if(way->props) + printf(" props=%02x (%s)\n",way->props,PropertiesNameList(way->props)); + if(way->speed) + printf(" speed=%d (%d km/hr)\n",way->speed,speed_to_kph(way->speed)); + if(way->weight) + printf(" weight=%d (%.1f tonnes)\n",way->weight,weight_to_tonnes(way->weight)); + if(way->height) + printf(" height=%d (%.1f m)\n",way->height,height_to_metres(way->height)); + if(way->width) + printf(" width=%d (%.1f m)\n",way->width,width_to_metres(way->width)); + if(way->length) + printf(" length=%d (%.1f m)\n",way->length,length_to_metres(way->length)); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out a header in OSM XML format. + ++++++++++++++++++++++++++++++++++++++*/ + +static void print_head_osm(void) +{ + printf("\n"); + printf("\n"); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out the contents of a node from the routing database in OSM XML format. + + Nodes *nodes The set of nodes to use. + + index_t item The node index to print. + ++++++++++++++++++++++++++++++++++++++*/ + +static void print_node_osm(Nodes* nodes,index_t item) +{ + double latitude,longitude; + + GetLatLong(nodes,item,&latitude,&longitude); + + if(IsSuperNode(nodes,item)) + { + printf(" \n",(unsigned long)item+1,radians_to_degrees(latitude),radians_to_degrees(longitude)); + printf(" \n"); + printf(" \n"); + } + else + printf(" \n",(unsigned long)item+1,radians_to_degrees(latitude),radians_to_degrees(longitude)); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out the contents of a segment from the routing database as a way in OSM XML format. + + Segments *segments The set of segments to use. + + index_t item The segment index to print. + + Ways *ways The set of ways to use. + ++++++++++++++++++++++++++++++++++++++*/ + +static void print_segment_osm(Segments *segments,index_t item,Ways *ways) +{ + Segment *segment=LookupSegment(segments,item); + Way *way=LookupWay(ways,segment->way); + int i; + + printf(" \n",(unsigned long)item+1); + + if(IsOnewayTo(segment,segment->node1)) + { + printf(" \n",(unsigned long)segment->node2+1); + printf(" \n",(unsigned long)segment->node1+1); + } + else + { + printf(" \n",(unsigned long)segment->node1+1); + printf(" \n",(unsigned long)segment->node2+1); + } + + if(IsSuperSegment(segment)) + printf(" \n"); + if(IsNormalSegment(segment)) + printf(" \n"); + + if(way->type & Way_OneWay) + printf(" \n"); + if(way->type & Way_Roundabout) + printf(" \n"); + + printf(" \n",HighwayName(HIGHWAY(way->type))); + + if(IsNormalSegment(segment) && WayNamed(ways,way)) + printf(" \n",ParseXML_Encode_Safe_XML(WayNameHighway(ways,way))); + + for(i=1;iallow & ALLOWED(i)) + printf(" \n",TransportName(i)); + + for(i=1;iprops & PROPERTIES(i)) + printf(" \n",PropertyName(i)); + + if(way->speed) + printf(" \n",speed_to_kph(way->speed)); + + if(way->weight) + printf(" \n",weight_to_tonnes(way->weight)); + if(way->height) + printf(" \n",height_to_metres(way->height)); + if(way->width) + printf(" \n",width_to_metres(way->width)); + if(way->length) + printf(" \n",length_to_metres(way->length)); + + printf(" \n"); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out a tail in OSM XML format. + ++++++++++++++++++++++++++++++++++++++*/ + +static void print_tail_osm(void) +{ + printf("\n"); +} + + +/*+ Conversion from time_t to date string (day of week). +*/ +static const char* const weekdays[7]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; + +/*+ Conversion from time_t to date string (month of year). +*/ +static const char* const months[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; + + +/*++++++++++++++++++++++++++++++++++++++ + Convert the time into an RFC 822 compliant date. + + char *RFC822Date Returns a pointer to a fixed string containing the date. + + time_t t The time. + ++++++++++++++++++++++++++++++++++++++*/ + +static char *RFC822Date(time_t t) +{ + static char value[32]; + char weekday[4]; + char month[4]; + struct tm *tim; + + tim=gmtime(&t); + + strcpy(weekday,weekdays[tim->tm_wday]); + strcpy(month,months[tim->tm_mon]); + + /* Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 */ + + sprintf(value,"%3s, %02d %3s %4d %02d:%02d:%02d %s", + weekday, + tim->tm_mday, + month, + tim->tm_year+1900, + tim->tm_hour, + tim->tm_min, + tim->tm_sec, + "GMT" + ); + + return(value); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out the usage information. + + int detail The level of detail to use - 0 = low, 1 = high. + ++++++++++++++++++++++++++++++++++++++*/ + +static void print_usage(int detail) +{ + fprintf(stderr, + "Usage: filedumper [--help]\n" + " [--dir=] [--prefix=]\n" + " [--statistics]\n" + " [--visualiser --latmin= --latmax=\n" + " --lonmin= --lonmax=\n" + " --data=]\n" + " [--dump [--node= ...]\n" + " [--segment= ...]\n" + " [--way= ...]]\n" + " [--dump-osm [--no-super]\n" + " [--latmin= --latmax=\n" + " --lonmin= --lonmax=]]\n"); + + if(detail) + fprintf(stderr, + "\n" + "--help Prints this information.\n" + "\n" + "--dir= The directory containing the routing database.\n" + "--prefix= The filename prefix for the routing database.\n" + "\n" + "--statistics Print statistics about the routing database.\n" + "\n" + "--visualiser Extract selected data from the routing database:\n" + " --latmin= * the minimum latitude (degrees N).\n" + " --latmax= * the maximum latitude (degrees N).\n" + " --lonmin= * the minimum longitude (degrees E).\n" + " --lonmax= * the maximum longitude (degrees E).\n" + " --data= * the type of data to select.\n" + "\n" + " can be selected from:\n" + " junctions = segment count at each junction.\n" + " super = super-node and super-segments.\n" + " oneway = oneway segments.\n" + " speed = speed limits.\n" + " weight = weight limits.\n" + " height = height limits.\n" + " width = width limits.\n" + " length = length limits.\n" + "\n" + "--dump Dump selected contents of the database.\n" + " --node= * the node with the selected number.\n" + " --segment= * the segment with the selected number.\n" + " --way= * the way with the selected number.\n" + " Use 'all' instead of a number to get all of them.\n" + "\n" + "--dump-osm Dump all or part of the database as an XML file.\n" + " --no-super * exclude the super-segments.\n" + " --latmin= * the minimum latitude (degrees N).\n" + " --latmax= * the maximum latitude (degrees N).\n" + " --lonmin= * the minimum longitude (degrees E).\n" + " --lonmax= * the maximum longitude (degrees E).\n"); + + exit(!detail); +} diff --git a/src/files.c b/src/files.c new file mode 100644 index 0000000..ce595ab --- /dev/null +++ b/src/files.c @@ -0,0 +1,372 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/files.c,v 1.18 2010/03/29 18:20:06 amb Exp $ + + Functions to handle files. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "functions.h" + + +/*+ A structure to contain the list of memory mapped files. +*/ +struct mmapinfo +{ + const char *filename; /*+ The name of the file (the index of the list). +*/ + int fd; /*+ The file descriptor used when it was opened. +*/ + void *address; /*+ The address the file was mapped to. +*/ + size_t length; /*+ The length of the file. +*/ +}; + +/*+ The list of memory mapped files. +*/ +static struct mmapinfo *mappedfiles; + +/*+ The number of mapped files. +*/ +static int nmappedfiles=0; + + +/*++++++++++++++++++++++++++++++++++++++ + Return a filename composed of the dirname, prefix and filename. + + char *FileName Returns an allocated filename. + + const char *dirname The directory name. + + const char *prefix The file prefix. + + const char *name The filename. + ++++++++++++++++++++++++++++++++++++++*/ + +char *FileName(const char *dirname,const char *prefix, const char *name) +{ + char *filename=(char*)malloc((dirname?strlen(dirname):0)+1+(prefix?strlen(prefix):0)+1+strlen(name)); + + sprintf(filename,"%s%s%s%s%s",dirname?dirname:"",dirname?"/":"",prefix?prefix:"",prefix?"-":"",name); + + return(filename); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Open a file and map it into memory. + + void *MapFile Returns the address of the file or exits in case of an error. + + const char *filename The name of the file to open. + ++++++++++++++++++++++++++++++++++++++*/ + +void *MapFile(const char *filename) +{ + int fd; + off_t size; + void *address; + + /* Open the file and get its size */ + + fd=ReOpenFile(filename); + + size=SizeFile(filename); + + /* Map the file */ + + address=mmap(NULL,size,PROT_READ,MAP_SHARED,fd,0); + + if(address==MAP_FAILED) + { + close(fd); + + fprintf(stderr,"Cannot mmap file '%s' [%s].\n",filename,strerror(errno)); + exit(EXIT_FAILURE); + } + + mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo)); + + mappedfiles[nmappedfiles].filename=filename; + mappedfiles[nmappedfiles].fd=fd; + mappedfiles[nmappedfiles].address=address; + mappedfiles[nmappedfiles].length=size; + + nmappedfiles++; + + return(address); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Unmap a file. + + void *UnmapFile Returns NULL (for similarity to the MapFile function). + + const char *filename The name of the file when it was opened. + ++++++++++++++++++++++++++++++++++++++*/ + +void *UnmapFile(const char *filename) +{ + int i; + + for(i=0;ii) + memmove(&mappedfiles[i],&mappedfiles[i+1],(nmappedfiles-i)*sizeof(struct mmapinfo)); + + return(NULL); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Open a new file on disk for writing to. + + int OpenFile Returns the file descriptor if OK or exits in case of an error. + + const char *filename The name of the file to create. + ++++++++++++++++++++++++++++++++++++++*/ + +int OpenFile(const char *filename) +{ + int fd; + + /* Open the file */ + + fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + + if(fd<0) + { + fprintf(stderr,"Cannot open file '%s' for writing [%s].\n",filename,strerror(errno)); + exit(EXIT_FAILURE); + } + + return(fd); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Open a new file on disk for reading and appending. + + int AppendFile Returns the file descriptor if OK or exits in case of an error. + + const char *filename The name of the file to create. + ++++++++++++++++++++++++++++++++++++++*/ + +int AppendFile(const char *filename) +{ + int fd; + + /* Open the file */ + + fd=open(filename,O_RDWR|O_CREAT|O_APPEND,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + + if(fd<0) + { + fprintf(stderr,"Cannot open file '%s' for appending [%s].\n",filename,strerror(errno)); + exit(EXIT_FAILURE); + } + + return(fd); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Open an existing file on disk for reading from. + + int ReOpenFile Returns the file descriptor if OK or exits in case of an error. + + const char *filename The name of the file to open. + ++++++++++++++++++++++++++++++++++++++*/ + +int ReOpenFile(const char *filename) +{ + int fd; + + /* Open the file */ + + fd=open(filename,O_RDONLY); + + if(fd<0) + { + fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno)); + exit(EXIT_FAILURE); + } + + return(fd); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Write data to a file on disk. + + int WriteFile Returns 0 if OK or something else in case of an error. + + int fd The file descriptor to write to. + + const void *address The address of the data to be written from. + + size_t length The length of data to write. + ++++++++++++++++++++++++++++++++++++++*/ + +int WriteFile(int fd,const void *address,size_t length) +{ + /* Write the data */ + + if(write(fd,address,length)!=length) + return(-1); + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Read data from a file on disk. + + int ReadFile Returns 0 if OK or something else in case of an error. + + int fd The file descriptor to read from. + + void *address The address of the data to be read into. + + size_t length The length of data to read. + ++++++++++++++++++++++++++++++++++++++*/ + +int ReadFile(int fd,void *address,size_t length) +{ + /* Read the data */ + + if(read(fd,address,length)!=length) + return(-1); + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Get the size of a file. + + off_t SizeFile Returns the file size. + + const char *filename The name of the file to check. + ++++++++++++++++++++++++++++++++++++++*/ + +off_t SizeFile(const char *filename) +{ + struct stat buf; + + if(stat(filename,&buf)) + { + fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno)); + exit(EXIT_FAILURE); + } + + return(buf.st_size); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Check if a file exists. + + int ExistsFile Returns 1 if the file exists and 0 if not. + + const char *filename The name of the file to check. + ++++++++++++++++++++++++++++++++++++++*/ + +int ExistsFile(const char *filename) +{ + struct stat buf; + + if(stat(filename,&buf)) + return(0); + else + return(1); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Seek to a position in a file on disk. + + int SeekFile Returns 0 if OK or something else in case of an error. + + int fd The file descriptor to seek within. + + off_t position The position to seek to. + ++++++++++++++++++++++++++++++++++++++*/ + +int SeekFile(int fd,off_t position) +{ + /* Seek the data */ + + if(lseek(fd,position,SEEK_SET)!=position) + return(-1); + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Close a file on disk. + + int fd The file descriptor to close. + ++++++++++++++++++++++++++++++++++++++*/ + +void CloseFile(int fd) +{ + close(fd); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Delete a file from disk. + + int DeleteFile Returns 0 if OK or something else in case of an error. + + char *filename The name of the file to delete. + ++++++++++++++++++++++++++++++++++++++*/ + +int DeleteFile(char *filename) +{ + unlink(filename); + + return(0); +} diff --git a/src/functions.h b/src/functions.h new file mode 100644 index 0000000..1ff10de --- /dev/null +++ b/src/functions.h @@ -0,0 +1,106 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/functions.h,v 1.54 2010/04/24 16:47:56 amb Exp $ + + Header file for function prototypes + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef FUNCTIONS_H +#define FUNCTIONS_H /*+ To stop multiple inclusions. +*/ + +#include +#include + +#include "types.h" +#include "profiles.h" +#include "results.h" + + +/* In router.c */ + +/*+ Return true if this is a fake node. +*/ +#define IsFakeNode(xxx) ((xxx)&NODE_SUPER) + +index_t CreateFakes(Nodes *nodes,int point,Segment *segment,index_t node1,index_t node2,distance_t dist1,distance_t dist2); + +void GetFakeLatLong(index_t node, double *latitude,double *longitude); + +Segment *FirstFakeSegment(index_t node); +Segment *NextFakeSegment(Segment *segment,index_t node); +Segment *ExtraFakeSegment(index_t node,index_t fakenode); + + +/* In files.c */ + +char *FileName(const char *dirname,const char *prefix, const char *name); + +void *MapFile(const char *filename); +void *UnmapFile(const char *filename); + +int OpenFile(const char *filename); +int AppendFile(const char *filename); +int ReOpenFile(const char *filename); + +int WriteFile(int fd,const void *address,size_t length); +int ReadFile(int fd,void *address,size_t length); + +off_t SizeFile(const char *filename); +int ExistsFile(const char *filename); + +int SeekFile(int fd,off_t position); + +void CloseFile(int fd); + +int DeleteFile(char *filename); + + +/* In optimiser.c */ + +Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,index_t start,index_t finish,Profile *profile); +Results *FindMiddleRoute(Nodes *supernodes,Segments *supersegments,Ways *superways,Results *begin,Results *end,Profile *profile); + +Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,index_t start,Profile *profile); +Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,index_t finish,Profile *profile); + +Results *CombineRoutes(Results *results,Nodes *nodes,Segments *segments,Ways *ways,Profile *profile); + +void FixForwardRoute(Results *results,index_t finish); + + +/* In output.c */ + +void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,Ways *ways,Profile *profile); + + +/* In sorting.c */ + +/*+ The type, size and alignment of variable to store the variable length +*/ +#define FILESORT_VARINT unsigned short +#define FILESORT_VARSIZE sizeof(FILESORT_VARINT) +#define FILESORT_VARALIGN sizeof(void*) + +void filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const void*,const void*),int (*buildindex)(void*,index_t)); + +void filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void*),int (*buildindex)(void*,index_t)); + +void heapsort(void **datap,size_t nitems,int(*compare)(const void*, const void*)); + + +#endif /* FUNCTIONS_H */ diff --git a/src/functionsx.h b/src/functionsx.h new file mode 100644 index 0000000..bb92183 --- /dev/null +++ b/src/functionsx.h @@ -0,0 +1,39 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/functionsx.h,v 1.5 2010/05/22 18:40:47 amb Exp $ + + Header file for function prototypes for extended data types. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef FUNCTIONSX_H +#define FUNCTIONSX_H /*+ To stop multiple inclusions. +*/ + +#include + +#include "typesx.h" +#include "profiles.h" + + +/* In osmparser.c */ + +int ParseOSM(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays); + + +#endif /* FUNCTIONSX_H */ diff --git a/src/nodes.c b/src/nodes.c new file mode 100644 index 0000000..7430d62 --- /dev/null +++ b/src/nodes.c @@ -0,0 +1,498 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/nodes.c,v 1.39 2010/07/08 17:54:54 amb Exp $ + + Node data type functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include + +#include "profiles.h" +#include "nodes.h" +#include "segments.h" +#include "ways.h" +#include "functions.h" + + +/*++++++++++++++++++++++++++++++++++++++ + Load in a node list from a file. + + Nodes* LoadNodeList Returns the node list. + + const char *filename The name of the file to load. + ++++++++++++++++++++++++++++++++++++++*/ + +Nodes *LoadNodeList(const char *filename) +{ + void *data; + Nodes *nodes; + + nodes=(Nodes*)malloc(sizeof(Nodes)); + + data=MapFile(filename); + + /* Copy the Nodes structure from the loaded data */ + + *nodes=*((Nodes*)data); + + /* Adjust the pointers in the Nodes structure. */ + + nodes->data=data; + nodes->offsets=(index_t*)(data+sizeof(Nodes)); + nodes->nodes=(Node*)(data+(sizeof(Nodes)+(nodes->latbins*nodes->lonbins+1)*sizeof(index_t))); + + return(nodes); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find the closest node given its latitude, longitude and optionally profile. + + index_t FindClosestNode Returns the closest node. + + Nodes* nodes The set of nodes to search. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + double latitude The latitude to look for. + + double longitude The longitude to look for. + + distance_t distance The maximum distance to look. + + Profile *profile The profile of the mode of transport (or NULL). + + distance_t *bestdist Returns the distance to the best node. + ++++++++++++++++++++++++++++++++++++++*/ + +index_t FindClosestNode(Nodes* nodes,Segments *segments,Ways *ways,double latitude,double longitude, + distance_t distance,Profile *profile,distance_t *bestdist) +{ + ll_bin_t latbin=latlong_to_bin(radians_to_latlong(latitude ))-nodes->latzero; + ll_bin_t lonbin=latlong_to_bin(radians_to_latlong(longitude))-nodes->lonzero; + int delta=0,count; + index_t i,bestn=NO_NODE; + distance_t bestd=INF_DISTANCE; + + /* Start with the bin containing the location, then spiral outwards. */ + + do + { + int latb,lonb,llbin; + + count=0; + + for(latb=latbin-delta;latb<=latbin+delta;latb++) + { + if(latb<0 || latb>=nodes->latbins) + continue; + + for(lonb=lonbin-delta;lonb<=lonbin+delta;lonb++) + { + if(lonb<0 || lonb>=nodes->lonbins) + continue; + + if(abs(latb-latbin)latbins+latb; + + /* Check if this grid square has any hope of being close enough */ + + if(delta>0) + { + double lat1=latlong_to_radians(bin_to_latlong(nodes->latzero+latb)); + double lon1=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb)); + double lat2=latlong_to_radians(bin_to_latlong(nodes->latzero+latb+1)); + double lon2=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb+1)); + + if(latb==latbin) + { + distance_t dist1=Distance(latitude,lon1,latitude,longitude); + distance_t dist2=Distance(latitude,lon2,latitude,longitude); + + if(dist1>distance && dist2>distance) + continue; + } + else if(lonb==lonbin) + { + distance_t dist1=Distance(lat1,longitude,latitude,longitude); + distance_t dist2=Distance(lat2,longitude,latitude,longitude); + + if(dist1>distance && dist2>distance) + continue; + } + else + { + distance_t dist1=Distance(lat1,lon1,latitude,longitude); + distance_t dist2=Distance(lat2,lon1,latitude,longitude); + distance_t dist3=Distance(lat2,lon2,latitude,longitude); + distance_t dist4=Distance(lat1,lon2,latitude,longitude); + + if(dist1>distance && dist2>distance && dist3>distance && dist4>distance) + continue; + } + } + + /* Check every node in this grid square. */ + + for(i=nodes->offsets[llbin];ioffsets[llbin+1];i++) + { + double lat=latlong_to_radians(bin_to_latlong(nodes->latzero+latb)+off_to_latlong(nodes->nodes[i].latoffset)); + double lon=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb)+off_to_latlong(nodes->nodes[i].lonoffset)); + + distance_t dist=Distance(lat,lon,latitude,longitude); + + if(distway); + + if(way->allow&profile->allow) + break; + + segment=NextSegment(segments,segment,i); + } + while(segment); + + if(!segment) + continue; + } + + bestn=i; bestd=distance=dist; + } + } + + count++; + } + } + + delta++; + } + while(count); + + *bestdist=bestd; + + return(bestn); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find the closest segment to a latitude, longitude and optionally profile. + + Segment *FindClosestSegment Returns the closest segment. + + Nodes* nodes The set of nodes to search. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + double latitude The latitude to look for. + + double longitude The longitude to look for. + + distance_t distance The maximum distance to look. + + Profile *profile The profile of the mode of transport (or NULL). + + distance_t *bestdist Returns the distance to the best segment. + + index_t *bestnode1 Returns the best node at one end. + + index_t *bestnode2 Returns the best node at the other end. + + distance_t *bestdist1 Returns the distance to the best node at one end. + + distance_t *bestdist2 Returns the distance to the best node at the other end. + ++++++++++++++++++++++++++++++++++++++*/ + +Segment *FindClosestSegment(Nodes* nodes,Segments *segments,Ways *ways,double latitude,double longitude, + distance_t distance,Profile *profile, distance_t *bestdist, + index_t *bestnode1,index_t *bestnode2,distance_t *bestdist1,distance_t *bestdist2) +{ + ll_bin_t latbin=latlong_to_bin(radians_to_latlong(latitude ))-nodes->latzero; + ll_bin_t lonbin=latlong_to_bin(radians_to_latlong(longitude))-nodes->lonzero; + int delta=0,count; + index_t i,bestn1=NO_NODE,bestn2=NO_NODE; + distance_t bestd=INF_DISTANCE,bestd1=INF_DISTANCE,bestd2=INF_DISTANCE; + Segment *bests=NULL; + + /* Start with the bin containing the location, then spiral outwards. */ + + do + { + int latb,lonb,llbin; + + count=0; + + for(latb=latbin-delta;latb<=latbin+delta;latb++) + { + if(latb<0 || latb>=nodes->latbins) + continue; + + for(lonb=lonbin-delta;lonb<=lonbin+delta;lonb++) + { + if(lonb<0 || lonb>=nodes->lonbins) + continue; + + if(abs(latb-latbin)latbins+latb; + + /* Check if this grid square has any hope of being close enough */ + + if(delta>0) + { + double lat1=latlong_to_radians(bin_to_latlong(nodes->latzero+latb)); + double lon1=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb)); + double lat2=latlong_to_radians(bin_to_latlong(nodes->latzero+latb+1)); + double lon2=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb+1)); + + if(latb==latbin) + { + distance_t dist1=Distance(latitude,lon1,latitude,longitude); + distance_t dist2=Distance(latitude,lon2,latitude,longitude); + + if(dist1>distance && dist2>distance) + continue; + } + else if(lonb==lonbin) + { + distance_t dist1=Distance(lat1,longitude,latitude,longitude); + distance_t dist2=Distance(lat2,longitude,latitude,longitude); + + if(dist1>distance && dist2>distance) + continue; + } + else + { + distance_t dist1=Distance(lat1,lon1,latitude,longitude); + distance_t dist2=Distance(lat2,lon1,latitude,longitude); + distance_t dist3=Distance(lat2,lon2,latitude,longitude); + distance_t dist4=Distance(lat1,lon2,latitude,longitude); + + if(dist1>distance && dist2>distance && dist3>distance && dist4>distance) + continue; + } + } + + /* Check every node in this grid square. */ + + for(i=nodes->offsets[llbin];ioffsets[llbin+1];i++) + { + double lat1=latlong_to_radians(bin_to_latlong(nodes->latzero+latb)+off_to_latlong(nodes->nodes[i].latoffset)); + double lon1=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb)+off_to_latlong(nodes->nodes[i].lonoffset)); + distance_t dist1; + + dist1=Distance(lat1,lon1,latitude,longitude); + + if(dist1way); + + if(!profile || way->allow&profile->allow) + { + distance_t dist2,dist3; + double lat2,lon2,dist3a,dist3b,distp; + + GetLatLong(nodes,OtherNode(segment,i),&lat2,&lon2); + + dist2=Distance(lat2,lon2,latitude,longitude); + + dist3=Distance(lat1,lon1,lat2,lon2); + + /* Use law of cosines (assume flat Earth) */ + + dist3a=((double)dist1*(double)dist1-(double)dist2*(double)dist2+(double)dist3*(double)dist3)/(2.0*(double)dist3); + dist3b=(double)dist3-dist3a; + + if(dist3a>=0 && dist3b>=0) + distp=sqrt((double)dist1*(double)dist1-dist3a*dist3a); + else if(dist3a>0) + { + distp=dist2; + dist3a=dist3; + dist3b=0; + } + else /* if(dist3b>0) */ + { + distp=dist1; + dist3a=0; + dist3b=dist3; + } + + if(distp<(double)bestd) + { + bests=segment; + bestn1=i; + bestn2=OtherNode(segment,i); + bestd1=(distance_t)dist3a; + bestd2=(distance_t)dist3b; + bestd=(distance_t)distp; + } + } + } + + segment=NextSegment(segments,segment,i); + } + while(segment); + } + + } /* dist1 < distance */ + + count++; + } + } + + delta++; + } + while(count); + + *bestdist=bestd; + + *bestnode1=bestn1; + *bestnode2=bestn2; + *bestdist1=bestd1; + *bestdist2=bestd2; + + return(bests); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Get the latitude and longitude associated with a node. + + Nodes *nodes The set of nodes. + + index_t index The node index. + + double *latitude Returns the latitude. + + double *longitude Returns the logitude. + ++++++++++++++++++++++++++++++++++++++*/ + +void GetLatLong(Nodes *nodes,index_t index,double *latitude,double *longitude) +{ + Node *node=&nodes->nodes[index]; + int latbin=-1,lonbin=-1; + int start,end,mid; + + /* Binary search - search key closest below is required. + * + * # <- start | Check mid and move start or end if it doesn't match + * # | + * # | Since an inexact match is wanted we must set end=mid-1 + * # <- mid | or start=mid because we know that mid doesn't match. + * # | + * # | Eventually either end=start or end=start+1 and one of + * # <- end | start or end is the wanted one. + */ + + /* Search for longitude */ + + start=0; + end=nodes->lonbins-1; + + do + { + mid=(start+end)/2; /* Choose mid point */ + + if(nodes->offsets[nodes->latbins*mid]offsets[nodes->latbins*mid]>index) /* Mid point is too high */ + end=mid-1; + else /* Mid point is correct */ + {lonbin=mid;break;} + } + while((end-start)>1); + + if(lonbin==-1) + { + if(nodes->offsets[nodes->latbins*end]>index) + lonbin=start; + else + lonbin=end; + } + + while(lonbinlonbins && nodes->offsets[lonbin*nodes->latbins]==nodes->offsets[(lonbin+1)*nodes->latbins]) + lonbin++; + + /* Search for latitude */ + + start=0; + end=nodes->latbins-1; + + do + { + mid=(start+end)/2; /* Choose mid point */ + + if(nodes->offsets[lonbin*nodes->latbins+mid]offsets[lonbin*nodes->latbins+mid]>index) /* Mid point is too high */ + end=mid-1; + else /* Mid point is correct */ + {latbin=mid;break;} + } + while((end-start)>1); + + if(latbin==-1) + { + if(nodes->offsets[lonbin*nodes->latbins+end]>index) + latbin=start; + else + latbin=end; + } + + while(latbinlatbins && nodes->offsets[lonbin*nodes->latbins+latbin]==nodes->offsets[lonbin*nodes->latbins+latbin+1]) + latbin++; + + /* Return the values */ + + *latitude =latlong_to_radians(bin_to_latlong(nodes->latzero+latbin)+off_to_latlong(node->latoffset)); + *longitude=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonbin)+off_to_latlong(node->lonoffset)); +} diff --git a/src/nodes.h b/src/nodes.h new file mode 100644 index 0000000..8bfc2b6 --- /dev/null +++ b/src/nodes.h @@ -0,0 +1,94 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/nodes.h,v 1.30 2009/11/14 19:39:19 amb Exp $ + + A header file for the nodes. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008,2009 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef NODES_H +#define NODES_H /*+ To stop multiple inclusions. +*/ + +#include + +#include "types.h" +#include "profiles.h" + + +/* Data structures */ + + +/*+ A structure containing a single node. +*/ +struct _Node +{ + index_t firstseg; /*+ The index of the first segment. +*/ + + ll_off_t latoffset; /*+ The node latitude offset within its bin. +*/ + ll_off_t lonoffset; /*+ The node longitude offset within its bin. +*/ +}; + + +/*+ A structure containing a set of nodes (mmap format). +*/ +struct _Nodes +{ + uint32_t number; /*+ How many nodes in total? +*/ + uint32_t snumber; /*+ How many super-nodes? +*/ + + uint32_t latbins; /*+ The number of bins containing latitude. +*/ + uint32_t lonbins; /*+ The number of bins containing longitude. +*/ + + ll_bin_t latzero; /*+ The bin number of the furthest south bin. +*/ + ll_bin_t lonzero; /*+ The bin number of the furthest west bin. +*/ + + index_t *offsets; /*+ An array of offset to the first node in each bin. +*/ + + Node *nodes; /*+ An array of nodes. +*/ + + void *data; /*+ The memory mapped data. +*/ +}; + + +/* Macros */ + +/*+ Return a Node pointer given a set of nodes and an index. +*/ +#define LookupNode(xxx,yyy) (&(xxx)->nodes[yyy]) + +/*+ Return a Segment points given a Node pointer and a set of segments. +*/ +#define FirstSegment(xxx,yyy,zzz) LookupSegment((xxx),SEGMENT((yyy)->nodes[zzz].firstseg)) + +/*+ Return true if this is a super-node. +*/ +#define IsSuperNode(xxx,yyy) (((xxx)->nodes[yyy].firstseg)&NODE_SUPER) + + +/* Functions */ + + +Nodes *LoadNodeList(const char *filename); + +index_t FindClosestNode(Nodes* nodes,Segments *segments,Ways *ways,double latitude,double longitude, + distance_t distance,Profile *profile,distance_t *bestdist); + +Segment *FindClosestSegment(Nodes* nodes,Segments *segments,Ways *ways,double latitude,double longitude, + distance_t distance,Profile *profile, distance_t *bestdist, + index_t *bestnode1,index_t *bestnode2,distance_t *bestdist1,distance_t *bestdist2); + +void GetLatLong(Nodes *nodes,index_t index,double *latitude,double *longitude); + + +#endif /* NODES_H */ diff --git a/src/nodesx.c b/src/nodesx.c new file mode 100644 index 0000000..cc1e0a2 --- /dev/null +++ b/src/nodesx.c @@ -0,0 +1,894 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/nodesx.c,v 1.56 2010/04/28 17:27:02 amb Exp $ + + Extented Node data type functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include +#include + +#include "types.h" +#include "functions.h" +#include "nodesx.h" +#include "segmentsx.h" +#include "waysx.h" +#include "segments.h" +#include "nodes.h" + + +/* Variables */ + +/*+ The command line '--slim' option. +*/ +extern int option_slim; + +/*+ The command line '--tmpdir' option or its default value. +*/ +extern char *option_tmpdirname; + +/*+ A temporary file-local variable for use by the sort functions. +*/ +static NodesX *sortnodesx; + +/* Functions */ + +static int sort_by_id(NodeX *a,NodeX *b); +static int index_by_id(NodeX *nodex,index_t index); + +static int sort_by_lat_long(NodeX *a,NodeX *b); +static int index_by_lat_long(NodeX *nodex,index_t index); + + +/*++++++++++++++++++++++++++++++++++++++ + Allocate a new node list (create a new file or open an existing one). + + NodesX *NewNodeList Returns the node list. + + int append Set to 1 if the file is to be opened for appending (now or later). + ++++++++++++++++++++++++++++++++++++++*/ + +NodesX *NewNodeList(int append) +{ + NodesX *nodesx; + + nodesx=(NodesX*)calloc(1,sizeof(NodesX)); + + assert(nodesx); /* Check calloc() worked */ + + nodesx->filename=(char*)malloc(strlen(option_tmpdirname)+32); + + if(append) + sprintf(nodesx->filename,"%s/nodes.input.tmp",option_tmpdirname); + else + sprintf(nodesx->filename,"%s/nodes.%p.tmp",option_tmpdirname,nodesx); + + if(append) + { + off_t size; + + nodesx->fd=AppendFile(nodesx->filename); + + size=SizeFile(nodesx->filename); + + nodesx->xnumber=size/sizeof(NodeX); + } + else + nodesx->fd=OpenFile(nodesx->filename); + + return(nodesx); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Free a node list. + + NodesX *nodesx The list to be freed. + + int keep Set to 1 if the file is to be kept. + ++++++++++++++++++++++++++++++++++++++*/ + +void FreeNodeList(NodesX *nodesx,int keep) +{ + if(!keep) + DeleteFile(nodesx->filename); + + free(nodesx->filename); + + if(nodesx->idata) + free(nodesx->idata); + + if(nodesx->ndata) + free(nodesx->ndata); + + if(nodesx->super) + free(nodesx->super); + + if(nodesx->offsets) + free(nodesx->offsets); + + free(nodesx); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Append a node to a newly created node list (unsorted). + + NodesX* nodesx The set of nodes to process. + + node_t id The node identification. + + double latitude The latitude of the node. + + double longitude The longitude of the node. + ++++++++++++++++++++++++++++++++++++++*/ + +void AppendNode(NodesX* nodesx,node_t id,double latitude,double longitude) +{ + NodeX nodex; + + assert(!nodesx->idata); /* Must not have idata filled in => unsorted */ + + nodex.id=id; + nodex.latitude =radians_to_latlong(latitude); + nodex.longitude=radians_to_latlong(longitude); + + WriteFile(nodesx->fd,&nodex,sizeof(NodeX)); + + nodesx->xnumber++; +} + + +/*++++++++++++++++++++++++++++++++++++++ + Sort the node list (i.e. create the sortable indexes). + + NodesX* nodesx The set of nodes to process. + ++++++++++++++++++++++++++++++++++++++*/ + +void SortNodeList(NodesX* nodesx) +{ + int fd; + + /* Check the start conditions */ + + assert(!nodesx->idata); /* Must not have idata filled in => unsorted */ + + /* Print the start message */ + + printf("Sorting Nodes"); + fflush(stdout); + + /* Close the files and re-open them (finished appending) */ + + CloseFile(nodesx->fd); + nodesx->fd=ReOpenFile(nodesx->filename); + + DeleteFile(nodesx->filename); + + fd=OpenFile(nodesx->filename); + + /* Allocate the array of indexes */ + + nodesx->idata=(node_t*)malloc(nodesx->xnumber*sizeof(node_t)); + + assert(nodesx->idata); /* Check malloc() worked */ + + /* Sort by node indexes */ + + sortnodesx=nodesx; + + filesort_fixed(nodesx->fd,fd,sizeof(NodeX),(int (*)(const void*,const void*))sort_by_id,(int (*)(void*,index_t))index_by_id); + + /* Close the files and re-open them */ + + CloseFile(nodesx->fd); + CloseFile(fd); + + nodesx->fd=ReOpenFile(nodesx->filename); + + /* Print the final message */ + + printf("\rSorted Nodes: Nodes=%d Duplicates=%d\n",nodesx->xnumber,nodesx->xnumber-nodesx->number); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Sort the nodes into id order. + + int sort_by_id Returns the comparison of the id fields. + + NodeX *a The first extended node. + + NodeX *b The second extended node. + ++++++++++++++++++++++++++++++++++++++*/ + +static int sort_by_id(NodeX *a,NodeX *b) +{ + node_t a_id=a->id; + node_t b_id=b->id; + + if(a_idb_id) + return(1); + else + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Index the nodes after sorting. + + int index_by_id Return 1 if the value is to be kept, otherwise zero. + + NodeX *nodex The extended node. + + index_t index The index of this node in the total. + ++++++++++++++++++++++++++++++++++++++*/ + +static int index_by_id(NodeX *nodex,index_t index) +{ + if(index==0 || sortnodesx->idata[index-1]!=nodex->id) + { + sortnodesx->idata[index]=nodex->id; + + sortnodesx->number++; + + return(1); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Sort the node list geographically. + + NodesX* nodesx The set of nodes to process. + ++++++++++++++++++++++++++++++++++++++*/ + +void SortNodeListGeographically(NodesX* nodesx) +{ + int fd; + + /* Print the start message */ + + printf("Sorting Nodes Geographically"); + fflush(stdout); + + /* Allocate the memory for the geographical offsets array */ + + nodesx->offsets=(index_t*)malloc((nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t)); + + nodesx->latlonbin=0; + + /* Close the files and re-open them */ + + CloseFile(nodesx->fd); + nodesx->fd=ReOpenFile(nodesx->filename); + + DeleteFile(nodesx->filename); + + fd=OpenFile(nodesx->filename); + + /* Sort geographically */ + + sortnodesx=nodesx; + + filesort_fixed(nodesx->fd,fd,sizeof(NodeX),(int (*)(const void*,const void*))sort_by_lat_long,(int (*)(void*,index_t))index_by_lat_long); + + /* Close the files and re-open them */ + + CloseFile(nodesx->fd); + CloseFile(fd); + + nodesx->fd=ReOpenFile(nodesx->filename); + + /* Finish off the indexing */ + + for(;nodesx->latlonbin<=(nodesx->latbins*nodesx->lonbins);nodesx->latlonbin++) + nodesx->offsets[nodesx->latlonbin]=nodesx->number; + + /* Print the final message */ + + printf("\rSorted Nodes Geographically \n"); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Sort the nodes into latitude and longitude order. + + int sort_by_lat_long Returns the comparison of the latitude and longitude fields. + + NodeX *a The first extended node. + + NodeX *b The second extended node. + ++++++++++++++++++++++++++++++++++++++*/ + +static int sort_by_lat_long(NodeX *a,NodeX *b) +{ + ll_bin_t a_lon=latlong_to_bin(a->longitude); + ll_bin_t b_lon=latlong_to_bin(b->longitude); + + if(a_lonb_lon) + return(1); + else + { + ll_bin_t a_lat=latlong_to_bin(a->latitude); + ll_bin_t b_lat=latlong_to_bin(b->latitude); + + if(a_latb_lat) + return(1); + else + { +#ifdef REGRESSION_TESTING + // Need this for regression testing because heapsort() is not order + // preserving like qsort() is (or was when tested). + + index_t a_id=a->id; + index_t b_id=b->id; + + if(a_idb_id) + return(1); + else +#endif + return(0); + } + } +} + + +/*++++++++++++++++++++++++++++++++++++++ + Index the nodes after sorting. + + int index_by_lat_long Return 1 if the value is to be kept, otherwise zero. + + NodeX *nodex The extended node. + + index_t index The index of this node in the total. + ++++++++++++++++++++++++++++++++++++++*/ + +static int index_by_lat_long(NodeX *nodex,index_t index) +{ + /* Work out the offsets */ + + ll_bin_t latbin=latlong_to_bin(nodex->latitude )-sortnodesx->latzero; + ll_bin_t lonbin=latlong_to_bin(nodex->longitude)-sortnodesx->lonzero; + int llbin=lonbin*sortnodesx->latbins+latbin; + + for(;sortnodesx->latlonbin<=llbin;sortnodesx->latlonbin++) + sortnodesx->offsets[sortnodesx->latlonbin]=index; + + return(1); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find a particular node index. + + index_t IndexNodeX Returns the index of the extended node with the specified id. + + NodesX* nodesx The set of nodes to process. + + node_t id The node id to look for. + ++++++++++++++++++++++++++++++++++++++*/ + +index_t IndexNodeX(NodesX* nodesx,node_t id) +{ + int start=0; + int end=nodesx->number-1; + int mid; + + assert(nodesx->idata); /* Must have idata filled in => sorted by id */ + + /* Binary search - search key exact match only is required. + * + * # <- start | Check mid and move start or end if it doesn't match + * # | + * # | Since an exact match is wanted we can set end=mid-1 + * # <- mid | or start=mid+1 because we know that mid doesn't match. + * # | + * # | Eventually either end=start or end=start+1 and one of + * # <- end | start or end is the wanted one. + */ + + if(endidata[start]) /* Check key is not before start */ + return(NO_NODE); + else if(id>nodesx->idata[end]) /* Check key is not after end */ + return(NO_NODE); + else + { + do + { + mid=(start+end)/2; /* Choose mid point */ + + if(nodesx->idata[mid]idata[mid]>id) /* Mid point is too high */ + end=mid-1; + else /* Mid point is correct */ + return(mid); + } + while((end-start)>1); + + if(nodesx->idata[start]==id) /* Start is correct */ + return(start); + + if(nodesx->idata[end]==id) /* End is correct */ + return(end); + } + + return(NO_NODE); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Lookup a particular node. + + NodeX *LookupNodeX Returns a pointer to the extended node with the specified id. + + NodesX* nodesx The set of nodes to process. + + index_t index The node index to look for. + + int position The position in the cache to use. + ++++++++++++++++++++++++++++++++++++++*/ + +NodeX *LookupNodeX(NodesX* nodesx,index_t index,int position) +{ + assert(index!=NO_NODE); /* Must be a valid node */ + + if(option_slim) + { + SeekFile(nodesx->fd,index*sizeof(NodeX)); + + ReadFile(nodesx->fd,&nodesx->cached[position-1],sizeof(NodeX)); + + return(&nodesx->cached[position-1]); + } + else + { + return(&nodesx->xdata[index]); + } +} + + +/*++++++++++++++++++++++++++++++++++++++ + Remove any nodes that are not part of a highway. + + NodesX *nodesx The complete node list. + + SegmentsX *segmentsx The list of segments. + ++++++++++++++++++++++++++++++++++++++*/ + +void RemoveNonHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx) +{ + NodeX nodex; + int total=0,highway=0,nothighway=0; + ll_bin_t lat_min_bin,lat_max_bin,lon_min_bin,lon_max_bin; + latlong_t lat_min,lat_max,lon_min,lon_max; + int fd; + + /* Check the start conditions */ + + assert(nodesx->idata); /* Must have idata filled in => data sorted */ + + /* Print the start message */ + + printf("Checking: Nodes=0"); + fflush(stdout); + + /* While we are here we can work out the range of data */ + + lat_min=radians_to_latlong( 2); + lat_max=radians_to_latlong(-2); + lon_min=radians_to_latlong( 4); + lon_max=radians_to_latlong(-4); + + /* Modify the on-disk image */ + + DeleteFile(nodesx->filename); + + fd=OpenFile(nodesx->filename); + SeekFile(nodesx->fd,0); + + while(!ReadFile(nodesx->fd,&nodex,sizeof(NodeX))) + { + if(IndexFirstSegmentX(segmentsx,nodex.id)==NO_SEGMENT) + nothighway++; + else + { + nodex.id=highway; + + WriteFile(fd,&nodex,sizeof(NodeX)); + + nodesx->idata[highway]=nodesx->idata[total]; + highway++; + + if(nodex.latitudelat_max) + lat_max=nodex.latitude; + if(nodex.longitudelon_max) + lon_max=nodex.longitude; + } + + total++; + + if(!(total%10000)) + { + printf("\rChecking: Nodes=%d Highway=%d not-Highway=%d",total,highway,nothighway); + fflush(stdout); + } + } + + /* Close the files and re-open them */ + + CloseFile(nodesx->fd); + CloseFile(fd); + + nodesx->fd=ReOpenFile(nodesx->filename); + + nodesx->number=highway; + + /* Work out the number of bins */ + + lat_min_bin=latlong_to_bin(lat_min); + lon_min_bin=latlong_to_bin(lon_min); + lat_max_bin=latlong_to_bin(lat_max); + lon_max_bin=latlong_to_bin(lon_max); + + nodesx->latzero=lat_min_bin; + nodesx->lonzero=lon_min_bin; + + nodesx->latbins=(lat_max_bin-lat_min_bin)+1; + nodesx->lonbins=(lon_max_bin-lon_min_bin)+1; + + /* Allocate and clear the super-node markers */ + + nodesx->super=(uint8_t*)calloc(nodesx->number,sizeof(uint8_t)); + + assert(nodesx->super); /* Check calloc() worked */ + + /* Print the final message */ + + printf("\rChecked: Nodes=%d Highway=%d not-Highway=%d \n",total,highway,nothighway); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Create the real node data. + + NodesX *nodesx The set of nodes to use. + + int iteration The final super-node iteration. + ++++++++++++++++++++++++++++++++++++++*/ + +void CreateRealNodes(NodesX *nodesx,int iteration) +{ + index_t i; + + /* Check the start conditions */ + + assert(!nodesx->ndata); /* Must not have ndata filled in => no real nodes */ + + /* Print the start message */ + + printf("Creating Real Nodes: Nodes=0"); + fflush(stdout); + + /* Map into memory */ + + if(!option_slim) + nodesx->xdata=MapFile(nodesx->filename); + + /* Allocate the memory */ + + nodesx->ndata=(Node*)malloc(nodesx->number*sizeof(Node)); + + assert(nodesx->ndata); /* Check malloc() worked */ + + /* Loop through and allocate. */ + + for(i=0;inumber;i++) + { + NodeX *nodex=LookupNodeX(nodesx,i,1); + + nodesx->ndata[nodex->id].latoffset=latlong_to_off(nodex->latitude); + nodesx->ndata[nodex->id].lonoffset=latlong_to_off(nodex->longitude); + nodesx->ndata[nodex->id].firstseg=SEGMENT(NO_SEGMENT); + + if(nodesx->super[nodex->id]==iteration) + nodesx->ndata[nodex->id].firstseg|=NODE_SUPER; + + if(!((i+1)%10000)) + { + printf("\rCreating Real Nodes: Nodes=%d",i+1); + fflush(stdout); + } + } + + /* Free the unneeded memory */ + + free(nodesx->super); + nodesx->super=NULL; + + /* Unmap from memory */ + + if(!option_slim) + nodesx->xdata=UnmapFile(nodesx->filename); + + /* Print the final message */ + + printf("\rCreating Real Nodes: Nodes=%d \n",nodesx->number); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Assign the segment indexes to the nodes. + + NodesX *nodesx The list of nodes to process. + + SegmentsX* segmentsx The set of segments to use. + ++++++++++++++++++++++++++++++++++++++*/ + +void IndexNodes(NodesX *nodesx,SegmentsX *segmentsx) +{ + index_t i; + + /* Check the start conditions */ + + assert(nodesx->ndata); /* Must have ndata filled in => real nodes exist */ + assert(segmentsx->sdata); /* Must have sdata filled in => real segments exist */ + + /* Print the start message */ + + printf("Indexing Segments: Segments=0"); + fflush(stdout); + + /* Map into memory */ + + if(!option_slim) + { + nodesx->xdata=MapFile(nodesx->filename); + segmentsx->xdata=MapFile(segmentsx->filename); + } + + /* Index the nodes */ + + for(i=0;inumber;i++) + { + SegmentX *segmentx=LookupSegmentX(segmentsx,i,1); + node_t id1=segmentx->node1; + node_t id2=segmentx->node2; + Node *node1=&nodesx->ndata[id1]; + Node *node2=&nodesx->ndata[id2]; + + /* Check node1 */ + + if(SEGMENT(node1->firstseg)==SEGMENT(NO_SEGMENT)) + { + node1->firstseg^=SEGMENT(NO_SEGMENT); + node1->firstseg|=i; + } + else + { + index_t index=SEGMENT(node1->firstseg); + + do + { + segmentx=LookupSegmentX(segmentsx,index,1); + + if(segmentx->node1==id1) + { + index++; + + if(index>=segmentsx->number) + break; + + segmentx=LookupSegmentX(segmentsx,index,1); + + if(segmentx->node1!=id1) + break; + } + else + { + if(segmentsx->sdata[index].next2==NO_NODE) + { + segmentsx->sdata[index].next2=i; + break; + } + else + index=segmentsx->sdata[index].next2; + } + } + while(1); + } + + /* Check node2 */ + + if(SEGMENT(node2->firstseg)==SEGMENT(NO_SEGMENT)) + { + node2->firstseg^=SEGMENT(NO_SEGMENT); + node2->firstseg|=i; + } + else + { + index_t index=SEGMENT(node2->firstseg); + + do + { + segmentx=LookupSegmentX(segmentsx,index,1); + + if(segmentx->node1==id2) + { + index++; + + if(index>=segmentsx->number) + break; + + segmentx=LookupSegmentX(segmentsx,index,1); + + if(segmentx->node1!=id2) + break; + } + else + { + if(segmentsx->sdata[index].next2==NO_NODE) + { + segmentsx->sdata[index].next2=i; + break; + } + else + index=segmentsx->sdata[index].next2; + } + } + while(1); + } + + if(!((i+1)%10000)) + { + printf("\rIndexing Segments: Segments=%d",i+1); + fflush(stdout); + } + } + + /* Unmap from memory */ + + if(!option_slim) + { + nodesx->xdata=UnmapFile(nodesx->filename); + segmentsx->xdata=UnmapFile(segmentsx->filename); + } + + /* Print the final message */ + + printf("\rIndexed Segments: Segments=%d \n",segmentsx->number); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Save the node list to a file. + + NodesX* nodesx The set of nodes to save. + + const char *filename The name of the file to save. + ++++++++++++++++++++++++++++++++++++++*/ + +void SaveNodeList(NodesX* nodesx,const char *filename) +{ + index_t i; + int fd; + Nodes *nodes; + int super_number=0; + + /* Check the start conditions */ + + assert(nodesx->ndata); /* Must have ndata filled in => real nodes exist */ + + /* Print the start message */ + + printf("Writing Nodes: Nodes=0"); + fflush(stdout); + + /* Map into memory */ + + if(!option_slim) + nodesx->xdata=MapFile(nodesx->filename); + + /* Count the number of super-nodes */ + + for(i=0;inumber;i++) + if(nodesx->ndata[i].firstseg&NODE_SUPER) + super_number++; + + /* Fill in a Nodes structure with the offset of the real data in the file after + the Node structure itself. */ + + nodes=calloc(1,sizeof(Nodes)); + + assert(nodes); /* Check calloc() worked */ + + nodes->number=nodesx->number; + nodes->snumber=super_number; + + nodes->latbins=nodesx->latbins; + nodes->lonbins=nodesx->lonbins; + + nodes->latzero=nodesx->latzero; + nodes->lonzero=nodesx->lonzero; + + nodes->data=NULL; + nodes->offsets=NULL; + nodes->nodes=NULL; + + /* Write out the Nodes structure and then the real data. */ + + fd=OpenFile(filename); + + WriteFile(fd,nodes,sizeof(Nodes)); + + WriteFile(fd,nodesx->offsets,(nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t)); + + for(i=0;inumber;i++) + { + NodeX *nodex=LookupNodeX(nodesx,i,1); + Node *node=&nodesx->ndata[nodex->id]; + + WriteFile(fd,node,sizeof(Node)); + + if(!((i+1)%10000)) + { + printf("\rWriting Nodes: Nodes=%d",i+1); + fflush(stdout); + } + } + + CloseFile(fd); + + /* Unmap from memory */ + + if(!option_slim) + nodesx->xdata=UnmapFile(nodesx->filename); + + /* Print the final message */ + + printf("\rWrote Nodes: Nodes=%d \n",nodes->number); + fflush(stdout); + + /* Free the fake Nodes */ + + free(nodes); +} diff --git a/src/nodesx.h b/src/nodesx.h new file mode 100644 index 0000000..2dc40a4 --- /dev/null +++ b/src/nodesx.h @@ -0,0 +1,100 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/nodesx.h,v 1.23 2010/03/19 19:47:09 amb Exp $ + + A header file for the extended nodes. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef NODESX_H +#define NODESX_H /*+ To stop multiple inclusions. +*/ + +#include + +#include "typesx.h" +#include "types.h" + + +/* Data structures */ + + +/*+ An extended structure used for processing. +*/ +struct _NodeX +{ + node_t id; /*+ The node identifier. +*/ + + latlong_t latitude; /*+ The node latitude. +*/ + latlong_t longitude; /*+ The node longitude. +*/ +}; + +/*+ A structure containing a set of nodes (memory format). +*/ +struct _NodesX +{ + char *filename; /*+ The name of the temporary file. +*/ + int fd; /*+ The file descriptor of the temporary file. +*/ + + uint32_t xnumber; /*+ The number of unsorted extended nodes. +*/ + + NodeX *xdata; /*+ The extended node data (sorted). +*/ + NodeX cached[2]; /*+ Two cached nodes read from the file in slim mode. +*/ + + uint32_t number; /*+ How many entries are still useful? +*/ + + node_t *idata; /*+ The extended node IDs (sorted by ID). +*/ + + uint8_t *super; /*+ A marker for super nodes (same order sorted nodes). +*/ + + Node *ndata; /*+ The actual nodes (same order as geographically sorted nodes). +*/ + + uint32_t latbins; /*+ The number of bins containing latitude. +*/ + uint32_t lonbins; /*+ The number of bins containing longitude. +*/ + + ll_bin_t latzero; /*+ The bin number of the furthest south bin. +*/ + ll_bin_t lonzero; /*+ The bin number of the furthest west bin. +*/ + + uint32_t latlonbin; /*+ A temporary index into the offsets array. +*/ + + index_t *offsets; /*+ An array of offset to the first node in each bin. +*/ +}; + + +/* Functions */ + +NodesX *NewNodeList(int append); +void FreeNodeList(NodesX *nodesx,int keep); + +void SaveNodeList(NodesX *nodesx,const char *filename); + +index_t IndexNodeX(NodesX* nodesx,node_t id); +NodeX *LookupNodeX(NodesX* nodesx,index_t index,int position); + +void AppendNode(NodesX* nodesx,node_t id,double latitude,double longitude); + +void SortNodeList(NodesX *nodesx); + +void SortNodeListGeographically(NodesX* nodesx); + +void RemoveNonHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx); + +void CreateRealNodes(NodesX *nodesx,int iteration); + +void IndexNodes(NodesX *nodesx,SegmentsX *segmentsx); + + +#endif /* NODESX_H */ diff --git a/src/optimiser.c b/src/optimiser.c new file mode 100644 index 0000000..cdb5986 --- /dev/null +++ b/src/optimiser.c @@ -0,0 +1,922 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/optimiser.c,v 1.87 2010/07/08 17:33:09 amb Exp $ + + Routing optimiser. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include + +#include "types.h" +#include "functions.h" +#include "nodes.h" +#include "segments.h" +#include "ways.h" +#include "results.h" + + +/*+ The option not to print any progress information. +*/ +extern int option_quiet; + +/*+ The option to calculate the quickest route insted of the shortest. +*/ +extern int option_quickest; + + +/*++++++++++++++++++++++++++++++++++++++ + Find the optimum route between two nodes not passing through a super-node. + + Results *FindNormalRoute Returns a set of results. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + index_t start The start node. + + index_t finish The finish node. + + Profile *profile The profile containing the transport type, speeds and allowed highways. + ++++++++++++++++++++++++++++++++++++++*/ + +Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,index_t start,index_t finish,Profile *profile) +{ + Results *results; + Queue *queue; + index_t node1,node2; + score_t finish_score; + double finish_lat,finish_lon; + Result *result1,*result2; + Segment *segment; + Way *way; + + /* Set up the finish conditions */ + + finish_score=INF_SCORE; + + if(IsFakeNode(finish)) + GetFakeLatLong(finish,&finish_lat,&finish_lon); + else + GetLatLong(nodes,finish,&finish_lat,&finish_lon); + + /* Create the list of results and insert the first node into the queue */ + + results=NewResultsList(8); + + results->start=start; + results->finish=finish; + + result1=InsertResult(results,start); + + ZeroResult(result1); + + queue=NewQueueList(); + + InsertInQueue(queue,result1); + + /* Loop across all nodes in the queue */ + + while((result1=PopFromQueue(queue))) + { + if(result1->score>finish_score) + continue; + + node1=result1->node; + + if(IsFakeNode(node1)) + segment=FirstFakeSegment(node1); + else + segment=FirstSegment(segments,nodes,node1); + + while(segment) + { + score_t segment_pref,segment_score,cumulative_score; + int i; + + node2=OtherNode(segment,node1); /* need this here because we use node2 later */ + + if(!IsNormalSegment(segment)) + goto endloop; + + if(profile->oneway && IsOnewayTo(segment,node1)) + goto endloop; + + if(result1->prev==node2) + goto endloop; + + if(node2!=finish && !IsFakeNode(node2) && IsSuperNode(nodes,node2)) + goto endloop; + + way=LookupWay(ways,segment->way); + + if(!(way->allow&profile->allow)) + goto endloop; + + if(!profile->highway[HIGHWAY(way->type)]) + goto endloop; + + if(way->weight && way->weightweight) + goto endloop; + + if((way->height && way->heightheight) || + (way->width && way->width width ) || + (way->length && way->lengthlength)) + goto endloop; + + segment_pref=profile->highway[HIGHWAY(way->type)]; + + for(i=1;iprops & PROPERTIES(i)) + { + if(way->props & PROPERTIES(i)) + segment_pref*=profile->props_yes[i]; + else + segment_pref*=profile->props_no[i]; + } + + if(segment_pref==0) + goto endloop; + + if(option_quickest==0) + segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; + else + segment_score=(score_t)Duration(segment,way,profile)/segment_pref; + + cumulative_score=result1->score+segment_score; + + if(cumulative_score>finish_score) + goto endloop; + + result2=FindResult(results,node2); + + if(!result2) /* New end node */ + { + result2=InsertResult(results,node2); + result2->prev=node1; + result2->next=NO_NODE; + result2->score=cumulative_score; + result2->segment=segment; + + if(node2==finish) + { + finish_score=cumulative_score; + } + else + { + result2->sortby=result2->score; + + InsertInQueue(queue,result2); + } + } + else if(cumulative_scorescore) /* New end node is better */ + { + result2->prev=node1; + result2->score=cumulative_score; + result2->segment=segment; + + if(node2==finish) + { + finish_score=cumulative_score; + } + else + { + result2->sortby=result2->score; + + if(result2->scorefinish)) + GetFakeLatLong(end->finish,&finish_lat,&finish_lon); + else + GetLatLong(nodes,end->finish,&finish_lat,&finish_lon); + + /* Create the list of results and insert the first node into the queue */ + + results=NewResultsList(2048); + + results->start=begin->start; + results->finish=end->finish; + + result1=InsertResult(results,begin->start); + result3=FindResult(begin,begin->start); + + *result1=*result3; + + queue=NewQueueList(); + + /* Insert the finish points of the beginning part of the path into the queue */ + + result3=FirstResult(begin); + + while(result3) + { + if(result3->node!=begin->start && !IsFakeNode(result3->node) && IsSuperNode(nodes,result3->node)) + { + result2=InsertResult(results,result3->node); + + *result2=*result3; + + result2->prev=begin->start; + + result2->sortby=result2->score; + + InsertInQueue(queue,result2); + } + + result3=NextResult(begin,result3); + } + + if(begin->number==1) + InsertInQueue(queue,result1); + + /* Loop across all nodes in the queue */ + + while((result1=PopFromQueue(queue))) + { + if(result1->score>finish_score) + continue; + + node1=result1->node; + + segment=FirstSegment(segments,nodes,node1); + + while(segment) + { + score_t segment_pref,segment_score,cumulative_score; + int i; + + if(!IsSuperSegment(segment)) + goto endloop; + + if(profile->oneway && IsOnewayTo(segment,node1)) + goto endloop; + + node2=OtherNode(segment,node1); + + if(result1->prev==node2) + goto endloop; + + way=LookupWay(ways,segment->way); + + if(!(way->allow&profile->allow)) + goto endloop; + + if(!profile->highway[HIGHWAY(way->type)]) + goto endloop; + + if(way->weight && way->weightweight) + goto endloop; + + if((way->height && way->heightheight) || + (way->width && way->width width ) || + (way->length && way->lengthlength)) + goto endloop; + + segment_pref=profile->highway[HIGHWAY(way->type)]; + + for(i=1;iprops & PROPERTIES(i)) + { + if(way->props & PROPERTIES(i)) + segment_pref*=profile->props_yes[i]; + else + segment_pref*=profile->props_no[i]; + } + + if(segment_pref==0) + goto endloop; + + if(option_quickest==0) + segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; + else + segment_score=(score_t)Duration(segment,way,profile)/segment_pref; + + cumulative_score=result1->score+segment_score; + + if(cumulative_score>finish_score) + goto endloop; + + result2=FindResult(results,node2); + + if(!result2) /* New end node */ + { + result2=InsertResult(results,node2); + result2->prev=node1; + result2->next=NO_NODE; + result2->score=cumulative_score; + result2->segment=segment; + + if((result3=FindResult(end,node2))) + { + if((result2->score+result3->score)score+result3->score; + end_prev=node2; + } + } + else + { + double lat,lon; + distance_t direct; + + GetLatLong(nodes,node2,&lat,&lon); + direct=Distance(lat,lon,finish_lat,finish_lon); + + if(option_quickest==0) + result2->sortby=result2->score+(score_t)direct/profile->max_pref; + else + result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; + + InsertInQueue(queue,result2); + } + } + else if(cumulative_scorescore) /* New end node is better */ + { + result2->prev=node1; + result2->score=cumulative_score; + result2->segment=segment; + + if((result3=FindResult(end,node2))) + { + if((result2->score+result3->score)score+result3->score; + end_prev=node2; + } + } + else if(result2->scoresortby=result2->score+(score_t)direct/profile->max_pref; + else + result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; + + InsertInQueue(queue,result2); + } + } + + endloop: + + if(!option_quiet && !(results->number%10000)) + { + printf("\rRouting: Super-Nodes checked = %d",results->number); + fflush(stdout); + } + + segment=NextSegment(segments,segment,node1); + } + } + + if(!option_quiet) + { + printf("\rRouting: Super-Nodes checked = %d\n",results->number); + fflush(stdout); + } + + /* Finish off the end part of the route. */ + + if(!FindResult(results,end->finish) && end_prev!=NO_NODE) + { + result2=InsertResult(results,end->finish); + result3=FindResult(end,end->finish); + + *result2=*result3; + + result2->prev=end_prev; + result2->score=finish_score; + } + + FreeQueueList(queue); + + /* Check it worked */ + + if(end_prev==NO_NODE) + { + FreeResultsList(results); + return(NULL); + } + + FixForwardRoute(results,end->finish); + + return(results); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find all routes from a specified node to any super-node. + + Results *FindStartRoutes Returns a set of results. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + index_t start The start node. + + Profile *profile The profile containing the transport type, speeds and allowed highways. + ++++++++++++++++++++++++++++++++++++++*/ + +Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,index_t start,Profile *profile) +{ + Results *results; + Queue *queue; + index_t node1,node2; + Result *result1,*result2; + Segment *segment; + Way *way; + + /* Insert the first node into the queue */ + + results=NewResultsList(8); + + results->start=start; + + result1=InsertResult(results,start); + + ZeroResult(result1); + + queue=NewQueueList(); + + InsertInQueue(queue,result1); + + /* Loop across all nodes in the queue */ + + while((result1=PopFromQueue(queue))) + { + node1=result1->node; + + if(IsFakeNode(node1)) + segment=FirstFakeSegment(node1); + else + segment=FirstSegment(segments,nodes,node1); + + while(segment) + { + score_t segment_pref,segment_score,cumulative_score; + int i; + + if(!IsNormalSegment(segment)) + goto endloop; + + if(profile->oneway && IsOnewayTo(segment,node1)) + goto endloop; + + node2=OtherNode(segment,node1); + + if(result1->prev==node2) + goto endloop; + + way=LookupWay(ways,segment->way); + + if(!(way->allow&profile->allow)) + goto endloop; + + if(!profile->highway[HIGHWAY(way->type)]) + goto endloop; + + if(way->weight && way->weightweight) + goto endloop; + + if((way->height && way->heightheight) || + (way->width && way->width width ) || + (way->length && way->lengthlength)) + goto endloop; + + segment_pref=profile->highway[HIGHWAY(way->type)]; + + for(i=1;iprops & PROPERTIES(i)) + { + if(way->props & PROPERTIES(i)) + segment_pref*=profile->props_yes[i]; + else + segment_pref*=profile->props_no[i]; + } + + if(segment_pref==0) + goto endloop; + + if(option_quickest==0) + segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; + else + segment_score=(score_t)Duration(segment,way,profile)/segment_pref; + + cumulative_score=result1->score+segment_score; + + result2=FindResult(results,node2); + + if(!result2) /* New end node */ + { + result2=InsertResult(results,node2); + result2->prev=node1; + result2->next=NO_NODE; + result2->score=cumulative_score; + result2->segment=segment; + + if(!IsFakeNode(node2) && !IsSuperNode(nodes,node2)) + { + result2->sortby=result2->score; + InsertInQueue(queue,result2); + } + } + else if(cumulative_scorescore) /* New end node is better */ + { + result2->prev=node1; + result2->score=cumulative_score; + result2->segment=segment; + + if(!IsFakeNode(node2) && !IsSuperNode(nodes,node2)) + { + result2->sortby=result2->score; + InsertInQueue(queue,result2); + } + } + + endloop: + + if(IsFakeNode(node1)) + segment=NextFakeSegment(segment,node1); + else + segment=NextSegment(segments,segment,node1); + } + } + + FreeQueueList(queue); + + /* Check it worked */ + + if(results->number==1) + { + FreeResultsList(results); + return(NULL); + } + + return(results); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find all routes from any super-node to a specific node. + + Results *FindFinishRoutes Returns a set of results. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + index_t finish The finishing node. + + Profile *profile The profile containing the transport type, speeds and allowed highways. + ++++++++++++++++++++++++++++++++++++++*/ + +Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,index_t finish,Profile *profile) +{ + Results *results; + Queue *queue; + index_t node1,node2; + Result *result1,*result2; + Segment *segment; + Way *way; + + /* Insert the first node into the queue */ + + results=NewResultsList(8); + + results->finish=finish; + + result1=InsertResult(results,finish); + + ZeroResult(result1); + + queue=NewQueueList(); + + InsertInQueue(queue,result1); + + /* Loop across all nodes in the queue */ + + while((result1=PopFromQueue(queue))) + { + node1=result1->node; + + if(IsFakeNode(node1)) + segment=FirstFakeSegment(node1); + else + segment=FirstSegment(segments,nodes,node1); + + while(segment) + { + score_t segment_pref,segment_score,cumulative_score; + int i; + + if(!IsNormalSegment(segment)) + goto endloop; + + if(profile->oneway && IsOnewayFrom(segment,node1)) + goto endloop; + + node2=OtherNode(segment,node1); + + if(result1->next==node2) + goto endloop; + + way=LookupWay(ways,segment->way); + + if(!(way->allow&profile->allow)) + goto endloop; + + if(!profile->highway[HIGHWAY(way->type)]) + goto endloop; + + if(way->weight && way->weightweight) + goto endloop; + + if((way->height && way->heightheight) || + (way->width && way->width width ) || + (way->length && way->lengthlength)) + goto endloop; + + segment_pref=profile->highway[HIGHWAY(way->type)]; + + for(i=1;iprops & PROPERTIES(i)) + { + if(way->props & PROPERTIES(i)) + segment_pref*=profile->props_yes[i]; + else + segment_pref*=profile->props_no[i]; + } + + if(segment_pref==0) + goto endloop; + + if(option_quickest==0) + segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; + else + segment_score=(score_t)Duration(segment,way,profile)/segment_pref; + + cumulative_score=result1->score+segment_score; + + result2=FindResult(results,node2); + + if(!result2) /* New end node */ + { + result2=InsertResult(results,node2); + result2->prev=NO_NODE; + result2->next=node1; + result2->score=cumulative_score; + result2->segment=segment; + + if(!IsFakeNode(node2) && !IsSuperNode(nodes,node2)) + { + result2->sortby=result2->score; + InsertInQueue(queue,result2); + } + } + else if(cumulative_scorescore) /* New end node is better */ + { + result2->next=node1; + result2->score=cumulative_score; + result2->segment=segment; + + if(!IsFakeNode(node2) && !IsSuperNode(nodes,node2)) + { + result2->sortby=result2->score; + InsertInQueue(queue,result2); + } + } + + endloop: + + if(IsFakeNode(node1)) + segment=NextFakeSegment(segment,node1); + else + segment=NextSegment(segments,segment,node1); + } + } + + FreeQueueList(queue); + + /* Check it worked */ + + if(results->number==1) + { + FreeResultsList(results); + return(NULL); + } + + return(results); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Create an optimum route given the set of super-nodes to follow. + + Results *CombineRoutes Returns the results from joining the super-nodes. + + Results *results The set of results from the super-nodes. + + Nodes *nodes The list of nodes. + + Segments *segments The set of segments to use. + + Ways *ways The list of ways. + + Profile *profile The profile containing the transport type, speeds and allowed highways. + ++++++++++++++++++++++++++++++++++++++*/ + +Results *CombineRoutes(Results *results,Nodes *nodes,Segments *segments,Ways *ways,Profile *profile) +{ + Result *result1,*result2,*result3,*result4; + Results *combined; + + combined=NewResultsList(64); + + combined->start=results->start; + combined->finish=results->finish; + + /* Sort out the combined route */ + + result1=FindResult(results,results->start); + + result3=InsertResult(combined,results->start); + + ZeroResult(result3); + + do + { + if(result1->next!=NO_NODE) + { + Results *results2=FindNormalRoute(nodes,segments,ways,result1->node,result1->next,profile); + + result2=FindResult(results2,result1->node); + + result3->next=result2->next; + + result2=FindResult(results2,result2->next); + + do + { + result4=InsertResult(combined,result2->node); + + *result4=*result2; + result4->score+=result3->score; + + if(result2->next!=NO_NODE) + result2=FindResult(results2,result2->next); + else + result2=NULL; + } + while(result2); + + FreeResultsList(results2); + + result1=FindResult(results,result1->next); + + result3=result4; + } + else + result1=NULL; + } + while(result1); + + return(combined); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Fx the forward route (i.e. setup next nodes for forward path from prev nodes on reverse path). + + Results *results The set of results to update. + + index_t finish The finish point. + ++++++++++++++++++++++++++++++++++++++*/ + +void FixForwardRoute(Results *results,index_t finish) +{ + Result *result2=FindResult(results,finish); + Result *result1; + + /* Create the forward links for the optimum path */ + + do + { + if(result2->prev!=NO_NODE) + { + index_t node1=result2->prev; + + result1=FindResult(results,node1); + + result1->next=result2->node; + + result2=result1; + } + else + result2=NULL; + } + while(result2); + + results->finish=finish; +} diff --git a/src/osmparser.c b/src/osmparser.c new file mode 100644 index 0000000..3af039d --- /dev/null +++ b/src/osmparser.c @@ -0,0 +1,748 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/osmparser.c,v 1.69 2010/05/29 13:54:23 amb Exp $ + + OSM XML file parser (either JOSM or planet) + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include + +#include "typesx.h" +#include "functionsx.h" +#include "nodesx.h" +#include "segmentsx.h" +#include "waysx.h" +#include "xmlparse.h" +#include "tagging.h" + + +/* Macros */ + +#define ISTRUE(xx) (!strcmp(xx,"true") || !strcmp(xx,"yes") || !strcmp(xx,"1")) + + +/* Local variables */ + +static long nnodes=0,nways=0,nrelations=0; +static TagList *current_tags=NULL; + +static node_t *way_nodes=NULL; +static int way_nnodes=0; + +static NodesX *nodes; +static SegmentsX *segments; +static WaysX *ways; + + +/* Local functions */ + +static void process_way_tags(TagList *tags,way_t id); + + +/* The XML tag processing function prototypes */ + +//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding); +//static int osmType_function(const char *_tag_,int _type_); +static int relationType_function(const char *_tag_,int _type_,const char *id); +static int wayType_function(const char *_tag_,int _type_,const char *id); +//static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role); +static int ndType_function(const char *_tag_,int _type_,const char *ref); +static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon); +static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v); +//static int boundType_function(const char *_tag_,int _type_); +//static int boundsType_function(const char *_tag_,int _type_); + + +/* The XML tag definitions */ + +/*+ The boundsType type tag. +*/ +static xmltag boundsType_tag= + {"bounds", + 0, {NULL}, + NULL, + {NULL}}; + +/*+ The boundType type tag. +*/ +static xmltag boundType_tag= + {"bound", + 0, {NULL}, + NULL, + {NULL}}; + +/*+ The tagType type tag. +*/ +static xmltag tagType_tag= + {"tag", + 2, {"k","v"}, + tagType_function, + {NULL}}; + +/*+ The nodeType type tag. +*/ +static xmltag nodeType_tag= + {"node", + 3, {"id","lat","lon"}, + nodeType_function, + {&tagType_tag,NULL}}; + +/*+ The ndType type tag. +*/ +static xmltag ndType_tag= + {"nd", + 1, {"ref"}, + ndType_function, + {NULL}}; + +/*+ The memberType type tag. +*/ +static xmltag memberType_tag= + {"member", + 3, {"type","ref","role"}, + NULL, + {NULL}}; + +/*+ The wayType type tag. +*/ +static xmltag wayType_tag= + {"way", + 1, {"id"}, + wayType_function, + {&ndType_tag,&tagType_tag,NULL}}; + +/*+ The relationType type tag. +*/ +static xmltag relationType_tag= + {"relation", + 1, {"id"}, + relationType_function, + {&memberType_tag,&tagType_tag,NULL}}; + +/*+ The osmType type tag. +*/ +static xmltag osmType_tag= + {"osm", + 0, {NULL}, + NULL, + {&boundsType_tag,&boundType_tag,&nodeType_tag,&wayType_tag,&relationType_tag,NULL}}; + +/*+ The xmlDeclaration type tag. +*/ +static xmltag xmlDeclaration_tag= + {"xml", + 2, {"version","encoding"}, + NULL, + {NULL}}; + + +/*+ The complete set of tags at the top level. +*/ +static xmltag *xml_toplevel_tags[]={&xmlDeclaration_tag,&osmType_tag,NULL}; + + +/* The XML tag processing functions */ + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the boundsType XSD type is seen + + int boundsType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int boundsType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the boundType XSD type is seen + + int boundType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int boundType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the tagType XSD type is seen + + int tagType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *k The contents of the 'k' attribute (or NULL if not defined). + + const char *v The contents of the 'v' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v) +{ + if(_type_&XMLPARSE_TAG_START && current_tags) + { + XMLPARSE_ASSERT_STRING(_tag_,k); + XMLPARSE_ASSERT_STRING(_tag_,v); + + AppendTag(current_tags,k,v); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the nodeType XSD type is seen + + int nodeType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *id The contents of the 'id' attribute (or NULL if not defined). + + const char *lat The contents of the 'lat' attribute (or NULL if not defined). + + const char *lon The contents of the 'lon' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon) +{ + if(_type_&XMLPARSE_TAG_START) + { + node_t node_id; + double latitude,longitude; + + nnodes++; + + if(!(nnodes%1000)) + { + printf("\rReading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations); + fflush(stdout); + } + + /* Handle the node information */ + + XMLPARSE_ASSERT_STRING(_tag_,id); node_id=atoll(id); /* need long long conversion */ + XMLPARSE_ASSERT_FLOATING(_tag_,lat,latitude); + XMLPARSE_ASSERT_FLOATING(_tag_,lon,longitude); + + AppendNode(nodes,node_id,degrees_to_radians(latitude),degrees_to_radians(longitude)); + +// current_tags=NewTagList(); + current_tags=NULL; + } + +// if(_type_&XMLPARSE_TAG_END) +// { +// TagList *result=ApplyTaggingRules(&NodeRules,current_tags); +// +// DeleteTagList(current_tags); +// DeleteTagList(result); +// } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the ndType XSD type is seen + + int ndType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *ref The contents of the 'ref' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int ndType_function(const char *_tag_,int _type_,const char *ref) +{ + if(_type_&XMLPARSE_TAG_START) + { + node_t node_id; + + XMLPARSE_ASSERT_STRING(_tag_,ref); node_id=atoll(ref); /* need long long conversion */ + + if((way_nnodes%256)==0) + way_nodes=(node_t*)realloc((void*)way_nodes,(way_nnodes+256)*sizeof(node_t)); + + way_nodes[way_nnodes++]=node_id; + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the memberType XSD type is seen + + int memberType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *type The contents of the 'type' attribute (or NULL if not defined). + + const char *ref The contents of the 'ref' attribute (or NULL if not defined). + + const char *role The contents of the 'role' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +//static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the wayType XSD type is seen + + int wayType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *id The contents of the 'id' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int wayType_function(const char *_tag_,int _type_,const char *id) +{ + static way_t way_id; + + if(_type_&XMLPARSE_TAG_START) + { + nways++; + + if(!(nways%1000)) + { + printf("\rReading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations); + fflush(stdout); + } + + current_tags=NewTagList(); + way_nnodes=0; + + /* Handle the way information */ + + XMLPARSE_ASSERT_STRING(_tag_,id); way_id=atoll(id); /* need long long conversion */ + } + + if(_type_&XMLPARSE_TAG_END) + { + TagList *result=ApplyTaggingRules(&WayRules,current_tags); + + process_way_tags(result,way_id); + + DeleteTagList(current_tags); + DeleteTagList(result); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the relationType XSD type is seen + + int relationType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *id The contents of the 'id' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int relationType_function(const char *_tag_,int _type_,const char *id) +{ + if(_type_&XMLPARSE_TAG_START) + { + nrelations++; + + if(!(nrelations%1000)) + { + printf("\rReading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations); + fflush(stdout); + } + +// current_tags=NewTagList(); + current_tags=NULL; + } + +// if(_type_&XMLPARSE_TAG_END) +// { +// TagList *result=ApplyTaggingRules(&RelationRules,current_tags); +// +// DeleteTagList(current_tags); +// DeleteTagList(result); +// } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the osmType XSD type is seen + + int osmType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int osmType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the XML declaration is seen + + int xmlDeclaration_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *version The contents of the 'version' attribute (or NULL if not defined). + + const char *encoding The contents of the 'encoding' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + Parse an OSM XML file (from JOSM or planet download). + + int ParseOSM Returns 0 if OK or something else in case of an error. + + FILE *file The file to read from. + + NodesX *OSMNodes The array of nodes to fill in. + + SegmentsX *OSMSegments The array of segments to fill in. + + WaysX *OSMWays The arrray of ways to fill in. + ++++++++++++++++++++++++++++++++++++++*/ + +int ParseOSM(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays) +{ + int retval; + + /* Parse the file */ + + nodes=OSMNodes; + segments=OSMSegments; + ways=OSMWays; + + nnodes=0,nways=0,nrelations=0; + + printf("\rReading: Lines=0 Nodes=0 Ways=0 Relations=0"); + fflush(stdout); + + retval=ParseXML(file,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE); + + printf("\rRead: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld \n",ParseXML_LineNumber(),nnodes,nways,nrelations); + fflush(stdout); + + return(retval); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Process the tags associated with a way. + + TagList *tags The list of way tags. + + way_t id The id of the way. + ++++++++++++++++++++++++++++++++++++++*/ + +static void process_way_tags(TagList *tags,way_t id) +{ + Way way={0}; + int oneway=0,roundabout=0; + char *name=NULL,*ref=NULL; + + int i; + + /* Parse the tags */ + + for(i=0;intags;i++) + { + char *k=tags->k[i]; + char *v=tags->v[i]; + + switch(*k) + { + case 'b': + if(!strcmp(k,"bicycle")) + if(ISTRUE(v)) + way.allow|= Allow_Bicycle; + + if(!strcmp(k,"bridge")) + if(ISTRUE(v)) + way.props|=Properties_Bridge; + + break; + + case 'f': + if(!strcmp(k,"foot")) + if(ISTRUE(v)) + way.allow|= Allow_Foot; + + break; + + case 'g': + if(!strcmp(k,"goods")) + if(ISTRUE(v)) + way.allow|=Allow_Goods; + + break; + + case 'h': + if(!strcmp(k,"highway")) + way.type=HighwayType(v); + + if(!strcmp(k,"horse")) + if(ISTRUE(v)) + way.allow|=Allow_Horse; + + if(!strcmp(k,"hgv")) + if(ISTRUE(v)) + way.allow|=Allow_HGV; + + break; + + case 'j': + if(!strcmp(k,"junction") && !strcmp(v,"roundabout")) + roundabout=1; + + break; + + case 'm': + if(!strcmp(k,"maxspeed")) + { + if(strstr(v,"mph")) + way.speed=kph_to_speed(1.609*atof(v)); + else + way.speed=kph_to_speed(atof(v)); + } + + if(!strcmp(k,"maxweight")) + { + if(strstr(v,"kg")) + way.weight=tonnes_to_weight(atof(v)/1000); + else + way.weight=tonnes_to_weight(atof(v)); + } + + if(!strcmp(k,"maxheight")) + { + if(strchr(v,'\'')) + { + int feet,inches; + + if(sscanf(v,"%d'%d\"",&feet,&inches)==2) + way.height=metres_to_height((feet+(double)inches/12.0)*0.254); + else if(sscanf(v,"%d'",&feet)==1) + way.height=metres_to_height((feet+(double)inches/12.0)*0.254); + } + else if(strstr(v,"ft") || strstr(v,"feet")) + way.height=metres_to_height(atof(v)*0.254); + else + way.height=metres_to_height(atof(v)); + } + + if(!strcmp(k,"maxwidth")) + { + if(strchr(v,'\'')) + { + int feet,inches; + + if(sscanf(v,"%d'%d\"",&feet,&inches)==2) + way.width=metres_to_height((feet+(double)inches/12.0)*0.254); + else if(sscanf(v,"%d'",&feet)==1) + way.width=metres_to_height((feet+(double)inches/12.0)*0.254); + } + else if(strstr(v,"ft") || strstr(v,"feet")) + way.width=metres_to_width(atof(v)*0.254); + else + way.width=metres_to_width(atof(v)); + } + + if(!strcmp(k,"maxlength")) + { + if(strchr(v,'\'')) + { + int feet,inches; + + if(sscanf(v,"%d'%d\"",&feet,&inches)==2) + way.length=metres_to_height((feet+(double)inches/12.0)*0.254); + else if(sscanf(v,"%d'",&feet)==1) + way.length=metres_to_height((feet+(double)inches/12.0)*0.254); + } + else if(strstr(v,"ft") || strstr(v,"feet")) + way.length=metres_to_length(atof(v)*0.254); + else + way.length=metres_to_length(atof(v)); + } + + if(!strcmp(k,"moped")) + if(ISTRUE(v)) + way.allow|=Allow_Moped; + + if(!strcmp(k,"motorbike")) + if(ISTRUE(v)) + way.allow|=Allow_Motorbike; + + if(!strcmp(k,"motorcar")) + if(ISTRUE(v)) + way.allow|=Allow_Motorcar; + + if(!strcmp(k,"multilane")) + if(ISTRUE(v)) + way.props|=Properties_Multilane; + + break; + + case 'n': + if(!strcmp(k,"name")) + name=v; + + break; + + case 'o': + if(!strcmp(k,"oneway")) + { + if(ISTRUE(v)) + oneway=1; + else if(!strcmp(v,"-1")) + oneway=-1; + } + + break; + + case 'p': + if(!strcmp(k,"paved")) + if(ISTRUE(v)) + way.props|=Properties_Paved; + + if(!strcmp(k,"psv")) + if(ISTRUE(v)) + way.allow|=Allow_PSV; + + break; + + case 'r': + if(!strcmp(k,"ref")) + ref=v; + + break; + + case 't': + if(!strcmp(k,"tunnel")) + if(ISTRUE(v)) + way.props|=Properties_Tunnel; + + break; + + case 'w': + if(!strcmp(k,"wheelchair")) + if(ISTRUE(v)) + way.allow|=Allow_Wheelchair; + + break; + + default: + ; + } + } + + /* Create the way */ + + if(way.type>0 && way.type0) + { + AppendSegment(segments,id,from,to,ONEWAY_1TO2); + AppendSegment(segments,id,to,from,ONEWAY_2TO1); + } + else if(oneway<0) + { + AppendSegment(segments,id,from,to,ONEWAY_2TO1); + AppendSegment(segments,id,to,from,ONEWAY_1TO2); + } + else + { + AppendSegment(segments,id,from,to,0); + AppendSegment(segments,id,to,from,0); + } + } + } + } +} diff --git a/src/output.c b/src/output.c new file mode 100644 index 0000000..e40f750 --- /dev/null +++ b/src/output.c @@ -0,0 +1,816 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/output.c,v 1.33 2010/07/07 17:31:06 amb Exp $ + + Routing output generator. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "functions.h" +#include "translations.h" +#include "nodes.h" +#include "segments.h" +#include "ways.h" +#include "results.h" +#include "xmlparse.h" + + +/* Global variables */ + +/*+ The option to calculate the quickest route insted of the shortest. +*/ +extern int option_quickest; + +/*+ The options to select the format of the output. +*/ +extern int option_html,option_gpx_track,option_gpx_route,option_text,option_text_all; + +/* Local variables */ + +/*+ Heuristics for determining if a junction is important. +*/ +static char junction_other_way[Way_Count][Way_Count]= + { /* M, T, P, S, T, U, R, S, T, C, P, S = Way type of route not taken */ + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* Motorway */ + { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* Trunk */ + { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* Primary */ + { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* Secondary */ + { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, /* Tertiary */ + { 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* Unclassified */ + { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, /* Residential */ + { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* Service */ + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, /* Track */ + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, /* Cycleway */ + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* Path */ + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* Steps */ + }; + + +/* Local functions */ + +static int turn_angle(Nodes *nodes,Segment *segment1,Segment *segment2,index_t node); +static int bearing_angle(Nodes *nodes,Segment *segment,index_t node); + + +/*++++++++++++++++++++++++++++++++++++++ + Print the optimum route between two nodes. + + Results **results The set of results to print (some may be NULL - ignore them). + + int nresults The number of results in the list. + + Nodes *nodes The list of nodes. + + Segments *segments The set of segments to use. + + Ways *ways The list of ways. + + Profile *profile The profile containing the transport type, speeds and allowed highways. + ++++++++++++++++++++++++++++++++++++++*/ + +void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,Ways *ways,Profile *profile) +{ + FILE *htmlfile=NULL,*gpxtrackfile=NULL,*gpxroutefile=NULL,*textfile=NULL,*textallfile=NULL; + + int point=1; + distance_t cum_distance=0; + duration_t cum_duration=0; + double finish_lat,finish_lon; + int segment_count=0; + int route_count=0; + + /* Open the files */ + + if(option_quickest==0) + { + /* Print the result for the shortest route */ + + if(option_html) + htmlfile =fopen("shortest.html","w"); + if(option_gpx_track) + gpxtrackfile=fopen("shortest-track.gpx","w"); + if(option_gpx_route) + gpxroutefile=fopen("shortest-route.gpx","w"); + if(option_text) + textfile =fopen("shortest.txt","w"); + if(option_text_all) + textallfile =fopen("shortest-all.txt","w"); + + if(option_html && !htmlfile) + fprintf(stderr,"Warning: Cannot open file 'shortest.html' for writing [%s].\n",strerror(errno)); + if(option_gpx_track && !gpxtrackfile) + fprintf(stderr,"Warning: Cannot open file 'shortest-track.gpx' for writing [%s].\n",strerror(errno)); + if(option_gpx_route && !gpxroutefile) + fprintf(stderr,"Warning: Cannot open file 'shortest-route.gpx' for writing [%s].\n",strerror(errno)); + if(option_text && !textfile) + fprintf(stderr,"Warning: Cannot open file 'shortest.txt' for writing [%s].\n",strerror(errno)); + if(option_text_all && !textallfile) + fprintf(stderr,"Warning: Cannot open file 'shortest-all.txt' for writing [%s].\n",strerror(errno)); + } + else + { + /* Print the result for the quickest route */ + + if(option_html) + htmlfile =fopen("quickest.html","w"); + if(option_gpx_track) + gpxtrackfile=fopen("quickest-track.gpx","w"); + if(option_gpx_route) + gpxroutefile=fopen("quickest-route.gpx","w"); + if(option_text) + textfile =fopen("quickest.txt","w"); + if(option_text_all) + textallfile =fopen("quickest-all.txt","w"); + + if(option_html && !htmlfile) + fprintf(stderr,"Warning: Cannot open file 'quickest.html' for writing [%s].\n",strerror(errno)); + if(option_gpx_track && !gpxtrackfile) + fprintf(stderr,"Warning: Cannot open file 'quickest-track.gpx' for writing [%s].\n",strerror(errno)); + if(option_gpx_route && !gpxroutefile) + fprintf(stderr,"Warning: Cannot open file 'quickest-route.gpx' for writing [%s].\n",strerror(errno)); + if(option_text && !textfile) + fprintf(stderr,"Warning: Cannot open file 'quickest.txt' for writing [%s].\n",strerror(errno)); + if(option_text_all && !textallfile) + fprintf(stderr,"Warning: Cannot open file 'quickest-all.txt' for writing [%s].\n",strerror(errno)); + } + + /* Print the head of the files */ + + if(htmlfile) + { + fprintf(htmlfile,"\n"); + fprintf(htmlfile,"\n"); + if(translate_copyright_creator[0] && translate_copyright_creator[1]) + fprintf(htmlfile,"\n",translate_copyright_creator[0],translate_copyright_creator[1]); + if(translate_copyright_source[0] && translate_copyright_source[1]) + fprintf(htmlfile,"\n",translate_copyright_source[0],translate_copyright_source[1]); + if(translate_copyright_license[0] && translate_copyright_license[1]) + fprintf(htmlfile,"\n",translate_copyright_license[0],translate_copyright_license[1]); + fprintf(htmlfile,"\n"); + fprintf(htmlfile,""); + fprintf(htmlfile,translate_html_title,option_quickest?translate_route_quickest:translate_route_shortest); + fprintf(htmlfile,"\n"); + fprintf(htmlfile,"\n"); + fprintf(htmlfile,"\n"); + fprintf(htmlfile,"\n"); + fprintf(htmlfile,"

"); + fprintf(htmlfile,translate_html_title,option_quickest?translate_route_quickest:translate_route_shortest); + fprintf(htmlfile,"

\n"); + fprintf(htmlfile,"\n"); + } + + if(gpxtrackfile) + { + fprintf(gpxtrackfile,"\n"); + fprintf(gpxtrackfile,"\n"); + + fprintf(gpxtrackfile,"\n"); + fprintf(gpxtrackfile,"%s : %s\n",translate_copyright_creator[0],translate_copyright_creator[1]); + if(translate_copyright_source[1]) + { + fprintf(gpxtrackfile,"\n",translate_copyright_source[1]); + + if(translate_copyright_license[1]) + fprintf(gpxtrackfile,"%s\n",translate_copyright_license[1]); + + fprintf(gpxtrackfile,"\n"); + } + fprintf(gpxtrackfile,"\n"); + + fprintf(gpxtrackfile,"\n"); + fprintf(gpxtrackfile,""); + fprintf(gpxtrackfile,translate_gpx_name,option_quickest?translate_route_quickest:translate_route_shortest); + fprintf(gpxtrackfile,"\n"); + fprintf(gpxtrackfile,""); + fprintf(gpxtrackfile,translate_gpx_desc,option_quickest?translate_route_quickest:translate_route_shortest); + fprintf(gpxtrackfile,"\n"); + } + + if(gpxroutefile) + { + fprintf(gpxroutefile,"\n"); + fprintf(gpxroutefile,"\n"); + + fprintf(gpxroutefile,"\n"); + fprintf(gpxroutefile,"%s : %s\n",translate_copyright_creator[0],translate_copyright_creator[1]); + if(translate_copyright_source[1]) + { + fprintf(gpxroutefile,"\n",translate_copyright_source[1]); + + if(translate_copyright_license[1]) + fprintf(gpxroutefile,"%s\n",translate_copyright_license[1]); + + fprintf(gpxroutefile,"\n"); + } + fprintf(gpxroutefile,"\n"); + + fprintf(gpxroutefile,"\n"); + fprintf(gpxroutefile,""); + fprintf(gpxroutefile,translate_gpx_name,option_quickest?translate_route_quickest:translate_route_shortest); + fprintf(gpxroutefile,"\n"); + fprintf(gpxroutefile,""); + fprintf(gpxroutefile,translate_gpx_desc,option_quickest?translate_route_quickest:translate_route_shortest); + fprintf(gpxroutefile,"\n"); + } + + if(textfile) + { + if(translate_copyright_creator[0] && translate_copyright_creator[1]) + fprintf(textfile,"# %s : %s\n",translate_copyright_creator[0],translate_copyright_creator[1]); + if(translate_copyright_source[0] && translate_copyright_source[1]) + fprintf(textfile,"# %s : %s\n",translate_copyright_source[0],translate_copyright_source[1]); + if(translate_copyright_license[0] && translate_copyright_license[1]) + fprintf(textfile,"# %s : %s\n",translate_copyright_license[0],translate_copyright_license[1]); + if((translate_copyright_creator[0] && translate_copyright_creator[1]) || + (translate_copyright_source[0] && translate_copyright_source[1]) || + (translate_copyright_license[0] && translate_copyright_license[1])) + fprintf(textfile,"#\n"); + + fprintf(textfile,"#Latitude\tLongitude\tSection \tSection \tTotal \tTotal \tPoint\tTurn\tBearing\tHighway\n"); + fprintf(textfile,"# \t \tDistance\tDuration\tDistance\tDuration\tType \t \t \t \n"); + /* "%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t %+d\t %+d\t%s\n" */ + } + + if(textallfile) + { + if(translate_copyright_creator[0] && translate_copyright_creator[1]) + fprintf(textallfile,"# %s : %s\n",translate_copyright_creator[0],translate_copyright_creator[1]); + if(translate_copyright_source[0] && translate_copyright_source[1]) + fprintf(textallfile,"# %s : %s\n",translate_copyright_source[0],translate_copyright_source[1]); + if(translate_copyright_license[0] && translate_copyright_license[1]) + fprintf(textallfile,"# %s : %s\n",translate_copyright_license[0],translate_copyright_license[1]); + if((translate_copyright_creator[0] && translate_copyright_creator[1]) || + (translate_copyright_source[0] && translate_copyright_source[1]) || + (translate_copyright_license[0] && translate_copyright_license[1])) + fprintf(textallfile,"#\n"); + + fprintf(textallfile,"#Latitude\tLongitude\t Node\tType\tSegment\tSegment\tTotal\tTotal \tSpeed\tBearing\tHighway\n"); + fprintf(textallfile,"# \t \t \t \tDist \tDurat'n\tDist \tDurat'n\t \t \t \n"); + /* "%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t%3d\t%4d\t%s\n" */ + } + + /* Loop through the segments of the route and print it */ + + while(!results[point]) + point++; + + while(point<=nresults) + { + int nextpoint=point; + double start_lat,start_lon; + distance_t junc_distance=0; + duration_t junc_duration=0; + Result *result; + + if(gpxtrackfile) + fprintf(gpxtrackfile,"\n"); + + if(IsFakeNode(results[point]->start)) + GetFakeLatLong(results[point]->start,&start_lat,&start_lon); + else + GetLatLong(nodes,results[point]->start,&start_lat,&start_lon); + + if(IsFakeNode(results[point]->finish)) + GetFakeLatLong(results[point]->finish,&finish_lat,&finish_lon); + else + GetLatLong(nodes,results[point]->finish,&finish_lat,&finish_lon); + + result=FindResult(results[point],results[point]->start); + + do + { + double latitude,longitude; + Result *nextresult; + + if(result->node==results[point]->start) + {latitude=start_lat; longitude=start_lon;} + else if(result->node==results[point]->finish) + {latitude=finish_lat; longitude=finish_lon;} + else + GetLatLong(nodes,result->node,&latitude,&longitude); + + if(gpxtrackfile) + fprintf(gpxtrackfile,"\n", + radians_to_degrees(latitude),radians_to_degrees(longitude)); + + nextresult=FindResult(results[point],result->next); + + if(!nextresult) + for(nextpoint=point+1;nextpoint<=nresults;nextpoint++) + if(results[nextpoint]) + { + nextresult=FindResult(results[nextpoint],results[nextpoint]->start); + nextresult=FindResult(results[nextpoint],nextresult->next); + break; + } + + if(result->node!=results[point]->start) + { + distance_t seg_distance=0; + duration_t seg_duration=0; + Way *resultway; + int important=0; + + /* Cache the values to be printed rather than calculating them repeatedly for each output format */ + + char *waynameraw=NULL,*wayname=NULL,*waynamexml=NULL; + int bearing_int=0,bearing_next_int=0,turn_int=0; + char *bearing_str=NULL,*bearing_next_str=NULL,*turn_str=NULL; + + /* Get the properties of this segment */ + + resultway=LookupWay(ways,result->segment->way); + + seg_distance+=DISTANCE(result->segment->distance); + seg_duration+=Duration(result->segment,resultway,profile); + junc_distance+=seg_distance; + junc_duration+=seg_duration; + cum_distance+=seg_distance; + cum_duration+=seg_duration; + + /* Decide if this is an important junction */ + + if(result->node==results[point]->finish) + important=10; + else + { + Segment *segment=FirstSegment(segments,nodes,result->node); + + do + { + index_t othernode=OtherNode(segment,result->node); + + if(othernode!=result->prev && segment!=result->segment) + if(IsNormalSegment(segment) && (!profile->oneway || !IsOnewayTo(segment,result->node))) + { + Way *way=LookupWay(ways,segment->way); + + if(othernode==result->next) /* the next segment that we follow */ + { + if(HIGHWAY(way->type)!=HIGHWAY(resultway->type)) + if(important<2) + important=2; + } + else /* a segment that we don't follow */ + { + if(junction_other_way[HIGHWAY(resultway->type)-1][HIGHWAY(way->type)-1]) + if(important<3) + important=3; + + if(important<1) + important=1; + } + } + + segment=NextSegment(segments,segment,result->node); + } + while(segment); + } + + /* Print out the important points (junctions / waypoints) */ + + if(important>1) + { + /* Print the intermediate finish points (because they have correct junction distances) */ + + if(htmlfile) + { + char *type; + + if(important==10) + type=translate_html_waypoint; + else + type=translate_html_junction; + + if(!waynameraw) + { + waynameraw=WayNameRaw(ways,resultway); + if(!*waynameraw) + waynameraw=translate_highway[HIGHWAY(resultway->type)]; + } + + if(!waynamexml) + waynamexml=ParseXML_Encode_Safe_XML(waynameraw); + + fprintf(htmlfile,"
%s:",translate_html_segment[0]); + fprintf(htmlfile,translate_html_segment[1], + waynamexml, + distance_to_km(junc_distance),duration_to_minutes(junc_duration)); + fprintf(htmlfile," ["); + fprintf(htmlfile,translate_html_total[1], + distance_to_km(cum_distance),duration_to_minutes(cum_duration)); + fprintf(htmlfile,"]\n"); + + fprintf(htmlfile,"
%.6f %.6f\n", + radians_to_degrees(latitude),radians_to_degrees(longitude)); + + if(nextresult) + { + if(!turn_str) + { + turn_int=turn_angle(nodes,result->segment,nextresult->segment,result->node); + turn_str=translate_turn[(4+(22+turn_int)/45)%8]; + } + + if(!bearing_next_str) + { + bearing_next_int=bearing_angle(nodes,nextresult->segment,nextresult->node); + bearing_next_str=translate_heading[(4+(22+bearing_next_int)/45)%8]; + } + + fprintf(htmlfile,"
%s:",translate_html_node[0]); + fprintf(htmlfile,translate_html_node[1], + type, + turn_str, + bearing_next_str); + fprintf(htmlfile,"\n"); + } + else + { + fprintf(htmlfile,"
%s:",translate_html_stop[0]); + fprintf(htmlfile,translate_html_stop[1], + translate_html_waypoint); + fprintf(htmlfile,"\n"); + fprintf(htmlfile,"
%s:",translate_html_total[0]); + fprintf(htmlfile,translate_html_total[1], + distance_to_km(cum_distance),duration_to_minutes(cum_duration)); + fprintf(htmlfile,"\n"); + } + } + + if(gpxroutefile) + { + if(!waynameraw) + { + waynameraw=WayNameRaw(ways,resultway); + if(!*waynameraw) + waynameraw=translate_highway[HIGHWAY(resultway->type)]; + } + + if(!waynamexml) + waynamexml=ParseXML_Encode_Safe_XML(waynameraw); + + if(!bearing_str) + { + bearing_int=bearing_angle(nodes,result->segment,result->node); + bearing_str=translate_heading[(4+(22+bearing_int)/45)%8]; + } + + fprintf(gpxroutefile,""); + fprintf(gpxroutefile,translate_gpx_step, + bearing_str, + waynamexml, + distance_to_km(junc_distance),duration_to_minutes(junc_duration)); + fprintf(gpxroutefile,"\n"); + + if(!nextresult) + { + fprintf(gpxroutefile,"%s\n", + radians_to_degrees(finish_lat),radians_to_degrees(finish_lon), + translate_gpx_finish); + fprintf(gpxroutefile,""); + fprintf(gpxroutefile,translate_gpx_final, + distance_to_km(cum_distance),duration_to_minutes(cum_duration)); + fprintf(gpxroutefile,"\n"); + } + else if(important==10) + fprintf(gpxroutefile,"%s%d\n", + radians_to_degrees(latitude),radians_to_degrees(longitude), + translate_gpx_inter,++segment_count); + else + fprintf(gpxroutefile,"%s%03d\n", + radians_to_degrees(latitude),radians_to_degrees(longitude), + translate_gpx_trip,++route_count); + } + + if(textfile) + { + char *type; + + if(important==10) + type="Waypt"; + else + type="Junct"; + + if(!wayname) + wayname=(char*)WayNameHighway(ways,resultway); + + if(nextresult) + { + if(!turn_str) + { + turn_int=turn_angle(nodes,result->segment,nextresult->segment,result->node); + turn_str=translate_turn[(4+(22+turn_int)/45)%8]; + } + + if(!bearing_next_str) + { + bearing_next_int=bearing_angle(nodes,nextresult->segment,nextresult->node); + bearing_next_str=translate_heading[(4+(22+bearing_next_int)/45)%8]; + } + + fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t %+d\t %+d\t%s\n", + radians_to_degrees(latitude),radians_to_degrees(longitude), + distance_to_km(junc_distance),duration_to_minutes(junc_duration), + distance_to_km(cum_distance),duration_to_minutes(cum_duration), + type, + (22+turn_int)/45, + ((22+bearing_next_int)/45+4)%8-4, + wayname); + } + else + fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t\t\t%s\n", + radians_to_degrees(latitude),radians_to_degrees(longitude), + distance_to_km(junc_distance),duration_to_minutes(junc_duration), + distance_to_km(cum_distance),duration_to_minutes(cum_duration), + type, + wayname); + } + + junc_distance=0; + junc_duration=0; + } + + /* Print out all of the results */ + + if(textallfile) + { + char *type; + + if(important==10) + type="Waypt"; + else if(important==2) + type="Change"; + else if(important>=1) + type="Junct"; + else + type="Inter"; + + if(!wayname) + wayname=(char*)WayNameHighway(ways,resultway); + + if(!bearing_str) + { + bearing_int=bearing_angle(nodes,result->segment,result->node); + bearing_str=translate_heading[(4+(22+bearing_int)/45)%8]; + } + + fprintf(textallfile,"%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t%3d\t%4d\t%s\n", + radians_to_degrees(latitude),radians_to_degrees(longitude), + IsFakeNode(result->node)?-(result->node&(~NODE_SUPER)):result->node, + (!IsFakeNode(result->node) && IsSuperNode(nodes,result->node))?'*':' ',type, + distance_to_km(seg_distance),duration_to_minutes(seg_duration), + distance_to_km(cum_distance),duration_to_minutes(cum_duration), + profile->speed[HIGHWAY(resultway->type)], + bearing_int, + wayname); + } + + if(waynamexml && waynamexml!=waynameraw) + free(waynamexml); + } + else if(!cum_distance) + { + int bearing_next_int=bearing_angle(nodes,nextresult->segment,nextresult->node); + char *bearing_next_str=translate_heading[(4+(22+bearing_next_int)/45)%8]; + + /* Print out the very first start point */ + + if(htmlfile) + { + fprintf(htmlfile,"
%.6f %.6f\n", + radians_to_degrees(latitude),radians_to_degrees(longitude)); + fprintf(htmlfile,"
%s:",translate_html_start[0]); + fprintf(htmlfile,translate_html_start[1], + translate_html_waypoint, + bearing_next_str); + fprintf(htmlfile,"\n"); + } + + if(gpxroutefile) + fprintf(gpxroutefile,"%s\n", + radians_to_degrees(latitude),radians_to_degrees(longitude), + translate_gpx_start); + + if(textfile) + fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t\t +%d\t\n", + radians_to_degrees(latitude),radians_to_degrees(longitude), + 0.0,0.0,0.0,0.0, + "Waypt", + (22+bearing_next_int)/45); + + if(textallfile) + fprintf(textallfile,"%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t\t\t\n", + radians_to_degrees(latitude),radians_to_degrees(longitude), + IsFakeNode(result->node)?-(result->node&(~NODE_SUPER)):result->node, + (!IsFakeNode(result->node) && IsSuperNode(nodes,result->node))?'*':' ',"Waypt", + 0.0,0.0,0.0,0.0); + } + + result=nextresult; + } + while(point==nextpoint); + + if(gpxtrackfile) + fprintf(gpxtrackfile,"\n"); + + point=nextpoint; + } + + /* Print the tail of the files */ + + if(htmlfile) + { + fprintf(htmlfile,"
\n"); + + if((translate_copyright_creator[0] && translate_copyright_creator[1]) || + (translate_copyright_source[0] && translate_copyright_source[1]) || + (translate_copyright_license[0] && translate_copyright_license[1])) + { + fprintf(htmlfile,"

\n"); + fprintf(htmlfile,"\n"); + if(translate_copyright_creator[0] && translate_copyright_creator[1]) + fprintf(htmlfile,"
%s:%s\n",translate_copyright_creator[0],translate_copyright_creator[1]); + if(translate_copyright_source[0] && translate_copyright_source[1]) + fprintf(htmlfile,"
%s:%s\n",translate_copyright_source[0],translate_copyright_source[1]); + if(translate_copyright_license[0] && translate_copyright_license[1]) + fprintf(htmlfile,"
%s:%s\n",translate_copyright_license[0],translate_copyright_license[1]); + fprintf(htmlfile,"
\n"); + } + + fprintf(htmlfile,"\n"); + fprintf(htmlfile,"\n"); + } + + if(gpxtrackfile) + { + fprintf(gpxtrackfile,"\n"); + fprintf(gpxtrackfile,"\n"); + } + + if(gpxroutefile) + { + fprintf(gpxroutefile,"\n"); + fprintf(gpxroutefile,"\n"); + } + + /* Close the files */ + + if(htmlfile) + fclose(htmlfile); + if(gpxtrackfile) + fclose(gpxtrackfile); + if(gpxroutefile) + fclose(gpxroutefile); + if(textfile) + fclose(textfile); + if(textallfile) + fclose(textallfile); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Calculate the angle to turn at a junction from segment1 to segment2 at node. + + int turn_angle Returns a value in the range -4 to +4 indicating the angle to turn. + + Nodes *nodes The set of nodes. + + Segment *segment1 The current segment. + + Segment *segment2 The next segment. + + index_t node The node at which they join. + + Straight ahead is zero, turning to the right is positive (90 degrees) and turning to the left is negative. + Angles are calculated using flat Cartesian lat/long grid approximation (after scaling longitude due to latitude). + ++++++++++++++++++++++++++++++++++++++*/ + +static int turn_angle(Nodes *nodes,Segment *segment1,Segment *segment2,index_t node) +{ + double lat1,latm,lat2; + double lon1,lonm,lon2; + double angle1,angle2,angle; + index_t node1,node2; + + node1=OtherNode(segment1,node); + node2=OtherNode(segment2,node); + + if(IsFakeNode(node1)) + GetFakeLatLong(node1,&lat1,&lon1); + else + GetLatLong(nodes,node1,&lat1,&lon1); + + if(IsFakeNode(node)) + GetFakeLatLong(node,&latm,&lonm); + else + GetLatLong(nodes,node,&latm,&lonm); + + if(IsFakeNode(node2)) + GetFakeLatLong(node2,&lat2,&lon2); + else + GetLatLong(nodes,node2,&lat2,&lon2); + + angle1=atan2((lonm-lon1)*cos(latm),(latm-lat1)); + angle2=atan2((lon2-lonm)*cos(latm),(lat2-latm)); + + angle=angle2-angle1; + + angle=radians_to_degrees(angle); + + angle=round(angle); + + if(angle<-180) angle+=360; + if(angle> 180) angle-=360; + + return((int)angle); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Calculate the bearing of a segment from the given node. + + int bearing_angle Returns a value in the range 0 to 359 indicating the bearing. + + Nodes *nodes The set of nodes. + + Segment *segment The segment. + + index_t node The node to start. + + Angles are calculated using flat Cartesian lat/long grid approximation (after scaling longitude due to latitude). + ++++++++++++++++++++++++++++++++++++++*/ + +static int bearing_angle(Nodes *nodes,Segment *segment,index_t node) +{ + double lat1,lat2; + double lon1,lon2; + double angle; + index_t node1,node2; + + node1=node; + node2=OtherNode(segment,node); + + if(IsFakeNode(node1)) + GetFakeLatLong(node1,&lat1,&lon1); + else + GetLatLong(nodes,node1,&lat1,&lon1); + + if(IsFakeNode(node2)) + GetFakeLatLong(node2,&lat2,&lon2); + else + GetLatLong(nodes,node2,&lat2,&lon2); + + angle=atan2((lat2-lat1),(lon2-lon1)*cos(lat1)); + + angle=radians_to_degrees(angle); + + angle=round(270-angle); + + if(angle< 0) angle+=360; + if(angle>360) angle-=360; + + return((int)angle); +} diff --git a/src/planetsplitter.c b/src/planetsplitter.c new file mode 100644 index 0000000..5380455 --- /dev/null +++ b/src/planetsplitter.c @@ -0,0 +1,410 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/planetsplitter.c,v 1.73 2010/05/22 18:40:47 amb Exp $ + + OSM planet file splitter. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include + +#include "typesx.h" +#include "types.h" +#include "functionsx.h" +#include "functions.h" +#include "nodesx.h" +#include "segmentsx.h" +#include "waysx.h" +#include "superx.h" +#include "ways.h" +#include "tagging.h" + + +/* Global variables */ + +/*+ The option to use a slim mode with file-backed read-only intermediate storage. +*/ +int option_slim=0; + +/*+ The name of the temporary directory. +*/ +char *option_tmpdirname=NULL; + +/*+ The amount of RAM to use for filesorting. +*/ +size_t option_filesort_ramsize=0; + + +/* Local functions */ + +static void print_usage(int detail); + + +/*++++++++++++++++++++++++++++++++++++++ + The main program for the planetsplitter. + ++++++++++++++++++++++++++++++++++++++*/ + +int main(int argc,char** argv) +{ + NodesX *Nodes; + SegmentsX *Segments,*SuperSegments=NULL,*MergedSegments=NULL; + WaysX *Ways; + int iteration=0,quit=0; + int max_iterations=10; + char *dirname=NULL,*prefix=NULL,*tagging=NULL; + int option_parse_only=0,option_process_only=0; + int option_filenames=0; + int arg; + + /* Parse the command line arguments */ + + for(arg=1;arg9?"=":""); + fflush(stdout); + + if(iteration==0) + { + /* Select the super-nodes */ + + ChooseSuperNodes(Nodes,Segments,Ways); + + /* Select the super-segments */ + + SuperSegments=CreateSuperSegments(Nodes,Segments,Ways,iteration); + } + else + { + SegmentsX *SuperSegments2; + + /* Select the super-nodes */ + + ChooseSuperNodes(Nodes,SuperSegments,Ways); + + /* Select the super-segments */ + + SuperSegments2=CreateSuperSegments(Nodes,SuperSegments,Ways,iteration); + + if(SuperSegments->xnumber==SuperSegments2->xnumber) + quit=1; + + FreeSegmentList(SuperSegments,0); + + SuperSegments=SuperSegments2; + } + + /* Sort the super-segments */ + + SortSegmentList(SuperSegments); + + /* Remove duplicated super-segments */ + + DeduplicateSegments(SuperSegments,Nodes,Ways); + + iteration++; + + if(iteration>max_iterations) + quit=1; + } + while(!quit); + + /* Combine the super-segments */ + + printf("\nCombine Segments and Super-Segments\n===================================\n\n"); + fflush(stdout); + + /* Merge the super-segments */ + + MergedSegments=MergeSuperSegments(Segments,SuperSegments); + + FreeSegmentList(Segments,0); + + FreeSegmentList(SuperSegments,0); + + Segments=MergedSegments; + + /* Rotate segments so that node1] [--prefix=]\n" + " [--slim] [--sort-ram-size=]\n" + " [--tmpdir=]\n" + " [--parse-only | --process-only]\n" + " [--max-iterations=]\n" + " [--tagging=]\n" + " [ ...]\n"); + + if(detail) + fprintf(stderr, + "\n" + "--help Prints this information.\n" + "\n" + "--dir= The directory containing the routing database.\n" + "--prefix= The filename prefix for the routing database.\n" + "\n" + "--slim Use less RAM and more temporary files.\n" + "--sort-ram-size= The amount of RAM (in MB) to use for data sorting\n" + " (defaults to 64MB with '--slim' or 256MB otherwise.)\n" + "--tmpdir= The directory name for temporary files.\n" + " (defaults to the '--dir' option directory.)\n" + "\n" + "--parse-only Parse the input OSM files and store the results.\n" + "--process-only Process the stored results from previous option.\n" + "\n" + "--max-iterations= The number of iterations for finding super-nodes.\n" + "\n" + "--tagging= The name of the XML file containing the tagging rules\n" + " (defaults to 'tagging.xml' with '--dirname' and\n" + " '--prefix' options).\n" + "\n" + " ... The name(s) of the file(s) to process (by default\n" + " data is read from standard input).\n" + "\n" + " defaults to all but can be set to:\n" + "%s" + "\n" + " can be selected from:\n" + "%s" + "\n" + " can be selected from:\n" + "%s", + TransportList(),HighwayList(),PropertyList()); + + exit(!detail); +} diff --git a/src/profiles.c b/src/profiles.c new file mode 100644 index 0000000..e27a067 --- /dev/null +++ b/src/profiles.c @@ -0,0 +1,1018 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/profiles.c,v 1.42 2010/05/29 10:37:12 amb Exp $ + + Load the profiles from a file and the functions for handling them. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include + +#include "profiles.h" +#include "types.h" +#include "ways.h" +#include "xmlparse.h" +#include "functions.h" + + +/*+ The profiles that have been loaded from file. +*/ +static Profile **loaded_profiles=NULL; + +/*+ The number of profiles that have been loaded from file. +*/ +static int nloaded_profiles=0; + + +/* The XML tag processing function prototypes */ + +//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding); +//static int RoutinoProfilesType_function(const char *_tag_,int _type_); +static int profileType_function(const char *_tag_,int _type_,const char *name,const char *transport); +//static int restrictionsType_function(const char *_tag_,int _type_); +static int lengthType_function(const char *_tag_,int _type_,const char *limit); +static int widthType_function(const char *_tag_,int _type_,const char *limit); +static int heightType_function(const char *_tag_,int _type_,const char *limit); +static int weightType_function(const char *_tag_,int _type_,const char *limit); +//static int propertiesType_function(const char *_tag_,int _type_); +static int onewayType_function(const char *_tag_,int _type_,const char *obey); +static int propertyType_function(const char *_tag_,int _type_,const char *type,const char *percent); +//static int preferencesType_function(const char *_tag_,int _type_); +static int preferenceType_function(const char *_tag_,int _type_,const char *highway,const char *percent); +//static int speedsType_function(const char *_tag_,int _type_); +static int speedType_function(const char *_tag_,int _type_,const char *highway,const char *kph); + + +/* The XML tag definitions */ + +/*+ The speedType type tag. +*/ +static xmltag speedType_tag= + {"speed", + 2, {"highway","kph"}, + speedType_function, + {NULL}}; + +/*+ The speedsType type tag. +*/ +static xmltag speedsType_tag= + {"speeds", + 0, {NULL}, + NULL, + {&speedType_tag,NULL}}; + +/*+ The preferenceType type tag. +*/ +static xmltag preferenceType_tag= + {"preference", + 2, {"highway","percent"}, + preferenceType_function, + {NULL}}; + +/*+ The preferencesType type tag. +*/ +static xmltag preferencesType_tag= + {"preferences", + 0, {NULL}, + NULL, + {&preferenceType_tag,NULL}}; + +/*+ The propertyType type tag. +*/ +static xmltag propertyType_tag= + {"property", + 2, {"type","percent"}, + propertyType_function, + {NULL}}; + +/*+ The onewayType type tag. +*/ +static xmltag onewayType_tag= + {"oneway", + 1, {"obey"}, + onewayType_function, + {NULL}}; + +/*+ The propertiesType type tag. +*/ +static xmltag propertiesType_tag= + {"properties", + 0, {NULL}, + NULL, + {&propertyType_tag,NULL}}; + +/*+ The weightType type tag. +*/ +static xmltag weightType_tag= + {"weight", + 1, {"limit"}, + weightType_function, + {NULL}}; + +/*+ The heightType type tag. +*/ +static xmltag heightType_tag= + {"height", + 1, {"limit"}, + heightType_function, + {NULL}}; + +/*+ The widthType type tag. +*/ +static xmltag widthType_tag= + {"width", + 1, {"limit"}, + widthType_function, + {NULL}}; + +/*+ The lengthType type tag. +*/ +static xmltag lengthType_tag= + {"length", + 1, {"limit"}, + lengthType_function, + {NULL}}; + +/*+ The restrictionsType type tag. +*/ +static xmltag restrictionsType_tag= + {"restrictions", + 0, {NULL}, + NULL, + {&onewayType_tag,&weightType_tag,&heightType_tag,&widthType_tag,&lengthType_tag,NULL}}; + +/*+ The profileType type tag. +*/ +static xmltag profileType_tag= + {"profile", + 2, {"name","transport"}, + profileType_function, + {&speedsType_tag,&preferencesType_tag,&propertiesType_tag,&restrictionsType_tag,NULL}}; + +/*+ The RoutinoProfilesType type tag. +*/ +static xmltag RoutinoProfilesType_tag= + {"routino-profiles", + 0, {NULL}, + NULL, + {&profileType_tag,NULL}}; + +/*+ The xmlDeclaration type tag. +*/ +static xmltag xmlDeclaration_tag= + {"xml", + 2, {"version","encoding"}, + NULL, + {NULL}}; + + +/*+ The complete set of tags at the top level. +*/ +static xmltag *xml_toplevel_tags[]={&xmlDeclaration_tag,&RoutinoProfilesType_tag,NULL}; + + +/* The XML tag processing functions */ + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the speedType XSD type is seen + + int speedType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *highway The contents of the 'highway' attribute (or NULL if not defined). + + const char *kph The contents of the 'kph' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int speedType_function(const char *_tag_,int _type_,const char *highway,const char *kph) +{ + if(_type_&XMLPARSE_TAG_START) + { + double speed; + Highway highwaytype; + + XMLPARSE_ASSERT_STRING(_tag_,highway); + + highwaytype=HighwayType(highway); + + if(highwaytype==Way_Count) + XMLPARSE_INVALID(_tag_,highway); + + XMLPARSE_ASSERT_FLOATING(_tag_,kph,speed); + + loaded_profiles[nloaded_profiles-1]->speed[highwaytype]=kph_to_speed(speed); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the speedsType XSD type is seen + + int speedsType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int speedsType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the preferenceType XSD type is seen + + int preferenceType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *highway The contents of the 'highway' attribute (or NULL if not defined). + + const char *percent The contents of the 'percent' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int preferenceType_function(const char *_tag_,int _type_,const char *highway,const char *percent) +{ + if(_type_&XMLPARSE_TAG_START) + { + Highway highwaytype; + double p; + + XMLPARSE_ASSERT_STRING(_tag_,highway); + + highwaytype=HighwayType(highway); + + if(highwaytype==Way_Count) + XMLPARSE_INVALID(_tag_,highway); + + XMLPARSE_ASSERT_FLOATING(_tag_,percent,p); + + loaded_profiles[nloaded_profiles-1]->highway[highwaytype]=p; + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the preferencesType XSD type is seen + + int preferencesType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int preferencesType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the propertyType XSD type is seen + + int propertyType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *type The contents of the 'type' attribute (or NULL if not defined). + + const char *percent The contents of the 'percent' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int propertyType_function(const char *_tag_,int _type_,const char *type,const char *percent) +{ + if(_type_&XMLPARSE_TAG_START) + { + Property property; + double p; + + XMLPARSE_ASSERT_STRING(_tag_,type); + + property=PropertyType(type); + + if(property==Property_Count) + XMLPARSE_INVALID(_tag_,type); + + XMLPARSE_ASSERT_FLOATING(_tag_,percent,p); + + loaded_profiles[nloaded_profiles-1]->props_yes[property]=p; + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the onewayType XSD type is seen + + int onewayType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *obey The contents of the 'obey' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int onewayType_function(const char *_tag_,int _type_,const char *obey) +{ + if(_type_&XMLPARSE_TAG_START) + { + int o; + + XMLPARSE_ASSERT_INTEGER(_tag_,obey,o); + + loaded_profiles[nloaded_profiles-1]->oneway=!!o; + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the propertiesType XSD type is seen + + int propertiesType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int propertiesType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the weightType XSD type is seen + + int weightType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *limit The contents of the 'limit' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int weightType_function(const char *_tag_,int _type_,const char *limit) +{ + if(_type_&XMLPARSE_TAG_START) + { + double l; + + XMLPARSE_ASSERT_FLOATING(_tag_,limit,l); + + loaded_profiles[nloaded_profiles-1]->weight=tonnes_to_weight(l); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the heightType XSD type is seen + + int heightType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *limit The contents of the 'limit' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int heightType_function(const char *_tag_,int _type_,const char *limit) +{ + if(_type_&XMLPARSE_TAG_START) + { + double l; + + XMLPARSE_ASSERT_FLOATING(_tag_,limit,l); + + loaded_profiles[nloaded_profiles-1]->height=metres_to_height(l); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the widthType XSD type is seen + + int widthType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *limit The contents of the 'limit' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int widthType_function(const char *_tag_,int _type_,const char *limit) +{ + if(_type_&XMLPARSE_TAG_START) + { + double l; + + XMLPARSE_ASSERT_FLOATING(_tag_,limit,l); + + loaded_profiles[nloaded_profiles-1]->width=metres_to_width(l); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the lengthType XSD type is seen + + int lengthType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *limit The contents of the 'limit' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int lengthType_function(const char *_tag_,int _type_,const char *limit) +{ + if(_type_&XMLPARSE_TAG_START) + { + double l; + + XMLPARSE_ASSERT_FLOATING(_tag_,limit,l); + + loaded_profiles[nloaded_profiles-1]->length=metres_to_length(l); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the restrictionsType XSD type is seen + + int restrictionsType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int restrictionsType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the profileType XSD type is seen + + int profileType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *name The contents of the 'name' attribute (or NULL if not defined). + + const char *transport The contents of the 'transport' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int profileType_function(const char *_tag_,int _type_,const char *name,const char *transport) +{ + if(_type_&XMLPARSE_TAG_START) + { + Transport transporttype; + int i; + + XMLPARSE_ASSERT_STRING(_tag_,name); + XMLPARSE_ASSERT_STRING(_tag_,transport); + + for(i=0;iname)) + XMLPARSE_MESSAGE(_tag_,"profile name must be unique"); + + transporttype=TransportType(transport); + + if(transporttype==Transport_None) + XMLPARSE_INVALID(_tag_,transport); + + if((nloaded_profiles%16)==0) + loaded_profiles=(Profile**)realloc((void*)loaded_profiles,(nloaded_profiles+16)*sizeof(Profile*)); + + nloaded_profiles++; + + loaded_profiles[nloaded_profiles-1]=(Profile*)calloc(1,sizeof(Profile)); + + loaded_profiles[nloaded_profiles-1]->name=strcpy(malloc(strlen(name)+1),name); + loaded_profiles[nloaded_profiles-1]->transport=transporttype; + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the RoutinoProfilesType XSD type is seen + + int RoutinoProfilesType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int RoutinoProfilesType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the XML declaration is seen + + int xmlDeclaration_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *version The contents of the 'version' attribute (or NULL if not defined). + + const char *encoding The contents of the 'encoding' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The XML profile parser. + + int ParseXMLProfiles Returns 0 if OK or something else in case of an error. + + const char *filename The name of the file to read. + ++++++++++++++++++++++++++++++++++++++*/ + +int ParseXMLProfiles(const char *filename) +{ + int retval; + + if(!ExistsFile(filename)) + { + fprintf(stderr,"Error: Specified profiles file '%s' does not exist.\n",filename); + return(1); + } + + FILE *file=fopen(filename,"r"); + + if(!file) + { + fprintf(stderr,"Error: Cannot open profiles file '%s' for reading.\n",filename); + return(1); + } + + retval=ParseXML(file,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_ERRNONAME); + + fclose(file); + + if(retval) + { + int i; + + for(i=0;iname,name)) + return(loaded_profiles[i]); + + return(NULL); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Update a profile with highway preference scaling factor. + + int UpdateProfile Returns 1 in case of a problem. + + Profile *profile The profile to be updated. + + Ways *ways The set of ways to use. + ++++++++++++++++++++++++++++++++++++++*/ + +int UpdateProfile(Profile *profile,Ways *ways) +{ + score_t hmax=0; + int i; + + /* Fix up the allowed transport types. */ + + profile->allow=ALLOWED(profile->transport); + + if(!(profile->allow & ways->allow)) + return(1); + + /* Normalise the highway preferences into the range 0 -> 1 */ + + for(i=1;ihighway[i]<0) + profile->highway[i]=0; + + if(profile->highway[i]>hmax) + hmax=profile->highway[i]; + } + + if(hmax==0) + return(1); + + for(i=1;ihighway[i]/=hmax; + + /* Normalise the property preferences into the range 0 -> 2 */ + + for(i=1;iprops_yes[i]<0) + profile->props_yes[i]=0; + + if(profile->props_yes[i]>100) + profile->props_yes[i]=100; + + profile->props_yes[i]/=50; + profile->props_no [i] =2-profile->props_yes[i]; + } + + /* Find the fastest preferred speed */ + + profile->max_speed=0; + + for(i=1;ispeed[i]>profile->max_speed) + profile->max_speed=profile->speed[i]; + + if(profile->max_speed==0) + return(1); + + /* Find the most preferred property combination */ + + profile->max_pref=1; /* since highway prefs were normalised to 1 */ + + for(i=1;iprops & PROPERTIES(i)) + { + if(profile->props_yes[i]>profile->props_no[i]) + profile->max_pref*=profile->props_yes[i]; + else + profile->max_pref*=profile->props_no[i]; + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out a profile. + + const Profile *profile The profile to print. + ++++++++++++++++++++++++++++++++++++++*/ + +void PrintProfile(const Profile *profile) +{ + unsigned int i; + + printf("Profile\n=======\n"); + + printf("\n"); + + printf("Transport: %s\n",TransportName(profile->transport)); + + printf("\n"); + + for(i=1;ihighway[i]); + + printf("\n"); + + for(i=1;ihighway[i]) + printf("Speed on %-12s: %3d km/h / %2.0f mph\n",HighwayName(i),profile->speed[i],(double)profile->speed[i]/1.6); + + printf("\n"); + + for(i=1;iprops_yes[i]); + + printf("\n"); + + printf("Obey one-way : %s\n",profile->oneway?"yes":"no"); + printf("Minimum weight: %.1f tonnes\n",weight_to_tonnes(profile->weight)); + printf("Minimum height: %.1f metres\n",height_to_metres(profile->height)); + printf("Minimum width : %.1f metres\n",width_to_metres(profile->width)); + printf("Minimum length: %.1f metres\n",length_to_metres(profile->length)); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out the profiles as XML for use as program input. + ++++++++++++++++++++++++++++++++++++++*/ + +void PrintProfilesXML(void) +{ + unsigned int i,j; + char *padding=" "; + + printf("\n"); + printf("\n"); + + printf("\n"); + printf("\n"); + + for(j=0;j\n",loaded_profiles[j]->name,TransportName(loaded_profiles[j]->transport)); + + printf(" \n"); + for(i=1;i\n",HighwayName(i),padding+3+strlen(HighwayName(i)),loaded_profiles[j]->speed[i]); + printf(" \n"); + + printf(" \n"); + for(i=1;i\n",HighwayName(i),padding+3+strlen(HighwayName(i)),loaded_profiles[j]->highway[i]); + printf(" \n"); + + printf(" \n"); + for(i=1;i\n",PropertyName(i),padding+6+strlen(PropertyName(i)),loaded_profiles[j]->props_yes[i]); + printf(" \n"); + + printf(" \n"); + printf(" \n",loaded_profiles[j]->oneway); + printf(" \n",weight_to_tonnes(loaded_profiles[j]->weight)); + printf(" \n",height_to_metres(loaded_profiles[j]->height)); + printf(" \n",width_to_metres(loaded_profiles[j]->width)); + printf(" \n",length_to_metres(loaded_profiles[j]->length)); + printf(" \n"); + + printf(" \n"); + printf("\n"); + } + + printf("\n"); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out the profiles as JavaScript Object Notation for use in a web form. + ++++++++++++++++++++++++++++++++++++++*/ + +void PrintProfilesJSON(void) +{ + unsigned int i,j; + + printf("var routino={ // contains all default Routino options (generated using \"--help-profile-json\").\n"); + printf("\n"); + + printf(" // Default transport type\n"); + printf(" transport: 'motorcar',\n"); + printf("\n"); + + printf(" // Transport types\n"); + printf(" transports: {"); + for(j=0;jtransport),j); + printf("},\n"); + printf("\n"); + + printf(" // Highway types\n"); + printf(" highways: {"); + for(i=1;itransport),(int)loaded_profiles[j]->highway[i]); + printf("}%s\n",i==(Way_Count-1)?"":","); + } + printf(" },\n"); + printf("\n"); + + printf(" // Speed limits\n"); + printf(" profile_speed: {\n"); + for(i=1;itransport),loaded_profiles[j]->speed[i]); + printf("}%s\n",i==(Way_Count-1)?"":","); + } + printf(" },\n"); + printf("\n"); + + printf(" // Highway properties\n"); + printf(" profile_property: {\n"); + for(i=1;itransport),(int)loaded_profiles[j]->props_yes[i]); + printf("}%s\n",i==(Property_Count-1)?"":","); + } + printf(" },\n"); + printf("\n"); + + printf(" // Restrictions\n"); + printf(" profile_restrictions: {\n"); + printf(" %12s: {","oneway"); + for(j=0;jtransport),loaded_profiles[j]->oneway); + printf("},\n"); + printf(" %12s: {","weight"); + for(j=0;jtransport),weight_to_tonnes(loaded_profiles[j]->weight)); + printf("},\n"); + printf(" %12s: {","height"); + for(j=0;jtransport),height_to_metres(loaded_profiles[j]->height)); + printf("},\n"); + printf(" %12s: {","width"); + for(j=0;jtransport),width_to_metres(loaded_profiles[j]->width)); + printf("},\n"); + printf(" %12s: {","length"); + for(j=0;jtransport),length_to_metres(loaded_profiles[j]->length)); + printf("}\n"); + printf(" }\n"); + printf("\n"); + + printf("}; // end of routino variable\n"); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out the profiles as Perl for use in a web CGI. + ++++++++++++++++++++++++++++++++++++++*/ + +void PrintProfilesPerl(void) +{ + unsigned int i,j; + + printf("$routino={ # contains all default Routino options (generated using \"--help-profile-perl\").\n"); + printf("\n"); + + printf(" # Default transport type\n"); + printf(" transport => 'motorcar',\n"); + printf("\n"); + + printf(" # Transport types\n"); + printf(" transports => {"); + for(j=0;j %d",j==1?"":", ",TransportName(loaded_profiles[j]->transport),j); + printf("},\n"); + printf("\n"); + + printf(" # Highway types\n"); + printf(" highways => {"); + for(i=1;i %d",i==1?"":", ",HighwayName(i),i); + printf("},\n"); + printf("\n"); + + printf(" # Property types\n"); + printf(" properties => {"); + for(i=1;i %d",i==1?"":", ",PropertyName(i),i); + printf("},\n"); + printf("\n"); + + printf(" # Restriction types\n"); + printf(" restrictions => {oneway => 1, weight => 2, height => 3, width => 4, length => 5},\n"); + printf("\n"); + + printf(" # Allowed highways\n"); + printf(" profile_highway => {\n"); + for(i=1;i {",HighwayName(i)); + for(j=0;j %3d",j==1?"":", ",TransportName(loaded_profiles[j]->transport),(int)loaded_profiles[j]->highway[i]); + printf("}%s\n",i==(Way_Count-1)?"":","); + } + printf(" },\n"); + printf("\n"); + + printf(" # Speed limits\n"); + printf(" profile_speed => {\n"); + for(i=1;i {",HighwayName(i)); + for(j=0;j %3d",j==1?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->speed[i]); + printf("}%s\n",i==(Way_Count-1)?"":","); + } + printf(" },\n"); + printf("\n"); + + printf(" # Highway properties\n"); + printf(" profile_property => {\n"); + for(i=1;i {",PropertyName(i)); + for(j=0;j %3d",j==1?"":", ",TransportName(loaded_profiles[j]->transport),(int)loaded_profiles[j]->props_yes[i]); + printf("}%s\n",i==(Property_Count-1)?"":","); + } + printf(" },\n"); + printf("\n"); + + printf(" # Restrictions\n"); + printf(" profile_restrictions => {\n"); + printf(" %12s => {","oneway"); + for(j=0;j %4d",j==1?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->oneway); + printf("},\n"); + printf(" %12s => {","weight"); + for(j=0;j %4.1f",j==1?"":", ",TransportName(loaded_profiles[j]->transport),weight_to_tonnes(loaded_profiles[j]->weight)); + printf("},\n"); + printf(" %12s => {","height"); + for(j=0;j %4.1f",j==1?"":", ",TransportName(loaded_profiles[j]->transport),height_to_metres(loaded_profiles[j]->height)); + printf("},\n"); + printf(" %12s => {","width"); + for(j=0;j %4.1f",j==1?"":", ",TransportName(loaded_profiles[j]->transport),width_to_metres(loaded_profiles[j]->width)); + printf("},\n"); + printf(" %12s => {","length"); + for(j=0;j %4.1f",j==1?"":", ",TransportName(loaded_profiles[j]->transport),length_to_metres(loaded_profiles[j]->length)); + printf("}\n"); + printf(" },\n"); + printf("\n"); + + printf("}; # end of routino variable\n"); +} diff --git a/src/profiles.h b/src/profiles.h new file mode 100644 index 0000000..25a933a --- /dev/null +++ b/src/profiles.h @@ -0,0 +1,79 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/profiles.h,v 1.16 2010/05/29 10:37:12 amb Exp $ + + A header file for the profiles. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef PROFILES_H +#define PROFILES_H /*+ To stop multiple inclusions. +*/ + +#include "types.h" +#include "ways.h" + + +/* Data structures */ + +/*+ A data structure to hold a transport type profile. +*/ +typedef struct _Profile +{ + char *name; /*+ The name of the profile. +*/ + + Transport transport; /*+ The type of transport. +*/ + + wayallow_t allow; /*+ The type of transport expressed as what must be allowed on a way. +*/ + + score_t highway[Way_Count]; /*+ A floating point preference for travel on the highway. +*/ + score_t max_pref; /*+ The maximum preference for any highway type. +*/ + + speed_t speed[Way_Count]; /*+ The maximum speed on each type of highway. +*/ + speed_t max_speed; /*+ The maximum speed for any highway type. +*/ + + score_t props_yes[Property_Count]; /*+ A floating point preference for ways with this attribute. +*/ + score_t props_no [Property_Count]; /*+ A floating point preference for ways without this attribute. +*/ + + int oneway; /*+ A flag to indicate if one-way restrictions apply. +*/ + + weight_t weight; /*+ The minimum weight of the route. +*/ + + height_t height; /*+ The minimum height of vehicles on the route. +*/ + width_t width; /*+ The minimum width of vehicles on the route. +*/ + length_t length; /*+ The minimum length of vehicles on the route. +*/ +} + Profile; + + +/* Functions */ + +int ParseXMLProfiles(const char *filename); + +Profile *GetProfile(const char *name); + +int UpdateProfile(Profile *profile,Ways *ways); + +void PrintProfile(const Profile *profile); + +void PrintProfilesXML(void); + +void PrintProfilesJSON(void); + +void PrintProfilesPerl(void); + +#endif /* PROFILES_H */ diff --git a/src/queue.c b/src/queue.c new file mode 100644 index 0000000..68c4ccb --- /dev/null +++ b/src/queue.c @@ -0,0 +1,201 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/queue.c,v 1.7 2009/11/13 19:24:11 amb Exp $ + + Queue data type functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008,2009 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include + +#include "results.h" + + +/*+ A queue of results. +*/ +struct _Queue +{ + uint32_t nallocated; /*+ The number of entries allocated. +*/ + uint32_t noccupied; /*+ The number of entries occupied. +*/ + + Result **data; /*+ The queue of pointers to results. +*/ +}; + + +/*++++++++++++++++++++++++++++++++++++++ + Allocate a new queue. + + Queue *NewQueueList Returns the queue. + ++++++++++++++++++++++++++++++++++++++*/ + +Queue *NewQueueList(void) +{ + Queue *queue; + + queue=(Queue*)malloc(sizeof(Queue)); + + queue->nallocated=1023; + queue->noccupied=0; + + queue->data=(Result**)malloc(queue->nallocated*sizeof(Result*)); + + return(queue); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Free a queue. + + Queue *queue The queue to be freed. + ++++++++++++++++++++++++++++++++++++++*/ + +void FreeQueueList(Queue *queue) +{ + free(queue->data); + + free(queue); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Insert a new item into the queue in the right place. + + The data is stored in a "Binary Heap" http://en.wikipedia.org/wiki/Binary_heap + and this operation is adding an item to the heap. + + Queue *queue The queue to insert the result into. + + Result *result The result to insert into the queue. + ++++++++++++++++++++++++++++++++++++++*/ + +void InsertInQueue(Queue *queue,Result *result) +{ + uint32_t index; + + if(result->queued==NOT_QUEUED) + { + if(queue->noccupied==queue->nallocated) + { + queue->nallocated=2*queue->nallocated+1; + queue->data=(Result**)realloc((void*)queue->data,queue->nallocated*sizeof(Result*)); + } + + index=queue->noccupied; + queue->noccupied++; + + queue->data[index]=result; + queue->data[index]->queued=index; + } + else + { + index=result->queued; + } + + /* Bubble up the new value */ + + while(index>0 && + queue->data[index]->sortbydata[(index-1)/2]->sortby) + { + uint32_t newindex; + Result *temp; + + newindex=(index-1)/2; + + temp=queue->data[index]; + queue->data[index]=queue->data[newindex]; + queue->data[newindex]=temp; + + queue->data[index]->queued=index; + queue->data[newindex]->queued=newindex; + + index=newindex; + } +} + + +/*++++++++++++++++++++++++++++++++++++++ + Pop an item from the front of the queue. + + The data is stored in a "Binary Heap" http://en.wikipedia.org/wiki/Binary_heap + and this operation is deleting the root item from the heap. + + Result *PopFromQueue Returns the top item. + + Queue *queue The queue to remove the result from. + ++++++++++++++++++++++++++++++++++++++*/ + +Result *PopFromQueue(Queue *queue) +{ + uint32_t index; + Result *retval; + + if(queue->noccupied==0) + return(NULL); + + retval=queue->data[0]; + retval->queued=NOT_QUEUED; + + index=0; + queue->noccupied--; + + queue->data[index]=queue->data[queue->noccupied]; + + /* Bubble down the newly promoted value */ + + while((2*index+2)noccupied && + (queue->data[index]->sortby>queue->data[2*index+1]->sortby || + queue->data[index]->sortby>queue->data[2*index+2]->sortby)) + { + uint32_t newindex; + Result *temp; + + if(queue->data[2*index+1]->sortbydata[2*index+2]->sortby) + newindex=2*index+1; + else + newindex=2*index+2; + + temp=queue->data[newindex]; + queue->data[newindex]=queue->data[index]; + queue->data[index]=temp; + + queue->data[index]->queued=index; + queue->data[newindex]->queued=newindex; + + index=newindex; + } + + if((2*index+2)==queue->noccupied && + queue->data[index]->sortby>queue->data[2*index+1]->sortby) + { + uint32_t newindex; + Result *temp; + + newindex=2*index+1; + + temp=queue->data[newindex]; + queue->data[newindex]=queue->data[index]; + queue->data[index]=temp; + + queue->data[index]->queued=index; + queue->data[newindex]->queued=newindex; + } + + return(retval); +} diff --git a/src/results.c b/src/results.c new file mode 100644 index 0000000..b5dec42 --- /dev/null +++ b/src/results.c @@ -0,0 +1,242 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/results.c,v 1.21 2010/07/07 19:04:18 amb Exp $ + + Result data type functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include + +#include "results.h" + +/*+ The size of the increment for the Results data structure. +*/ +#define RESULTS_INCREMENT 64 + + +/*++++++++++++++++++++++++++++++++++++++ + Allocate a new results list. + + Results *NewResultsList Returns the results list. + + int nbins The number of bins in the results array. + ++++++++++++++++++++++++++++++++++++++*/ + +Results *NewResultsList(int nbins) +{ + Results *results; + uint32_t i; + + results=(Results*)malloc(sizeof(Results)); + + results->nbins=1; + results->mask=~0; + + while(nbins>>=1) + { + results->mask<<=1; + results->nbins<<=1; + } + + results->mask=~results->mask; + + results->alloced=RESULTS_INCREMENT; + results->number=0; + + results->count=(uint32_t*)malloc(results->nbins*sizeof(uint32_t)); + results->point=(Result***)malloc(results->nbins*sizeof(Result**)); + + for(i=0;inbins;i++) + { + results->count[i]=0; + + results->point[i]=(Result**)malloc(results->alloced*sizeof(Result*)); + } + + results->data=(Result**)malloc(1*sizeof(Result*)); + results->data[0]=(Result*)malloc(results->nbins*RESULTS_INCREMENT*sizeof(Result)); + + results->start=NO_NODE; + results->finish=NO_NODE; + + return(results); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Allocate a new results list. + + Results *results The results list to be destroyed. + ++++++++++++++++++++++++++++++++++++++*/ + +void FreeResultsList(Results *results) +{ + int i,c=(results->number-1)/(results->nbins*RESULTS_INCREMENT); + + for(i=c;i>=0;i--) + free(results->data[i]); + + free(results->data); + + for(i=0;inbins;i++) + free(results->point[i]); + + free(results->point); + + free(results->count); + + free(results); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Insert a new result into the results data structure in the right order. + + Result *InsertResult Returns the result that has been inserted. + + Results *results The results structure to insert into. + + index_t node The node that is to be inserted into the results. + ++++++++++++++++++++++++++++++++++++++*/ + +Result *InsertResult(Results *results,index_t node) +{ + int bin=node&results->mask; + uint32_t i; + + /* Check that the arrays have enough space. */ + + if(results->count[bin]==results->alloced) + { + results->alloced+=RESULTS_INCREMENT; + + for(i=0;inbins;i++) + results->point[i]=(Result**)realloc((void*)results->point[i],results->alloced*sizeof(Result*)); + } + + if(results->number && (results->number%RESULTS_INCREMENT)==0 && (results->number%(RESULTS_INCREMENT*results->nbins))==0) + { + int c=results->number/(results->nbins*RESULTS_INCREMENT); + + results->data=(Result**)realloc((void*)results->data,(c+1)*sizeof(Result*)); + results->data[c]=(Result*)malloc(results->nbins*RESULTS_INCREMENT*sizeof(Result)); + } + + /* Insert the new entry */ + + results->point[bin][results->count[bin]]=&results->data[results->number/(results->nbins*RESULTS_INCREMENT)][results->number%(results->nbins*RESULTS_INCREMENT)]; + + results->number++; + + results->count[bin]++; + + results->point[bin][results->count[bin]-1]->node=node; + results->point[bin][results->count[bin]-1]->queued=NOT_QUEUED; + + return(results->point[bin][results->count[bin]-1]); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Zero the values in a result structure. + + Result *result The result to modify. + ++++++++++++++++++++++++++++++++++++++*/ + +void ZeroResult(Result *result) +{ + result->prev=NO_NODE; + result->next=NO_NODE; + + result->score=0; + result->sortby=0; + + result->segment=NULL; +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find a result; search by node. + + Result *FindResult Returns the result that has been found. + + Results *results The results structure to search. + + index_t node The node that is to be found. + ++++++++++++++++++++++++++++++++++++++*/ + +Result *FindResult(Results *results,index_t node) +{ + int bin=node&results->mask; + int i; + + for(i=results->count[bin]-1;i>=0;i--) + if(results->point[bin][i]->node==node) + return(results->point[bin][i]); + + return(NULL); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find a result from a set of results. + + Result *FirstResult Returns the first results from a set of results. + + Results *results The set of results. + ++++++++++++++++++++++++++++++++++++++*/ + +Result *FirstResult(Results *results) +{ + return(&results->data[0][0]); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find a result from a set of results. + + Result *NextResult Returns the next result from a set of results. + + Results *results The set of results. + + Result *result The previous result. + ++++++++++++++++++++++++++++++++++++++*/ + +Result *NextResult(Results *results,Result *result) +{ + int i,j=0,c=(results->number-1)/(results->nbins*RESULTS_INCREMENT); + + for(i=0;i<=c;i++) + { + j=result-results->data[i]; + + if(j>=0 && j<(results->nbins*RESULTS_INCREMENT)) + break; + } + + if(++j>=(results->nbins*RESULTS_INCREMENT)) + {i++;j=0;} + + if((i*(results->nbins*RESULTS_INCREMENT)+j)>=results->number) + return(NULL); + + return(&results->data[i][j]); +} diff --git a/src/results.h b/src/results.h new file mode 100644 index 0000000..a7191f0 --- /dev/null +++ b/src/results.h @@ -0,0 +1,112 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/results.h,v 1.17 2009/11/13 19:24:11 amb Exp $ + + A header file for the results. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008,2009 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef RESULTS_H +#define RESULTS_H /*+ To stop multiple inclusions. +*/ + +#include + +#include "types.h" + + +/* Constants */ + +/*+ A result is not currently queued. +*/ +#define NOT_QUEUED (uint32_t)(~0) + + +/* Data structures */ + +/*+ The result for a node. +*/ +typedef struct _Result +{ + index_t node; /*+ The node for which this result applies. +*/ + + index_t prev; /*+ The previous node following the best path. +*/ + index_t next; /*+ The next node following the best path. +*/ + + score_t score; /*+ The best actual weighted distance or duration score from the start to the node. +*/ + + score_t sortby; /*+ The best possible weighted distance or duration score from the start to the finish. +*/ + uint32_t queued; /*+ The position of this result in the queue. +*/ + + Segment *segment; /*+ The segment for the path to here (from prev). +*/ +} + Result; + +/*+ A list of results. +*/ +typedef struct _Results +{ + uint32_t nbins; /*+ The number of bins. +*/ + uint32_t mask; /*+ A bit mask to select the bottom 'nbins' bits. +*/ + + uint32_t alloced; /*+ The amount of space allocated for results + (the length of the number and pointers arrays and + 1/nbins times the amount in the real results). +*/ + uint32_t number; /*+ The total number of occupied results. +*/ + + uint32_t *count; /*+ An array of nbins counters of results in each array. +*/ + Result ***point; /*+ An array of nbins arrays of pointers to actual results. +*/ + + Result **data; /*+ An array of arrays containing the actual results + (don't need to realloc the array of data when adding more, + only realloc the array that points to the array of data). + Most importantly pointers into the real data don't change + as more space is allocated (since realloc is not being used). +*/ + + index_t start; /*+ The start node. +*/ + index_t finish; /*+ The finish node. +*/ +} + Results; + + +/* Forward definitions for opaque type */ + +typedef struct _Queue Queue; + + +/* Results Functions */ + +Results *NewResultsList(int nbins); +void FreeResultsList(Results *results); + +Result *InsertResult(Results *results,index_t node); +void ZeroResult(Result *result); + +Result *FindResult(Results *results,index_t node); + +Result *FirstResult(Results *results); +Result *NextResult(Results *results,Result *result); + + +/* Queue Functions */ + +Queue *NewQueueList(void); +void FreeQueueList(Queue *queue); + +void InsertInQueue(Queue *queue,Result *result); +Result *PopFromQueue(Queue *queue); + + +#endif /* RESULTS_H */ diff --git a/src/router.c b/src/router.c new file mode 100644 index 0000000..46ca0b4 --- /dev/null +++ b/src/router.c @@ -0,0 +1,814 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/router.c,v 1.83 2010/06/28 17:56:26 amb Exp $ + + OSM router. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include + +#include "types.h" +#include "functions.h" +#include "translations.h" +#include "profiles.h" +#include "nodes.h" +#include "segments.h" +#include "ways.h" + + +/*+ The number of waypoints allowed to be specified. +*/ +#define NWAYPOINTS 99 + +/*+ The maximum distance from the specified point to search for a node or segment (in km). +*/ +#define MAXSEARCH 1 + +/*+ The minimum distance along a segment from a node to insert a fake node. (in km). +*/ +#define MINSEGMENT 0.005 + + +/*+ A set of fake segments to allow start/finish in the middle of a segment. +*/ +static Segment fake_segments[2*NWAYPOINTS]; + +/*+ A set of fake node latitudes and longitudes. +*/ +static double point_lon[NWAYPOINTS+1],point_lat[NWAYPOINTS+1]; + +/*+ The option not to print any progress information. +*/ +int option_quiet=0; + +/*+ The options to select the format of the output. +*/ +int option_html=0,option_gpx_track=0,option_gpx_route=0,option_text=0,option_text_all=0,option_none=0; + +/*+ The option to calculate the quickest route insted of the shortest. +*/ +int option_quickest=0; + + +/* Local functions */ + +static void print_usage(int detail); + + +/*++++++++++++++++++++++++++++++++++++++ + The main program for the router. + ++++++++++++++++++++++++++++++++++++++*/ + +int main(int argc,char** argv) +{ + Nodes *OSMNodes; + Segments *OSMSegments; + Ways *OSMWays; + Results *results[NWAYPOINTS+1]={NULL}; + int point_used[NWAYPOINTS+1]={0}; + int help_profile=0,help_profile_xml=0,help_profile_json=0,help_profile_pl=0; + char *dirname=NULL,*prefix=NULL; + char *profiles=NULL,*profilename=NULL; + char *translations=NULL,*language=NULL; + int exactnodes=0; + Transport transport=Transport_None; + Profile *profile=NULL; + index_t start=NO_NODE,finish=NO_NODE; + int arg,point; + + /* Parse the command line arguments */ + + if(argc<2) + print_usage(0); + + /* Get the non-routing, general program options */ + + for(arg=1;argtransport=transport; + } + + /* Parse the other command line arguments */ + + for(arg=1;argNWAYPOINTS || point_used[point]&1) + print_usage(0); + + point_lon[point]=degrees_to_radians(atof(p)); + point_used[point]+=1; + } + else if(!strncmp(argv[arg],"--lat",5) && isdigit(argv[arg][5])) + { + char *p=&argv[arg][6]; + while(isdigit(*p)) p++; + if(*p++!='=') + print_usage(0); + + point=atoi(&argv[arg][5]); + if(point>NWAYPOINTS || point_used[point]&2) + print_usage(0); + + point_lat[point]=degrees_to_radians(atof(p)); + point_used[point]+=2; + } + else if(!strncmp(argv[arg],"--transport=",12)) + ; /* Done this already */ + else if(!strncmp(argv[arg],"--highway-",10)) + { + Highway highway; + char *equal=strchr(argv[arg],'='); + char *string; + + if(!equal) + print_usage(0); + + string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+10); + string[equal-argv[arg]-10]=0; + + highway=HighwayType(string); + + if(highway==Way_Count) + print_usage(0); + + profile->highway[highway]=atof(equal+1); + + free(string); + } + else if(!strncmp(argv[arg],"--speed-",8)) + { + Highway highway; + char *equal=strchr(argv[arg],'='); + char *string; + + if(!equal) + print_usage(0); + + string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+8); + string[equal-argv[arg]-8]=0; + + highway=HighwayType(string); + + if(highway==Way_Count) + print_usage(0); + + profile->speed[highway]=kph_to_speed(atof(equal+1)); + + free(string); + } + else if(!strncmp(argv[arg],"--property-",11)) + { + Property property; + char *equal=strchr(argv[arg],'='); + char *string; + + if(!equal) + print_usage(0); + + string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+11); + string[equal-argv[arg]-11]=0; + + property=PropertyType(string); + + if(property==Way_Count) + print_usage(0); + + profile->props_yes[property]=atof(equal+1); + + free(string); + } + else if(!strncmp(argv[arg],"--oneway=",9)) + profile->oneway=!!atoi(&argv[arg][9]); + else if(!strncmp(argv[arg],"--weight=",9)) + profile->weight=tonnes_to_weight(atof(&argv[arg][9])); + else if(!strncmp(argv[arg],"--height=",9)) + profile->height=metres_to_height(atof(&argv[arg][9])); + else if(!strncmp(argv[arg],"--width=",8)) + profile->width=metres_to_width(atof(&argv[arg][8])); + else if(!strncmp(argv[arg],"--length=",9)) + profile->length=metres_to_length(atof(&argv[arg][9])); + else + print_usage(0); + } + + for(point=1;point<=NWAYPOINTS;point++) + if(point_used[point]==1 || point_used[point]==2) + print_usage(0); + + if(help_profile) + { + PrintProfile(profile); + + return(0); + } + else if(help_profile_xml) + { + PrintProfilesXML(); + + return(0); + } + else if(help_profile_json) + { + PrintProfilesJSON(); + + return(0); + } + else if(help_profile_pl) + { + PrintProfilesPerl(); + + return(0); + } + + /* Load in the translations */ + + if(option_html==0 && option_gpx_track==0 && option_gpx_route==0 && option_text==0 && option_text_all==0 && option_none==0) + option_html=option_gpx_track=option_gpx_route=option_text=option_text_all=1; + + if(option_html || option_gpx_route || option_gpx_track) + { + if(translations && ExistsFile(translations)) + ; + else if(!translations && ExistsFile(FileName(dirname,prefix,"translations.xml"))) + translations=FileName(dirname,prefix,"translations.xml"); + + if(!translations && language) + { + fprintf(stderr,"Error: Cannot use '--language' option without reading some translations.\n"); + return(1); + } + + if(translations && ParseXMLTranslations(translations,language)) + { + fprintf(stderr,"Error: Cannot read the translations in the file '%s'.\n",translations); + return(1); + } + } + + /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */ + + OSMNodes=LoadNodeList(FileName(dirname,prefix,"nodes.mem")); + + OSMSegments=LoadSegmentList(FileName(dirname,prefix,"segments.mem")); + + OSMWays=LoadWayList(FileName(dirname,prefix,"ways.mem")); + + if(UpdateProfile(profile,OSMWays)) + { + fprintf(stderr,"Error: Profile is invalid or not compatible with database.\n"); + return(1); + } + + /* Loop through all pairs of points */ + + for(point=1;point<=NWAYPOINTS;point++) + { + Results *begin,*end; + distance_t distmax=km_to_distance(MAXSEARCH); + distance_t distmin; + Segment *segment=NULL; + index_t node1,node2; + + if(point_used[point]!=3) + continue; + + /* Find the closest point */ + + start=finish; + + if(exactnodes) + { + finish=FindClosestNode(OSMNodes,OSMSegments,OSMWays,point_lat[point],point_lon[point],distmax,profile,&distmin); + } + else + { + distance_t dist1,dist2; + + if((segment=FindClosestSegment(OSMNodes,OSMSegments,OSMWays,point_lat[point],point_lon[point],distmax,profile,&distmin,&node1,&node2,&dist1,&dist2))) + finish=CreateFakes(OSMNodes,point,segment,node1,node2,dist1,dist2); + else + finish=NO_NODE; + } + + if(finish==NO_NODE) + { + fprintf(stderr,"Error: Cannot find node close to specified point %d.\n",point); + return(1); + } + + if(!option_quiet) + { + double lat,lon; + + if(IsFakeNode(finish)) + GetFakeLatLong(finish,&lat,&lon); + else + GetLatLong(OSMNodes,finish,&lat,&lon); + + if(IsFakeNode(finish)) + printf("Point %d is segment %d (node %d -> %d): %3.6f %4.6f = %2.3f km\n",point,IndexSegment(OSMSegments,segment),node1,node2, + radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin)); + else + printf("Point %d is node %d: %3.6f %4.6f = %2.3f km\n",point,finish, + radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin)); + } + + if(start==NO_NODE) + continue; + + if(start==finish) + continue; + + /* Calculate the beginning of the route */ + + if(!IsFakeNode(start) && IsSuperNode(OSMNodes,start)) + { + Result *result; + + begin=NewResultsList(1); + + begin->start=start; + + result=InsertResult(begin,start); + + ZeroResult(result); + } + else + { + begin=FindStartRoutes(OSMNodes,OSMSegments,OSMWays,start,profile); + + if(!begin) + { + fprintf(stderr,"Error: Cannot find initial section of route compatible with profile.\n"); + return(1); + } + } + + if(FindResult(begin,finish)) + { + FixForwardRoute(begin,finish); + + results[point]=begin; + + if(!option_quiet) + { + printf("\rRouted: Super-Nodes Checked = %d\n",begin->number); + fflush(stdout); + } + } + else + { + Results *superresults; + + /* Calculate the end of the route */ + + if(!IsFakeNode(finish) && IsSuperNode(OSMNodes,finish)) + { + Result *result; + + end=NewResultsList(1); + + end->finish=finish; + + result=InsertResult(end,finish); + + ZeroResult(result); + } + else + { + end=FindFinishRoutes(OSMNodes,OSMSegments,OSMWays,finish,profile); + + if(!end) + { + fprintf(stderr,"Error: Cannot find final section of route compatible with profile.\n"); + return(1); + } + } + + /* Calculate the middle of the route */ + + superresults=FindMiddleRoute(OSMNodes,OSMSegments,OSMWays,begin,end,profile); + + FreeResultsList(begin); + FreeResultsList(end); + + if(!superresults) + { + fprintf(stderr,"Error: Cannot find route compatible with profile.\n"); + return(1); + } + + results[point]=CombineRoutes(superresults,OSMNodes,OSMSegments,OSMWays,profile); + + FreeResultsList(superresults); + } + } + + /* Print out the combined route */ + + if(!option_none) + PrintRoute(results,NWAYPOINTS,OSMNodes,OSMSegments,OSMWays,profile); + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Create a pair of fake segments corresponding to the given segment split in two. + + index_t CreateFakes Returns the fake node index (or a real one in special cases). + + Nodes *nodes The set of nodes to use. + + int point Which of the waypoints is this. + + Segment *segment The segment to split. + + index_t node1 The first node at the end of this segment. + + index_t node2 The second node at the end of this segment. + + distance_t dist1 The distance to the first node. + + distance_t dist2 The distance to the second node. + ++++++++++++++++++++++++++++++++++++++*/ + +index_t CreateFakes(Nodes *nodes,int point,Segment *segment,index_t node1,index_t node2,distance_t dist1,distance_t dist2) +{ + index_t fakenode; + double lat1,lon1,lat2,lon2; + + /* Check if we are actually close enough to an existing node */ + + if(dist1km_to_distance(MINSEGMENT)) + return(node1); + + if(dist2km_to_distance(MINSEGMENT)) + return(node2); + + if(dist13 && lat2<-3) + lat2+=2*M_PI; + else if(lat1<-3 && lat2>3) + lat1+=2*M_PI; + + point_lat[point]=lat1+(lat2-lat1)*(double)dist1/(double)(dist1+dist2); + point_lon[point]=lon1+(lon2-lon1)*(double)dist1/(double)(dist1+dist2); + + if(point_lat[point]>M_PI) point_lat[point]-=2*M_PI; + + /* Create the first fake segment */ + + fake_segments[2*point-2]=*segment; + + if(segment->node1==node1) + fake_segments[2*point-2].node1=fakenode; + else + fake_segments[2*point-2].node2=fakenode; + + fake_segments[2*point-2].distance=DISTANCE(dist1)|DISTFLAG(segment->distance); + + /* Create the second fake segment */ + + fake_segments[2*point-1]=*segment; + + if(segment->node1==node2) + fake_segments[2*point-1].node1=fakenode; + else + fake_segments[2*point-1].node2=fakenode; + + fake_segments[2*point-1].distance=DISTANCE(dist2)|DISTFLAG(segment->distance); + + return(fakenode); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Lookup the latitude and longitude of a fake node. + + index_t fakenode The node to lookup. + + double *latitude Returns the latitude + + double *longitude Returns the longitude. + ++++++++++++++++++++++++++++++++++++++*/ + +void GetFakeLatLong(index_t fakenode, double *latitude,double *longitude) +{ + index_t realnode=fakenode&(~NODE_SUPER); + + *latitude =point_lat[realnode]; + *longitude=point_lon[realnode]; +} + + +/*++++++++++++++++++++++++++++++++++++++ + Finds the first fake segment associated to a fake node. + + Segment *FirstFakeSegment Returns the first fake segment. + + index_t fakenode The node to lookup. + ++++++++++++++++++++++++++++++++++++++*/ + +Segment *FirstFakeSegment(index_t fakenode) +{ + index_t realnode=fakenode&(~NODE_SUPER); + + return(&fake_segments[2*realnode-2]); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Finds the next (there can only be two) fake segment associated to a fake node. + + Segment *NextFakeSegment Returns the second fake segment. + + Segment *segment The first fake segment. + + index_t fakenode The node to lookup. + ++++++++++++++++++++++++++++++++++++++*/ + +Segment *NextFakeSegment(Segment *segment,index_t fakenode) +{ + index_t realnode=fakenode&(~NODE_SUPER); + + if(segment==&fake_segments[2*realnode-2]) + return(&fake_segments[2*realnode-1]); + else + return(NULL); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Finds the next (there can only be two) fake segment associated to a fake node. + + Segment *ExtraFakeSegment Returns a segment between the two specified nodes if it exists. + + index_t node The real node. + + index_t fakenode The fake node to lookup. + ++++++++++++++++++++++++++++++++++++++*/ + +Segment *ExtraFakeSegment(index_t node,index_t fakenode) +{ + index_t realnode=fakenode&(~NODE_SUPER); + + if(fake_segments[2*realnode-2].node1==node || fake_segments[2*realnode-2].node2==node) + return(&fake_segments[2*realnode-2]); + + if(fake_segments[2*realnode-1].node1==node || fake_segments[2*realnode-1].node2==node) + return(&fake_segments[2*realnode-1]); + + return(NULL); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Print out the usage information. + + int detail The level of detail to use - 0 = low, 1 = high. + ++++++++++++++++++++++++++++++++++++++*/ + +static void print_usage(int detail) +{ + fprintf(stderr, + "Usage: router [--help | --help-profile | --help-profile-xml |\n" + " --help-profile-json | --help-profile-perl ]\n" + " [--dir=] [--prefix=]\n" + " [--profiles=] [--translations=]\n" + " [--exact-nodes-only]\n" + " [--quiet]\n" + " [--language=]\n" + " [--output-html]\n" + " [--output-gpx-track] [--output-gpx-route]\n" + " [--output-text] [--output-text-all]\n" + " [--output-none]\n" + " [--profile=]\n" + " [--transport=]\n" + " [--shortest | --quickest]\n" + " --lon1= --lat1=\n" + " --lon2= --lon2=\n" + " [ ... --lon99= --lon99=]\n" + " [--highway-= ...]\n" + " [--speed-= ...]\n" + " [--property-= ...]\n" + " [--oneway=(0|1)]\n" + " [--weight=]\n" + " [--height=] [--width=] [--length=]\n"); + + if(detail) + fprintf(stderr, + "\n" + "--help Prints this information.\n" + "--help-profile Prints the information about the selected profile.\n" + "--help-profile-xml Prints all loaded profiles in XML format.\n" + "--help-profile-json Prints all loaded profiles in JSON format.\n" + "--help-profile-perl Prints all loaded profiles in Perl format.\n" + "\n" + "--dir= The directory containing the routing database.\n" + "--prefix= The filename prefix for the routing database.\n" + "--profiles= The name of the profiles (defaults to 'profiles.xml'\n" + " with '--dirname' and '--prefix' options).\n" + "--translations= The filename of the translations (defaults to\n" + " 'translations.xml' with '--dirname' and '--prefix').\n" + "\n" + "--exact-nodes-only Only route between nodes (don't find closest segment).\n" + "\n" + "--quiet Don't print any screen output when running.\n" + "--language= Use the translations for specified language.\n" + "--output-html Write an HTML description of the route.\n" + "--output-gpx-track Write a GPX track file with all route points.\n" + "--output-gpx-route Write a GPX route file with interesting junctions.\n" + "--output-text Write a plain text file with interesting junctions.\n" + "--output-text-all Write a plain test file with all route points.\n" + "--output-none Don't write any output files or read any translations.\n" + " (If no output option is given then all are written.)\n" + "\n" + "--profile= Select the loaded profile with this name.\n" + "--transport= Select the transport to use (selects the profile\n" + " named after the transport if '--profile' is not used.)\n" + "\n" + "--shortest Find the shortest route between the waypoints.\n" + "--quickest Find the quickest route between the waypoints.\n" + "\n" + "--lon= Specify the longitude of the n'th waypoint.\n" + "--lat= Specify the latitude of the n'th waypoint.\n" + "\n" + " Routing preference options\n" + "--highway-= * preference for highway type (%%).\n" + "--speed-= * speed for highway type (km/h).\n" + "--property-= * preference for proprty type (%%).\n" + "--oneway=(0|1) * oneway streets are to be obeyed.\n" + "--weight= * maximum weight limit (tonnes).\n" + "--height= * maximum height limit (metres).\n" + "--width= * maximum width limit (metres).\n" + "--length= * maximum length limit (metres).\n" + "\n" + " defaults to motorcar but can be set to:\n" + "%s" + "\n" + " can be selected from:\n" + "%s" + "\n" + " can be selected from:\n" + "%s", + TransportList(),HighwayList(),PropertyList()); + + exit(!detail); +} diff --git a/src/segments.c b/src/segments.c new file mode 100644 index 0000000..0557d50 --- /dev/null +++ b/src/segments.c @@ -0,0 +1,170 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/segments.c,v 1.45 2010/04/28 17:27:02 amb Exp $ + + Segment data type functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include + +#include "types.h" +#include "functions.h" +#include "nodes.h" +#include "segments.h" +#include "ways.h" +#include "profiles.h" + + +/*++++++++++++++++++++++++++++++++++++++ + Load in a segment list from a file. + + Segments* LoadSegmentList Returns the segment list that has just been loaded. + + const char *filename The name of the file to load. + ++++++++++++++++++++++++++++++++++++++*/ + +Segments *LoadSegmentList(const char *filename) +{ + void *data; + Segments *segments; + + segments=(Segments*)malloc(sizeof(Segments)); + + data=MapFile(filename); + + /* Copy the Segments structure from the loaded data */ + + *segments=*((Segments*)data); + + /* Adjust the pointers in the Segments structure. */ + + segments->data=data; + segments->segments=(Segment*)(data+sizeof(Segments)); + + return(segments); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find the next segment with a particular starting node. + + Segment *NextSegment Returns a pointer to the next segment with the same id. + + Segments* segments The set of segments to process. + + Segment *segment The current segment. + + index_t node The current node. + ++++++++++++++++++++++++++++++++++++++*/ + +Segment *NextSegment(Segments* segments,Segment *segment,index_t node) +{ + if(segment->node1==node) + { + segment++; + if((segment-segments->segments)>=segments->number || segment->node1!=node) + return(NULL); + else + return(segment); + } + else + { + if(segment->next2==NO_NODE) + return(NULL); + else + return(LookupSegment(segments,segment->next2)); + } +} + + +/*++++++++++++++++++++++++++++++++++++++ + Calculate the distance between two locations. + + distance_t Distance Returns the distance between the locations. + + double lat1 The latitude of the first location. + + double lon1 The longitude of the first location. + + double lat2 The latitude of the second location. + + double lon2 The longitude of the second location. + ++++++++++++++++++++++++++++++++++++++*/ + +distance_t Distance(double lat1,double lon1,double lat2,double lon2) +{ + double dlon = lon1 - lon2; + double dlat = lat1 - lat2; + + double a1,a2,a,sa,c,d; + + if(dlon==0 && dlat==0) + return 0; + + a1 = sin (dlat / 2); + a2 = sin (dlon / 2); + a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2; + sa = sqrt (a); + if (sa <= 1.0) + {c = 2 * asin (sa);} + else + {c = 2 * asin (1.0);} + d = 6378.137 * c; + + return km_to_distance(d); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Calculate the duration of segment. + + duration_t Duration Returns the duration of travel between the nodes. + + Segment *segment The segment to traverse. + + Way *way The way that the segment belongs to. + + Profile *profile The profile of the transport being used. + ++++++++++++++++++++++++++++++++++++++*/ + +duration_t Duration(Segment *segment,Way *way,Profile *profile) +{ + speed_t speed1=way->speed; + speed_t speed2=profile->speed[HIGHWAY(way->type)]; + distance_t distance=DISTANCE(segment->distance); + + if(speed1==0) + { + if(speed2==0) + return(hours_to_duration(10)); + else + return distance_speed_to_duration(distance,speed2); + } + else /* if(speed1!=0) */ + { + if(speed2==0) + return distance_speed_to_duration(distance,speed1); + else if(speed1<=speed2) + return distance_speed_to_duration(distance,speed1); + else + return distance_speed_to_duration(distance,speed2); + } +} diff --git a/src/segments.h b/src/segments.h new file mode 100644 index 0000000..8b6554f --- /dev/null +++ b/src/segments.h @@ -0,0 +1,101 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/segments.h,v 1.34 2009/11/14 19:39:20 amb Exp $ + + A header file for the segments. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008,2009 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef SEGMENTS_H +#define SEGMENTS_H /*+ To stop multiple inclusions. +*/ + +#include + +#include "types.h" +#include "profiles.h" + + +/* Data structures */ + + +/*+ A structure containing a single segment. +*/ +struct _Segment +{ + index_t node1; /*+ The index of the starting node. +*/ + index_t node2; /*+ The index of the finishing node. +*/ + + index_t next2; /*+ The index of the next segment sharing node2. +*/ + + index_t way; /*+ The index of the way associated with the segment. +*/ + + distance_t distance; /*+ The distance between the nodes. +*/ +}; + + +/*+ A structure containing a set of segments (mmap format). +*/ +struct _Segments +{ + uint32_t number; /*+ How many segments in total? +*/ + uint32_t snumber; /*+ How many super-segments? +*/ + uint32_t nnumber; /*+ How many normal segments? +*/ + + Segment *segments; /*+ An array of segments. +*/ + + void *data; /*+ The memory mapped data. +*/ +}; + + +/* Macros */ + + +/*+ Return a segment pointer given a set of segments and an index. +*/ +#define LookupSegment(xxx,yyy) (&(xxx)->segments[yyy]) + +/*+ Return a segment index given a set of segments and a pointer. +*/ +#define IndexSegment(xxx,yyy) ((yyy)-&(xxx)->segments[0]) + +/*+ Return true if this is a normal segment. +*/ +#define IsNormalSegment(xxx) (((xxx)->distance)&SEGMENT_NORMAL) + +/*+ Return true if this is a super-segment. +*/ +#define IsSuperSegment(xxx) (((xxx)->distance)&SEGMENT_SUPER) + +/*+ Return true if the segment is oneway towards the specified node. +*/ +#define IsOnewayTo(xxx,yyy) ((xxx)->node1==(yyy)?((xxx)->distance&ONEWAY_2TO1):((xxx)->distance&ONEWAY_1TO2)) + +/*+ Return true if the segment is oneway from the specified node. +*/ +#define IsOnewayFrom(xxx,yyy) ((xxx)->node2==(yyy)?((xxx)->distance&ONEWAY_2TO1):((xxx)->distance&ONEWAY_1TO2)) + +/*+ Return the other node in the segment that is not the specified node. +*/ +#define OtherNode(xxx,yyy) ((xxx)->node1==(yyy)?(xxx)->node2:(xxx)->node1) + + +/* Functions */ + + +Segments *LoadSegmentList(const char *filename); + +Segment *NextSegment(Segments* segments,Segment *segment,index_t node); + +distance_t Distance(double lat1,double lon1,double lat2,double lon2); + +duration_t Duration(Segment *segment,Way *way,Profile *profile); + + +#endif /* SEGMENTS_H */ diff --git a/src/segmentsx.c b/src/segmentsx.c new file mode 100644 index 0000000..5a4f03b --- /dev/null +++ b/src/segmentsx.c @@ -0,0 +1,1053 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/segmentsx.c,v 1.51 2010/04/28 17:27:02 amb Exp $ + + Extended Segment data type functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "functions.h" +#include "nodesx.h" +#include "segmentsx.h" +#include "waysx.h" +#include "nodes.h" +#include "segments.h" +#include "ways.h" + + +/* Variables */ + +/*+ The command line '--slim' option. +*/ +extern int option_slim; + +/*+ The command line '--tmpdir' option or its default value. +*/ +extern char *option_tmpdirname; + +/* Local Functions */ + +static int sort_by_id(SegmentX *a,SegmentX *b); + +static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2); + + +/*++++++++++++++++++++++++++++++++++++++ + Allocate a new segment list (create a new file or open an existing one). + + SegmentsX *NewSegmentList Returns the segment list. + + int append Set to 1 if the file is to be opened for appending (now or later). + ++++++++++++++++++++++++++++++++++++++*/ + +SegmentsX *NewSegmentList(int append) +{ + SegmentsX *segmentsx; + + segmentsx=(SegmentsX*)calloc(1,sizeof(SegmentsX)); + + assert(segmentsx); /* Check calloc() worked */ + + segmentsx->filename=(char*)malloc(strlen(option_tmpdirname)+32); + + if(append) + sprintf(segmentsx->filename,"%s/segments.input.tmp",option_tmpdirname); + else + sprintf(segmentsx->filename,"%s/segments.%p.tmp",option_tmpdirname,segmentsx); + + if(append) + { + off_t size; + + segmentsx->fd=AppendFile(segmentsx->filename); + + size=SizeFile(segmentsx->filename); + + segmentsx->xnumber=size/sizeof(SegmentX); + } + else + segmentsx->fd=OpenFile(segmentsx->filename); + + return(segmentsx); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Free a segment list. + + SegmentsX *segmentsx The list to be freed. + + int keep Set to 1 if the file is to be kept. + ++++++++++++++++++++++++++++++++++++++*/ + +void FreeSegmentList(SegmentsX *segmentsx,int keep) +{ + if(!keep) + DeleteFile(segmentsx->filename); + + free(segmentsx->filename); + + if(segmentsx->idata) + free(segmentsx->idata); + + if(segmentsx->firstnode) + free(segmentsx->firstnode); + + if(segmentsx->sdata) + free(segmentsx->sdata); + + free(segmentsx); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Append a single segment to a segment list. + + SegmentsX* segmentsx The set of segments to process. + + way_t way The way that the segment belongs to. + + node_t node1 The first node in the segment. + + node_t node2 The second node in the segment. + + distance_t distance The distance between the nodes (or just the flags). + ++++++++++++++++++++++++++++++++++++++*/ + +void AppendSegment(SegmentsX* segmentsx,way_t way,node_t node1,node_t node2,distance_t distance) +{ + SegmentX segmentx; + + assert(!segmentsx->idata); /* Must not have idata filled in => unsorted */ + + segmentx.node1=node1; + segmentx.node2=node2; + segmentx.way=way; + segmentx.distance=distance; + + WriteFile(segmentsx->fd,&segmentx,sizeof(SegmentX)); + + segmentsx->xnumber++; +} + + +/*++++++++++++++++++++++++++++++++++++++ + Sort the segment list. + + SegmentsX* segmentsx The set of segments to process. + ++++++++++++++++++++++++++++++++++++++*/ + +void SortSegmentList(SegmentsX* segmentsx) +{ + int fd; + + /* Check the start conditions */ + + assert(!segmentsx->idata); /* Must not have idata filled in => unsorted */ + + /* Print the start message */ + + printf("Sorting Segments"); + fflush(stdout); + + /* Close the files and re-open them (finished appending) */ + + CloseFile(segmentsx->fd); + segmentsx->fd=ReOpenFile(segmentsx->filename); + + DeleteFile(segmentsx->filename); + + fd=OpenFile(segmentsx->filename); + + /* Sort by node indexes */ + + filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),(int (*)(const void*,const void*))sort_by_id,NULL); + + segmentsx->number=segmentsx->xnumber; + + /* Close the files and re-open them */ + + CloseFile(segmentsx->fd); + CloseFile(fd); + + segmentsx->fd=ReOpenFile(segmentsx->filename); + + /* Print the final message */ + + printf("\rSorted Segments: Segments=%d\n",segmentsx->xnumber); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Sort the segments into id order (node1 then node2). + + int sort_by_id Returns the comparison of the node fields. + + SegmentX *a The first segment. + + SegmentX *b The second segment. + ++++++++++++++++++++++++++++++++++++++*/ + +static int sort_by_id(SegmentX *a,SegmentX *b) +{ + node_t a_id1=a->node1; + node_t b_id1=b->node1; + + if(a_id1b_id1) + return(1); + else /* if(a_id1==b_id1) */ + { + node_t a_id2=a->node2; + node_t b_id2=b->node2; + + if(a_id2b_id2) + return(1); + else + { + distance_t a_distance=a->distance; + distance_t b_distance=b->distance; + + if(a_distanceb_distance) + return(1); + else + return(0); + } + } +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find the first segment index with a particular starting node. + + index_t IndexFirstSegmentX Returns a pointer to the index of the first extended segment with the specified id. + + SegmentsX* segmentsx The set of segments to process. + + node_t node The node to look for. + ++++++++++++++++++++++++++++++++++++++*/ + +index_t IndexFirstSegmentX(SegmentsX* segmentsx,node_t node) +{ + int start=0; + int end=segmentsx->number-1; + int mid; + int found; + + /* Check if the first node index exists */ + + if(segmentsx->firstnode) + { + index_t index=segmentsx->firstnode[node]; + + if(segmentsx->firstnode[node+1]==index) + return(NO_SEGMENT); + + return(index); + } + + assert(segmentsx->idata); /* Must have idata filled in => sorted by node 1 */ + + /* Binary search - search key exact match only is required. + * + * # <- start | Check mid and move start or end if it doesn't match + * # | + * # | Since an exact match is wanted we can set end=mid-1 + * # <- mid | or start=mid+1 because we know that mid doesn't match. + * # | + * # | Eventually either end=start or end=start+1 and one of + * # <- end | start or end is the wanted one. + */ + + if(endidata[start]) /* Check key is not before start */ + return(NO_SEGMENT); + else if(node>segmentsx->idata[end]) /* Check key is not after end */ + return(NO_SEGMENT); + else + { + do + { + mid=(start+end)/2; /* Choose mid point */ + + if(segmentsx->idata[mid]idata[mid]>node) /* Mid point is too high */ + end=mid; + else /* Mid point is correct */ + {found=mid; goto found;} + } + while((end-start)>1); + + if(segmentsx->idata[start]==node) /* Start is correct */ + {found=start; goto found;} + + if(segmentsx->idata[end]==node) /* End is correct */ + {found=end; goto found;} + } + + return(NO_SEGMENT); + + found: + + while(found>0 && segmentsx->idata[found-1]==node) + found--; + + return(found); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find the next segment index with a particular starting node. + + index_t IndexNextSegmentX Returns the index of the next segment with the same id. + + SegmentsX* segmentsx The set of segments to process. + + index_t segindex The current segment index. + + index_t nodeindex The node index. + ++++++++++++++++++++++++++++++++++++++*/ + +index_t IndexNextSegmentX(SegmentsX* segmentsx,index_t segindex,index_t nodeindex) +{ + assert(segmentsx->firstnode); /* Must have firstnode filled in => segments updated */ + + if(++segindex==segmentsx->firstnode[nodeindex+1]) + return(NO_SEGMENT); + else + return(segindex); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Lookup a particular segment. + + SegmentX *LookupSegmentX Returns a pointer to the extended segment with the specified id. + + SegmentsX* segmentsx The set of segments to process. + + index_t index The segment index to look for. + + int position The position in the cache to use. + ++++++++++++++++++++++++++++++++++++++*/ + +SegmentX *LookupSegmentX(SegmentsX* segmentsx,index_t index,int position) +{ + assert(index!=NO_SEGMENT); /* Must be a valid segment */ + + if(option_slim) + { + SeekFile(segmentsx->fd,index*sizeof(SegmentX)); + + ReadFile(segmentsx->fd,&segmentsx->cached[position-1],sizeof(SegmentX)); + + return(&segmentsx->cached[position-1]); + } + else + { + return(&segmentsx->xdata[index]); + } +} + + +/*++++++++++++++++++++++++++++++++++++++ + Remove bad segments (duplicated, zero length or missing nodes). + + NodesX *nodesx The nodes to check. + + SegmentsX *segmentsx The segments to modify. + ++++++++++++++++++++++++++++++++++++++*/ + +void RemoveBadSegments(NodesX *nodesx,SegmentsX *segmentsx) +{ + int duplicate=0,loop=0,missing=0,good=0,total=0; + SegmentX segmentx; + int fd; + node_t prevnode1=NO_NODE,prevnode2=NO_NODE; + + /* Print the start message */ + + printf("Checking: Segments=0 Duplicate=0 Loop=0 Missing-Node=0"); + fflush(stdout); + + /* Allocate the array of indexes */ + + segmentsx->idata=(node_t*)malloc(segmentsx->xnumber*sizeof(node_t)); + + assert(segmentsx->idata); /* Check malloc() worked */ + + /* Modify the on-disk image */ + + DeleteFile(segmentsx->filename); + + fd=OpenFile(segmentsx->filename); + SeekFile(segmentsx->fd,0); + + while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX))) + { + if(prevnode1==segmentx.node1 && prevnode2==segmentx.node2) + duplicate++; + else if(segmentx.node1==segmentx.node2) + loop++; + else if(IndexNodeX(nodesx,segmentx.node1)==NO_NODE || + IndexNodeX(nodesx,segmentx.node2)==NO_NODE) + missing++; + else + { + WriteFile(fd,&segmentx,sizeof(SegmentX)); + + segmentsx->idata[good]=segmentx.node1; + good++; + + prevnode1=segmentx.node1; + prevnode2=segmentx.node2; + } + + total++; + + if(!(total%10000)) + { + printf("\rChecking: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d",total,duplicate,loop,missing); + fflush(stdout); + } + } + + /* Close the files and re-open them */ + + CloseFile(segmentsx->fd); + CloseFile(fd); + + segmentsx->fd=ReOpenFile(segmentsx->filename); + + segmentsx->number=good; + + /* Print the final message */ + + printf("\rChecked: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d \n",total,duplicate,loop,missing); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Measure the segments and replace node/way ids with indexes. + + SegmentsX* segmentsx The set of segments to process. + + NodesX *nodesx The list of nodes to use. + + WaysX *waysx The list of ways to use. + ++++++++++++++++++++++++++++++++++++++*/ + +void UpdateSegments(SegmentsX* segmentsx,NodesX *nodesx,WaysX *waysx) +{ + index_t index=0; + int i,fd; + SegmentX segmentx; + + /* Print the start message */ + + printf("Measuring Segments: Segments=0"); + fflush(stdout); + + /* Map into memory */ + + if(!option_slim) + nodesx->xdata=MapFile(nodesx->filename); + + /* Free the now-unneeded index */ + + free(segmentsx->idata); + segmentsx->idata=NULL; + + /* Allocate the array of indexes */ + + segmentsx->firstnode=(index_t*)malloc((nodesx->number+1)*sizeof(index_t)); + + assert(segmentsx->firstnode); /* Check malloc() worked */ + + for(i=0;inumber;i++) + segmentsx->firstnode[i]=NO_SEGMENT; + + segmentsx->firstnode[nodesx->number]=segmentsx->number; + + /* Modify the on-disk image */ + + DeleteFile(segmentsx->filename); + + fd=OpenFile(segmentsx->filename); + SeekFile(segmentsx->fd,0); + + while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX))) + { + index_t node1=IndexNodeX(nodesx,segmentx.node1); + index_t node2=IndexNodeX(nodesx,segmentx.node2); + index_t way =IndexWayX (waysx ,segmentx.way); + + NodeX *nodex1=LookupNodeX(nodesx,node1,1); + NodeX *nodex2=LookupNodeX(nodesx,node2,2); + + /* Replace the node and way ids with their indexes */ + + segmentx.node1=node1; + segmentx.node2=node2; + segmentx.way =way; + + /* Set the distance but preserve the ONEWAY_* flags */ + + segmentx.distance|=DISTANCE(DistanceX(nodex1,nodex2)); + + /* Set the first segment index in the nodes */ + + if(indexfirstnode[node1]) + segmentsx->firstnode[node1]=index; + + /* Write the modified segment */ + + WriteFile(fd,&segmentx,sizeof(SegmentX)); + + index++; + + if(!(index%10000)) + { + printf("\rMeasuring Segments: Segments=%d",index); + fflush(stdout); + } + } + + /* Close the files and re-open them */ + + CloseFile(segmentsx->fd); + CloseFile(fd); + + segmentsx->fd=ReOpenFile(segmentsx->filename); + + /* Free the other now-unneeded indexes */ + + free(nodesx->idata); + nodesx->idata=NULL; + + free(waysx->idata); + waysx->idata=NULL; + + /* Unmap from memory */ + + if(!option_slim) + nodesx->xdata=UnmapFile(nodesx->filename); + + /* Print the final message */ + + printf("\rMeasured Segments: Segments=%d \n",segmentsx->number); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Make the segments all point the same way (node1idata); /* Must not have idata filled in => not sorted by node 1 */ + + /* Print the start message */ + + printf("Rotating Segments: Segments=0 Rotated=0"); + fflush(stdout); + + /* Close the files and re-open them (finished appending) */ + + CloseFile(segmentsx->fd); + segmentsx->fd=ReOpenFile(segmentsx->filename); + + DeleteFile(segmentsx->filename); + + fd=OpenFile(segmentsx->filename); + + /* Modify the file contents */ + + while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX))) + { + if(segmentx.node1>segmentx.node2) + { + node_t temp; + + temp=segmentx.node1; + segmentx.node1=segmentx.node2; + segmentx.node2=temp; + + if(segmentx.distance&(ONEWAY_2TO1|ONEWAY_1TO2)) + segmentx.distance^=ONEWAY_2TO1|ONEWAY_1TO2; + + rotated++; + } + + WriteFile(fd,&segmentx,sizeof(SegmentX)); + + index++; + + if(!(index%10000)) + { + printf("\rRotating Segments: Segments=%d Rotated=%d",index,rotated); + fflush(stdout); + } + } + + /* Close the files and re-open them */ + + CloseFile(segmentsx->fd); + CloseFile(fd); + + segmentsx->fd=ReOpenFile(segmentsx->filename); + + /* Print the final message */ + + printf("\rRotated Segments: Segments=%d Rotated=%d \n",index,rotated); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Remove the duplicate segments. + + SegmentsX* segmentsx The set of segments to process. + + NodesX *nodesx The list of nodes to use. + + WaysX *waysx The list of ways to use. + ++++++++++++++++++++++++++++++++++++++*/ + +void DeduplicateSegments(SegmentsX* segmentsx,NodesX *nodesx,WaysX *waysx) +{ + int duplicate=0,good=0; + index_t firstindex=0,index=0; + int i,fd; + SegmentX prevsegmentx[16],segmentx; + + /* Print the start message */ + + printf("Deduplicating Segments: Segments=0 Duplicate=0"); + fflush(stdout); + + /* Map into memory */ + + if(!option_slim) + waysx->xdata=MapFile(waysx->filename); + + /* Allocate the array of indexes */ + + segmentsx->firstnode=(index_t*)malloc((nodesx->number+1)*sizeof(index_t)); + + assert(segmentsx->firstnode); /* Check malloc() worked */ + + for(i=0;inumber;i++) + segmentsx->firstnode[i]=NO_SEGMENT; + + segmentsx->firstnode[nodesx->number]=segmentsx->number; + + /* Modify the on-disk image */ + + DeleteFile(segmentsx->filename); + + fd=OpenFile(segmentsx->filename); + SeekFile(segmentsx->fd,0); + + while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX))) + { + int isduplicate=0; + + if(index && segmentx.node1==prevsegmentx[0].node1 && + segmentx.node2==prevsegmentx[0].node2) + { + index_t previndex=firstindex; + + while(previndexway,&wayx2->way)) + { + isduplicate=1; + duplicate++; + break; + } + } + + previndex++; + } + + assert((index-firstindex)<(sizeof(prevsegmentx)/sizeof(prevsegmentx[0]))); + + prevsegmentx[index-firstindex]=segmentx; + } + else + { + firstindex=index; + prevsegmentx[0]=segmentx; + } + + if(!isduplicate) + { + WriteFile(fd,&segmentx,sizeof(SegmentX)); + + if(goodfirstnode[segmentx.node1]) + segmentsx->firstnode[segmentx.node1]=good; + + good++; + } + + index++; + + if(!(index%10000)) + { + printf("\rDeduplicating Segments: Segments=%d Duplicate=%d",index,duplicate); + fflush(stdout); + } + } + + /* Close the files and re-open them */ + + CloseFile(segmentsx->fd); + CloseFile(fd); + + segmentsx->fd=ReOpenFile(segmentsx->filename); + + segmentsx->number=good; + + /* Fix-up the firstnode index for the missing nodes */ + + for(i=nodesx->number-1;i>=0;i--) + if(segmentsx->firstnode[i]==NO_SEGMENT) + segmentsx->firstnode[i]=segmentsx->firstnode[i+1]; + + /* Unmap from memory */ + + if(!option_slim) + waysx->xdata=UnmapFile(waysx->filename); + + /* Print the final message */ + + printf("\rDeduplicated Segments: Segments=%d Duplicate=%d Unique=%d\n",index,duplicate,index-duplicate); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Create the real segments data. + + SegmentsX* segmentsx The set of segments to use. + + WaysX* waysx The set of ways to use. + ++++++++++++++++++++++++++++++++++++++*/ + +void CreateRealSegments(SegmentsX *segmentsx,WaysX *waysx) +{ + index_t i; + + /* Check the start conditions */ + + assert(!segmentsx->sdata); /* Must not have sdata filled in => no real segments */ + + /* Print the start message */ + + printf("Creating Real Segments: Segments=0"); + fflush(stdout); + + /* Map into memory */ + + if(!option_slim) + { + segmentsx->xdata=MapFile(segmentsx->filename); + waysx->xdata=MapFile(waysx->filename); + } + + /* Free the unneeded memory */ + + free(segmentsx->firstnode); + segmentsx->firstnode=NULL; + + /* Allocate the memory */ + + segmentsx->sdata=(Segment*)malloc(segmentsx->number*sizeof(Segment)); + + assert(segmentsx->sdata); /* Check malloc() worked */ + + /* Loop through and fill */ + + for(i=0;inumber;i++) + { + SegmentX *segmentx=LookupSegmentX(segmentsx,i,1); + WayX *wayx=LookupWayX(waysx,segmentx->way,1); + + segmentsx->sdata[i].node1=0; + segmentsx->sdata[i].node2=0; + segmentsx->sdata[i].next2=NO_NODE; + segmentsx->sdata[i].way=wayx->prop; + segmentsx->sdata[i].distance=segmentx->distance; + + if(!((i+1)%10000)) + { + printf("\rCreating Real Segments: Segments=%d",i+1); + fflush(stdout); + } + } + + /* Unmap from memory */ + + if(!option_slim) + { + segmentsx->xdata=UnmapFile(segmentsx->filename); + waysx->xdata=UnmapFile(waysx->filename); + } + + /* Print the final message */ + + printf("\rCreating Real Segments: Segments=%d \n",segmentsx->number); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Assign the nodes indexes to the segments. + + SegmentsX* segmentsx The set of segments to process. + + NodesX *nodesx The list of nodes to use. + ++++++++++++++++++++++++++++++++++++++*/ + +void IndexSegments(SegmentsX* segmentsx,NodesX *nodesx) +{ + index_t i; + + /* Check the start conditions */ + + assert(nodesx->ndata); /* Must have ndata filled in => real nodes exist */ + assert(segmentsx->sdata); /* Must have sdata filled in => real segments exist */ + + /* Print the start message */ + + printf("Indexing Nodes: Nodes=0"); + fflush(stdout); + + /* Map into memory */ + + if(!option_slim) + { + nodesx->xdata=MapFile(nodesx->filename); + segmentsx->xdata=MapFile(segmentsx->filename); + } + + /* Index the segments */ + + for(i=0;inumber;i++) + { + NodeX *nodex=LookupNodeX(nodesx,i,1); + Node *node =&nodesx->ndata[nodex->id]; + index_t index=SEGMENT(node->firstseg); + + do + { + SegmentX *segmentx=LookupSegmentX(segmentsx,index,1); + + if(segmentx->node1==nodex->id) + { + segmentsx->sdata[index].node1=i; + + index++; + + if(index>=segmentsx->number) + break; + + segmentx=LookupSegmentX(segmentsx,index,1); + + if(segmentx->node1!=nodex->id) + break; + } + else + { + segmentsx->sdata[index].node2=i; + + if(segmentsx->sdata[index].next2==NO_NODE) + break; + else + index=segmentsx->sdata[index].next2; + } + } + while(1); + + if(!((i+1)%10000)) + { + printf("\rIndexing Nodes: Nodes=%d",i+1); + fflush(stdout); + } + } + + /* Unmap from memory */ + + if(!option_slim) + { + nodesx->xdata=UnmapFile(nodesx->filename); + segmentsx->xdata=UnmapFile(segmentsx->filename); + } + + /* Print the final message */ + + printf("\rIndexed Nodes: Nodes=%d \n",nodesx->number); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Save the segment list to a file. + + SegmentsX* segmentsx The set of segments to save. + + const char *filename The name of the file to save. + ++++++++++++++++++++++++++++++++++++++*/ + +void SaveSegmentList(SegmentsX* segmentsx,const char *filename) +{ + index_t i; + int fd; + Segments *segments; + int super_number=0,normal_number=0; + + /* Check the start conditions */ + + assert(segmentsx->sdata); /* Must have sdata filled in => real segments */ + + /* Print the start message */ + + printf("Writing Segments: Segments=0"); + fflush(stdout); + + /* Count the number of super-segments and normal segments */ + + for(i=0;inumber;i++) + { + if(IsSuperSegment(&segmentsx->sdata[i])) + super_number++; + if(IsNormalSegment(&segmentsx->sdata[i])) + normal_number++; + } + + /* Fill in a Segments structure with the offset of the real data in the file after + the Segment structure itself. */ + + segments=calloc(1,sizeof(Segments)); + + assert(segments); /* Check calloc() worked */ + + segments->number=segmentsx->number; + segments->snumber=super_number; + segments->nnumber=normal_number; + + segments->data=NULL; + segments->segments=NULL; + + /* Write out the Segments structure and then the real data. */ + + fd=OpenFile(filename); + + WriteFile(fd,segments,sizeof(Segments)); + + for(i=0;inumber;i++) + { + WriteFile(fd,&segmentsx->sdata[i],sizeof(Segment)); + + if(!((i+1)%10000)) + { + printf("\rWriting Segments: Segments=%d",i+1); + fflush(stdout); + } + } + + CloseFile(fd); + + /* Print the final message */ + + printf("\rWrote Segments: Segments=%d \n",segments->number); + fflush(stdout); + + /* Free the fake Segments */ + + free(segments); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Calculate the distance between two nodes. + + distance_t DistanceX Returns the distance between the extended nodes. + + NodeX *nodex1 The starting node. + + NodeX *nodex2 The end node. + ++++++++++++++++++++++++++++++++++++++*/ + +static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2) +{ + double dlon = latlong_to_radians(nodex1->longitude) - latlong_to_radians(nodex2->longitude); + double dlat = latlong_to_radians(nodex1->latitude) - latlong_to_radians(nodex2->latitude); + double lat1 = latlong_to_radians(nodex1->latitude); + double lat2 = latlong_to_radians(nodex2->latitude); + + double a1,a2,a,sa,c,d; + + if(dlon==0 && dlat==0) + return 0; + + a1 = sin (dlat / 2); + a2 = sin (dlon / 2); + a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2; + sa = sqrt (a); + if (sa <= 1.0) + {c = 2 * asin (sa);} + else + {c = 2 * asin (1.0);} + d = 6378.137 * c; + + return km_to_distance(d); +} diff --git a/src/segmentsx.h b/src/segmentsx.h new file mode 100644 index 0000000..ac19a77 --- /dev/null +++ b/src/segmentsx.h @@ -0,0 +1,100 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/segmentsx.h,v 1.20 2010/03/19 19:47:09 amb Exp $ + + A header file for the extended segments. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef SEGMENTSX_H +#define SEGMENTSX_H /*+ To stop multiple inclusions. +*/ + +#include + +#include "typesx.h" +#include "types.h" + + +/* Data structures */ + + +/*+ An extended structure used for processing. +*/ +struct _SegmentX +{ + node_t node1; /*+ The id of the starting node. +*/ + node_t node2; /*+ The id of the finishing node. +*/ + + way_t way; /*+ The id of the way. +*/ + + distance_t distance; /*+ The distance between the nodes. +*/ +}; + + +/*+ A structure containing a set of segments (memory format). +*/ +struct _SegmentsX +{ + char *filename; /*+ The name of the temporary file. +*/ + int fd; /*+ The file descriptor of the temporary file. +*/ + + uint32_t xnumber; /*+ The number of unsorted extended nodes. +*/ + + SegmentX *xdata; /*+ The extended segment data (unsorted). +*/ + SegmentX cached[2]; /*+ Two cached segments read from the file in slim mode. +*/ + + uint32_t number; /*+ How many entries are still useful? +*/ + + node_t *idata; /*+ The extended segment data (sorted by node1 then node2). +*/ + index_t *firstnode; /*+ The first segment index for each node. +*/ + + Segment *sdata; /*+ The segment data (same order as n1data). +*/ +}; + + +/* Functions */ + + +SegmentsX *NewSegmentList(int append); +void FreeSegmentList(SegmentsX *segmentsx,int keep); + +void SaveSegmentList(SegmentsX *segmentsx,const char *filename); + +SegmentX *LookupSegmentX(SegmentsX* segmentsx,index_t index,int position); + +index_t IndexFirstSegmentX(SegmentsX* segmentsx,node_t node); + +index_t IndexNextSegmentX(SegmentsX* segmentsx,index_t segindex,index_t nodeindex); + +void AppendSegment(SegmentsX* segmentsx,way_t way,node_t node1,node_t node2,distance_t distance); + +void SortSegmentList(SegmentsX* segmentsx); + +void RemoveBadSegments(NodesX *nodesx,SegmentsX *segmentsx); + +void UpdateSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx); + +void RotateSegments(SegmentsX* segmentsx); + +void DeduplicateSegments(SegmentsX* segmentsx,NodesX *nodesx,WaysX *waysx); + +void CreateRealSegments(SegmentsX *segmentsx,WaysX *waysx); + +void IndexSegments(SegmentsX* segmentsx,NodesX *nodesx); + + +#endif /* SEGMENTSX_H */ diff --git a/src/sorting.c b/src/sorting.c new file mode 100644 index 0000000..54bfdf0 --- /dev/null +++ b/src/sorting.c @@ -0,0 +1,650 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/sorting.c,v 1.8 2010/04/09 15:15:02 amb Exp $ + + Merge sort functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2009 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include + +#include "functions.h" + + +/* Variables */ + +/*+ The command line '--tmpdir' option or its default value. +*/ +extern char *option_tmpdirname; + +/*+ The amount of RAM to use for filesorting. +*/ +extern size_t option_filesort_ramsize; + + +/*++++++++++++++++++++++++++++++++++++++ + A function to sort the contents of a file of fixed length objects using a + limited amount of RAM. + + The data is sorted using a "Merge sort" http://en.wikipedia.org/wiki/Merge_sort + and in particular an "external sort" http://en.wikipedia.org/wiki/External_sorting. + The individual sort steps and the merge step both use a "Heap sort" + http://en.wikipedia.org/wiki/Heapsort. The combination of the two should work well + if the data is already partially sorted. + + int fd_in The file descriptor of the input file (opened for reading and at the beginning). + + int fd_out The file descriptor of the output file (opened for writing and empty). + + size_t itemsize The size of each item in the file that needs sorting. + + int (*compare)(const void*, const void*) The comparison function (identical to qsort if the + data to be sorted is an array of things not pointers). + + int (*buildindex)(void *,index_t) If non-NULL then this function is called for each item, if it + returns 1 then it is written to the output file. + ++++++++++++++++++++++++++++++++++++++*/ + +void filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const void*,const void*),int (*buildindex)(void*,index_t)) +{ + int *fds=NULL,*heap=NULL; + int nfiles=0,ndata=0; + index_t count=0,total=0; + size_t nitems=option_filesort_ramsize/(itemsize+sizeof(void*)); + void *data=NULL,**datap=NULL; + char *filename; + int i,more=1; + + /* Allocate the RAM buffer and other bits */ + + data=malloc(nitems*itemsize); + datap=malloc(nitems*sizeof(void*)); + + filename=(char*)malloc(strlen(option_tmpdirname)+24); + + /* Loop around, fill the buffer, sort the data and write a temporary file */ + + do + { + int fd,n=0; + + /* Read in the data and create pointers */ + + for(i=0;i0 && + compare(datap[heap[index]],datap[heap[(index-1)/2]])<0) + { + int newindex; + int temp; + + newindex=(index-1)/2; + + temp=heap[index]; + heap[index]=heap[newindex]; + heap[newindex]=temp; + + index=newindex; + } + } + + /* Repeatedly pull out the root of the heap and refill from the same file */ + + ndata=nfiles; + + do + { + int index=0; + + if(!buildindex || buildindex(datap[heap[0]],count)) + { + WriteFile(fd_out,datap[heap[0]],itemsize); + count++; + } + + if(ReadFile(fds[heap[0]],datap[heap[0]],itemsize)) + { + ndata--; + heap[0]=heap[ndata]; + } + + /* Bubble down the new value */ + + while((2*index+2)0 || + compare(datap[heap[index]],datap[heap[2*index+2]])>0)) + { + int newindex; + int temp; + + if(compare(datap[heap[2*index+1]],datap[heap[2*index+2]])<0) + newindex=2*index+1; + else + newindex=2*index+2; + + temp=heap[newindex]; + heap[newindex]=heap[index]; + heap[index]=temp; + + index=newindex; + } + + if((2*index+2)==ndata && + compare(datap[heap[index]],datap[heap[2*index+1]])>0) + { + int newindex; + int temp; + + newindex=2*index+1; + + temp=heap[newindex]; + heap[newindex]=heap[index]; + heap[index]=temp; + } + } + while(ndata>0); + + /* Tidy up */ + + tidy_and_exit: + + if(fds) + { + for(i=0;ilargestitemsize) + largestitemsize=itemsize; + + *(FILESORT_VARINT*)(data+ramused)=itemsize; + + ramused+=FILESORT_VARSIZE; + + ReadFile(fd_in,data+ramused,itemsize); + + *--datap=data+ramused; /* points to real data */ + + ramused+=itemsize; + + ramused =FILESORT_VARALIGN*((ramused+FILESORT_VARSIZE-1)/FILESORT_VARALIGN); + ramused+=FILESORT_VARALIGN-FILESORT_VARSIZE; + + total++; + n++; + + if(ReadFile(fd_in,&nextitemsize,FILESORT_VARSIZE)) + { + more=0; + break; + } + } + + if(n==0) + break; + + /* Sort the data pointers using a heap sort */ + + heapsort(datap,n,compare); + + /* Shortcut if all read in and sorted at once */ + + if(nfiles==0 && !more) + { + for(i=0;i0 && + compare(datap[heap[index]],datap[heap[(index-1)/2]])<0) + { + int newindex; + int temp; + + newindex=(index-1)/2; + + temp=heap[index]; + heap[index]=heap[newindex]; + heap[newindex]=temp; + + index=newindex; + } + } + + /* Repeatedly pull out the root of the heap and refill from the same file */ + + ndata=nfiles; + + do + { + int index=0; + FILESORT_VARINT itemsize; + + if(!buildindex || buildindex(datap[heap[0]],count)) + { + itemsize=*(FILESORT_VARINT*)(datap[heap[0]]-FILESORT_VARSIZE); + + WriteFile(fd_out,datap[heap[0]]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE); + count++; + } + + if(ReadFile(fds[heap[0]],&itemsize,FILESORT_VARSIZE)) + { + ndata--; + heap[0]=heap[ndata]; + } + else + { + *(FILESORT_VARINT*)(datap[heap[0]]-FILESORT_VARSIZE)=itemsize; + + ReadFile(fds[heap[0]],datap[heap[0]],itemsize); + } + + /* Bubble down the new value */ + + while((2*index+2)0 || + compare(datap[heap[index]],datap[heap[2*index+2]])>0)) + { + int newindex; + int temp; + + if(compare(datap[heap[2*index+1]],datap[heap[2*index+2]])<0) + newindex=2*index+1; + else + newindex=2*index+2; + + temp=heap[newindex]; + heap[newindex]=heap[index]; + heap[index]=temp; + + index=newindex; + } + + if((2*index+2)==ndata && + compare(datap[heap[index]],datap[heap[2*index+1]])>0) + { + int newindex; + int temp; + + newindex=2*index+1; + + temp=heap[newindex]; + heap[newindex]=heap[index]; + heap[index]=temp; + } + } + while(ndata>0); + + /* Tidy up */ + + tidy_and_exit: + + if(fds) + { + for(i=0;i0 && + compare(datap[index],datap[(index-1)/2])>0) /* reversed compared to filesort() above */ + { + int newindex; + void *temp; + + newindex=(index-1)/2; + + temp=datap[index]; + datap[index]=datap[newindex]; + datap[newindex]=temp; + + index=newindex; + } + } + + /* Repeatedly pull out the root of the heap and swap with the bottom item */ + + for(i=nitems-1;i>0;i--) + { + int index=0; + void *temp; + + temp=datap[index]; + datap[index]=datap[i]; + datap[i]=temp; + + /* Bubble down the new value (upside-down, put largest at top) */ + + while((2*index+2)0) /* reversed compared to filesort() above */ + newindex=2*index+1; + else + newindex=2*index+2; + + temp=datap[newindex]; + datap[newindex]=datap[index]; + datap[index]=temp; + + index=newindex; + } + + if((2*index+2)==i && + compare(datap[index],datap[2*index+1])<0) /* reversed compared to filesort() above */ + { + int newindex; + void *temp; + + newindex=2*index+1; + + temp=datap[newindex]; + datap[newindex]=datap[index]; + datap[index]=temp; + } + } +} diff --git a/src/superx.c b/src/superx.c new file mode 100644 index 0000000..45b8227 --- /dev/null +++ b/src/superx.c @@ -0,0 +1,480 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/superx.c,v 1.38 2010/07/05 19:05:51 amb Exp $ + + Super-Segment data type functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include + +#include "results.h" +#include "functions.h" +#include "nodesx.h" +#include "segmentsx.h" +#include "waysx.h" +#include "superx.h" +#include "ways.h" + + +/* Variables */ + +/*+ The command line '--slim' option. +*/ +extern int option_slim; + +/* Local Functions */ + +static Results *FindRoutesWay(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match,int iteration); + + +/*++++++++++++++++++++++++++++++++++++++ + Select the super-segments from the list of segments. + + NodesX *nodesx The nodes. + + SegmentsX *segmentsx The segments. + + WaysX *waysx The ways. + ++++++++++++++++++++++++++++++++++++++*/ + +void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx) +{ + index_t i; + int nnodes=0; + + /* Check the start conditions */ + + assert(segmentsx->firstnode); /* Must have firstnode filled in => segments are updated */ + + /* Print the start message */ + + printf("Finding Super-Nodes: Nodes=0 Super-Nodes=0"); + fflush(stdout); + + /* Map into memory */ + + if(!option_slim) + { + segmentsx->xdata=MapFile(segmentsx->filename); + waysx->xdata=MapFile(waysx->filename); + } + + /* Find super-nodes */ + + for(i=0;inumber;i++) + { + int difference=0; + index_t index1,index2; + + index1=IndexFirstSegmentX(segmentsx,i); + + while(index1!=NO_SEGMENT) + { + SegmentX *segmentx1=LookupSegmentX(segmentsx,index1,1); + WayX *wayx1=LookupWayX(waysx,segmentx1->way,1); + + index1=IndexNextSegmentX(segmentsx,index1,i); + index2=index1; + + while(index2!=NO_SEGMENT) + { + SegmentX *segmentx2=LookupSegmentX(segmentsx,index2,2); + WayX *wayx2=LookupWayX(waysx,segmentx2->way,2); + + /* If the ways are different in any way and there is a type of traffic that can use both ... */ + + if(WaysCompare(&wayx1->way,&wayx2->way)) + if(wayx1->way.allow & wayx2->way.allow) + { + difference=1; + break; + } + + index2=IndexNextSegmentX(segmentsx,index2,i); + } + + if(difference) + break; + } + + /* Store the node if there is a difference in the connected ways that could affect routing. */ + + if(difference) + { + nodesx->super[i]++; + + nnodes++; + } + + if(!((i+1)%10000)) + { + printf("\rFinding Super-Nodes: Nodes=%d Super-Nodes=%d",i+1,nnodes); + fflush(stdout); + } + } + + /* Unmap from memory */ + + if(!option_slim) + { + segmentsx->xdata=UnmapFile(segmentsx->filename); + waysx->xdata=UnmapFile(waysx->filename); + } + + /* Print the final message */ + + printf("\rFound Super-Nodes: Nodes=%d Super-Nodes=%d \n",nodesx->number,nnodes); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Create the super-segments. + + SegmentsX *CreateSuperSegments Creates the super segments. + + NodesX *nodesx The nodes. + + SegmentsX *segmentsx The segments. + + WaysX *waysx The ways. + + int iteration The current super-node / super-segment iteration number. + ++++++++++++++++++++++++++++++++++++++*/ + +SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,int iteration) +{ + index_t i; + SegmentsX *supersegmentsx; + int sn=0,ss=0; + + /* Check the start conditions */ + + assert(segmentsx->firstnode); /* Must have firstnode filled in => segments are updated */ + + /* Print the start message */ + + printf("Creating Super-Segments: Super-Nodes=0 Super-Segments=0"); + fflush(stdout); + + /* Map into memory */ + + if(!option_slim) + { + segmentsx->xdata=MapFile(segmentsx->filename); + waysx->xdata=MapFile(waysx->filename); + } + + /* Create super-segments for each super-node. */ + + supersegmentsx=NewSegmentList(0); + + for(i=0;inumber;i++) + { + if(nodesx->super[i]>iteration) + { + index_t index,first; + + index=first=IndexFirstSegmentX(segmentsx,i); + + while(index!=NO_SEGMENT) + { + SegmentX *segmentx=LookupSegmentX(segmentsx,index,1); + WayX *wayx=LookupWayX(waysx,segmentx->way,1); + + /* Check that this type of way hasn't already been routed */ + + if(index!=first) + { + index_t otherindex=first; + + while(otherindex!=NO_SEGMENT && otherindex!=index) + { + SegmentX *othersegmentx=LookupSegmentX(segmentsx,otherindex,2); + WayX *otherwayx=LookupWayX(waysx,othersegmentx->way,2); + + if(!WaysCompare(&otherwayx->way,&wayx->way)) + { + wayx=NULL; + break; + } + + otherindex=IndexNextSegmentX(segmentsx,otherindex,i); + } + } + + /* Route the way and store the super-segments. */ + + if(wayx) + { + Results *results=FindRoutesWay(nodesx,segmentsx,waysx,i,&wayx->way,iteration); + Result *result=FirstResult(results); + + while(result) + { + if(result->node!=i && nodesx->super[result->node]>iteration) + { + if(wayx->way.type&Way_OneWay) + { + AppendSegment(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score)|ONEWAY_1TO2); + AppendSegment(supersegmentsx,segmentx->way,result->node,i,DISTANCE((distance_t)result->score)|ONEWAY_2TO1); + } + else + AppendSegment(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score)); + + ss++; + } + + result=NextResult(results,result); + } + + FreeResultsList(results); + } + + index=IndexNextSegmentX(segmentsx,index,i); + } + + sn++; + + if(!(sn%10000)) + { + printf("\rCreating Super-Segments: Super-Nodes=%d Super-Segments=%d",sn,ss); + fflush(stdout); + } + } + } + + /* Unmap from memory */ + + if(!option_slim) + { + segmentsx->xdata=UnmapFile(segmentsx->filename); + waysx->xdata=UnmapFile(waysx->filename); + } + + /* Print the final message */ + + printf("\rCreated Super-Segments: Super-Nodes=%d Super-Segments=%d \n",sn,ss); + fflush(stdout); + + return(supersegmentsx); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Merge the segments and super-segments into a new segment list. + + SegmentsX* MergeSuperSegments Returns a new set of merged segments. + + SegmentsX* segmentsx The set of segments to process. + + SegmentsX* supersegmentsx The set of super-segments to merge. + ++++++++++++++++++++++++++++++++++++++*/ + +SegmentsX *MergeSuperSegments(SegmentsX* segmentsx,SegmentsX* supersegmentsx) +{ + index_t i,j; + int m=0,a=0; + SegmentsX* mergedsegmentsx; + + /* Print the start message */ + + printf("Merging: Segments=0 Super-Segments=0 Merged=0 Added=0"); + fflush(stdout); + + /* Map into memory */ + + if(!option_slim) + { + segmentsx->xdata=MapFile(segmentsx->filename); + supersegmentsx->xdata=MapFile(supersegmentsx->filename); + } + + /* Loop through and create a new list of combined segments */ + + mergedsegmentsx=NewSegmentList(0); + + for(i=0,j=0;inumber;i++) + { + int super=0; + SegmentX *segmentx=LookupSegmentX(segmentsx,i,1); + + while(jnumber) + { + SegmentX *supersegmentx=LookupSegmentX(supersegmentsx,j,1); + + if(segmentx->node1 ==supersegmentx->node1 && + segmentx->node2 ==supersegmentx->node2 && + segmentx->distance==supersegmentx->distance) + { + m++; + j++; + /* mark as super-segment and normal segment */ + super=1; + break; + } + else if((segmentx->node1==supersegmentx->node1 && + segmentx->node2==supersegmentx->node2) || + (segmentx->node1==supersegmentx->node1 && + segmentx->node2>supersegmentx->node2) || + (segmentx->node1>supersegmentx->node1)) + { + /* mark as super-segment */ + AppendSegment(mergedsegmentsx,supersegmentx->way,supersegmentx->node1,supersegmentx->node2,supersegmentx->distance|SEGMENT_SUPER); + a++; + j++; + } + else + { + /* mark as normal segment */ + break; + } + } + + if(super) + AppendSegment(mergedsegmentsx,segmentx->way,segmentx->node1,segmentx->node2,segmentx->distance|SEGMENT_SUPER|SEGMENT_NORMAL); + else + AppendSegment(mergedsegmentsx,segmentx->way,segmentx->node1,segmentx->node2,segmentx->distance|SEGMENT_NORMAL); + + if(!((i+1)%10000)) + { + printf("\rMerging: Segments=%d Super-Segments=%d Merged=%d Added=%d",i+1,j,m,a); + fflush(stdout); + } + } + + /* Unmap from memory */ + + if(!option_slim) + { + segmentsx->xdata=UnmapFile(segmentsx->filename); + supersegmentsx->xdata=UnmapFile(supersegmentsx->filename); + } + + /* Print the final message */ + + printf("\rMerged: Segments=%d Super-Segments=%d Merged=%d Added=%d \n",segmentsx->number,supersegmentsx->number,m,a); + fflush(stdout); + + return(mergedsegmentsx); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find all routes from a specified node to any node in the specified list that follows a certain type of way. + + Results *FindRoutesWay Returns a set of results. + + NodesX *nodesx The set of nodes to use. + + SegmentsX *segmentsx The set of segments to use. + + WaysX *waysx The set of ways to use. + + node_t start The start node. + + Way *match The way that the route must match. + + int iteration The current super-node / super-segment iteration number. + ++++++++++++++++++++++++++++++++++++++*/ + +static Results *FindRoutesWay(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match,int iteration) +{ + Results *results; + Queue *queue; + index_t node1,node2; + Result *result1,*result2; + index_t index; + WayX *wayx; + + /* Insert the first node into the queue */ + + results=NewResultsList(8); + + queue=NewQueueList(); + + result1=InsertResult(results,start); + + ZeroResult(result1); + + InsertInQueue(queue,result1); + + /* Loop across all nodes in the queue */ + + while((result1=PopFromQueue(queue))) + { + node1=result1->node; + + index=IndexFirstSegmentX(segmentsx,node1); + + while(index!=NO_SEGMENT) + { + SegmentX *segmentx=LookupSegmentX(segmentsx,index,2); /* must use 2 here */ + distance_t cumulative_distance; + + if(segmentx->distance&ONEWAY_2TO1) + goto endloop; + + node2=segmentx->node2; + + if(result1->prev==node2) + goto endloop; + + wayx=LookupWayX(waysx,segmentx->way,2); + + if(WaysCompare(&wayx->way,match)) + goto endloop; + + cumulative_distance=(distance_t)result1->score+DISTANCE(segmentx->distance); + + result2=FindResult(results,node2); + + if(!result2) /* New end node */ + { + result2=InsertResult(results,node2); + result2->prev=node1; + result2->next=NO_NODE; + result2->score=cumulative_distance; + result2->sortby=cumulative_distance; + + if(nodesx->super[node2]<=iteration) + InsertInQueue(queue,result2); + } + else if(cumulative_distancescore) + { + result2->prev=node1; + result2->score=cumulative_distance; + result2->sortby=cumulative_distance; + + if(nodesx->super[node2]<=iteration) + InsertInQueue(queue,result2); + } + + endloop: + + index=IndexNextSegmentX(segmentsx,index,node1); + } + } + + FreeQueueList(queue); + + return(results); +} diff --git a/src/superx.h b/src/superx.h new file mode 100644 index 0000000..cb330df --- /dev/null +++ b/src/superx.h @@ -0,0 +1,38 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/superx.h,v 1.7 2009/09/06 15:51:09 amb Exp $ + + Header for super-node and super-segment functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008,2009 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef SUPERX_H +#define SUPERX_H /*+ To stop multiple inclusions. +*/ + +#include "typesx.h" + + +void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx); + +SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,int iteration); + +SegmentsX* MergeSuperSegments(SegmentsX* segmentsx,SegmentsX* supersegmentsx); + + +#endif /* SUPERX_H */ diff --git a/src/tagging.c b/src/tagging.c new file mode 100644 index 0000000..814580f --- /dev/null +++ b/src/tagging.c @@ -0,0 +1,574 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/tagging.c,v 1.2 2010/05/23 10:18:59 amb Exp $ + + Load the tagging rules from a file and the functions for handling them. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include + +#include "functions.h" +#include "tagging.h" +#include "xmlparse.h" + + +/* Global variables */ + +TaggingRuleList NodeRules={NULL,0}; +TaggingRuleList WayRules={NULL,0}; +TaggingRuleList RelationRules={NULL,0}; + + +/* Local variables */ + +TaggingRuleList *current_list=NULL; +TaggingRule *current_rule=NULL; + + +/* Local functions */ + +static void apply_actions(TaggingRule *rule,int match,TagList *input,TagList *output); + + +/* The XML tag processing function prototypes */ + +//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding); +//static int RoutinoTaggingType_function(const char *_tag_,int _type_); +static int WayType_function(const char *_tag_,int _type_); +static int IfType_function(const char *_tag_,int _type_,const char *k,const char *v); +static int RelationType_function(const char *_tag_,int _type_); +static int OutputType_function(const char *_tag_,int _type_,const char *k,const char *v); +static int SetType_function(const char *_tag_,int _type_,const char *k,const char *v); +static int NodeType_function(const char *_tag_,int _type_); + + +/* The XML tag definitions */ + +/*+ The NodeType type tag. +*/ +static xmltag NodeType_tag= + {"node", + 0, {NULL}, + NodeType_function, + {NULL}}; + +/*+ The SetType type tag. +*/ +static xmltag SetType_tag= + {"set", + 2, {"k","v"}, + SetType_function, + {NULL}}; + +/*+ The OutputType type tag. +*/ +static xmltag OutputType_tag= + {"output", + 2, {"k","v"}, + OutputType_function, + {NULL}}; + +/*+ The RelationType type tag. +*/ +static xmltag RelationType_tag= + {"relation", + 0, {NULL}, + RelationType_function, + {NULL}}; + +/*+ The IfType type tag. +*/ +static xmltag IfType_tag= + {"if", + 2, {"k","v"}, + IfType_function, + {&SetType_tag,&OutputType_tag,NULL}}; + +/*+ The WayType type tag. +*/ +static xmltag WayType_tag= + {"way", + 0, {NULL}, + WayType_function, + {&IfType_tag,NULL}}; + +/*+ The RoutinoTaggingType type tag. +*/ +static xmltag RoutinoTaggingType_tag= + {"routino-tagging", + 0, {NULL}, + NULL, + {&NodeType_tag,&WayType_tag,&RelationType_tag,NULL}}; + +/*+ The xmlDeclaration type tag. +*/ +static xmltag xmlDeclaration_tag= + {"xml", + 2, {"version","encoding"}, + NULL, + {NULL}}; + + +/*+ The complete set of tags at the top level. +*/ +static xmltag *xml_toplevel_tags[]={&xmlDeclaration_tag,&RoutinoTaggingType_tag,NULL}; + + +/* The XML tag processing functions */ + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the NodeType XSD type is seen + + int NodeType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +static int NodeType_function(const char *_tag_,int _type_) +{ + if(_type_&XMLPARSE_TAG_START) + current_list=&NodeRules; + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the SetType XSD type is seen + + int SetType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *k The contents of the 'k' attribute (or NULL if not defined). + + const char *v The contents of the 'v' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int SetType_function(const char *_tag_,int _type_,const char *k,const char *v) +{ + if(_type_&XMLPARSE_TAG_START) + AppendTaggingAction(current_rule,k,v,0); + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the OutputType XSD type is seen + + int OutputType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *k The contents of the 'k' attribute (or NULL if not defined). + + const char *v The contents of the 'v' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int OutputType_function(const char *_tag_,int _type_,const char *k,const char *v) +{ + if(_type_&XMLPARSE_TAG_START) + AppendTaggingAction(current_rule,k,v,1); + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the RelationType XSD type is seen + + int RelationType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +static int RelationType_function(const char *_tag_,int _type_) +{ + if(_type_&XMLPARSE_TAG_START) + current_list=&RelationRules; + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the IfType XSD type is seen + + int IfType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *k The contents of the 'k' attribute (or NULL if not defined). + + const char *v The contents of the 'v' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int IfType_function(const char *_tag_,int _type_,const char *k,const char *v) +{ + if(_type_&XMLPARSE_TAG_START) + { + current_rule=AppendTaggingRule(current_list,k,v); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the WayType XSD type is seen + + int WayType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +static int WayType_function(const char *_tag_,int _type_) +{ + if(_type_&XMLPARSE_TAG_START) + current_list=&WayRules; + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the RoutinoTaggingType XSD type is seen + + int RoutinoTaggingType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int RoutinoTaggingType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the XML declaration is seen + + int xmlDeclaration_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *version The contents of the 'version' attribute (or NULL if not defined). + + const char *encoding The contents of the 'encoding' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The XML tagging rules parser. + + int ParseXMLTaggingRules Returns 0 if OK or something else in case of an error. + + const char *filename The name of the file to read. + ++++++++++++++++++++++++++++++++++++++*/ + +int ParseXMLTaggingRules(const char *filename) +{ + int retval; + + if(!ExistsFile(filename)) + { + fprintf(stderr,"Error: Specified tagging rules file '%s' does not exist.\n",filename); + return(1); + } + + FILE *file=fopen(filename,"r"); + + if(!file) + { + fprintf(stderr,"Error: Cannot open tagging rules file '%s' for reading.\n",filename); + return(1); + } + + retval=ParseXML(file,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_ERRNONAME); + + fclose(file); + + if(retval) + return(1); + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Append a tagging rule to the list of rules. + + TaggingRule *AppendTaggingRule Returns the latest rule (the just added one). + + TaggingRuleList *rules The list of rules to add to. + + const char *k The tag key. + + const char *v The tag value. + ++++++++++++++++++++++++++++++++++++++*/ + +TaggingRule *AppendTaggingRule(TaggingRuleList *rules,const char *k,const char *v) +{ + if((rules->nrules%16)==0) + rules->rules=(TaggingRule*)realloc((void*)rules->rules,(rules->nrules+16)*sizeof(TaggingRule)); + + rules->nrules++; + + if(k) + rules->rules[rules->nrules-1].k=strcpy(malloc(strlen(k)+1),k); + else + rules->rules[rules->nrules-1].k=NULL; + + if(v) + rules->rules[rules->nrules-1].v=strcpy(malloc(strlen(v)+1),v); + else + rules->rules[rules->nrules-1].v=NULL; + + rules->rules[rules->nrules-1].nactions=0; + rules->rules[rules->nrules-1].actions=NULL; + + return(&rules->rules[rules->nrules-1]); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Append a tagging action to a tagging rule. + + TaggingRule *rule The rule to add the action to. + + const char *k The tag key. + + const char *v The tag value. + + int output Set to 1 if this is an output rule. + ++++++++++++++++++++++++++++++++++++++*/ + +void AppendTaggingAction(TaggingRule *rule,const char *k,const char *v,int output) +{ + if((rule->nactions%16)==0) + rule->actions=(TaggingAction*)realloc((void*)rule->actions,(rule->nactions+16)*sizeof(TaggingAction)); + + rule->nactions++; + + rule->actions[rule->nactions-1].output=output; + + if(k) + rule->actions[rule->nactions-1].k=strcpy(malloc(strlen(k)+1),k); + else + rule->actions[rule->nactions-1].k=NULL; + + if(v) + rule->actions[rule->nactions-1].v=strcpy(malloc(strlen(v)+1),v); + else + rule->actions[rule->nactions-1].v=NULL; +} + + +/*++++++++++++++++++++++++++++++++++++++ + Create a new TagList structure. + + TagList *NewTagList Returns the new allocated TagList. + ++++++++++++++++++++++++++++++++++++++*/ + +TagList *NewTagList(void) +{ + return((TagList*)calloc(sizeof(TagList),1)); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Append a tag to the list of tags. + + TagList *tags The list of tags to add to. + + const char *k The tag key. + + const char *v The tag value. + ++++++++++++++++++++++++++++++++++++++*/ + +void AppendTag(TagList *tags,const char *k,const char *v) +{ + if((tags->ntags%16)==0) + { + int i; + + tags->k=(char**)realloc((void*)tags->k,(tags->ntags+16)*sizeof(char*)); + tags->v=(char**)realloc((void*)tags->v,(tags->ntags+16)*sizeof(char*)); + + for(i=tags->ntags;i<(tags->ntags+16);i++) + tags->k[i]=tags->v[i]=NULL; + } + + tags->k[tags->ntags]=strcpy(realloc(tags->k[tags->ntags],strlen(k)+1),k); + tags->v[tags->ntags]=strcpy(realloc(tags->v[tags->ntags],strlen(v)+1),v); + + tags->ntags++; +} + + +/*++++++++++++++++++++++++++++++++++++++ + Modify an existing tag or append a new tag to the list of tags. + + TagList *tags The list of tags to modify. + + const char *k The tag key. + + const char *v The tag value. + ++++++++++++++++++++++++++++++++++++++*/ + +void ModifyTag(TagList *tags,const char *k,const char *v) +{ + int i; + + for(i=0;intags;i++) + if(!strcmp(tags->k[i],k)) + { + tags->v[i]=strcpy(realloc(tags->v[i],strlen(v)+1),v); + return; + } + + AppendTag(tags,k,v); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Delete a tag list and the contents. + + TagList *tags The list of tags to delete. + ++++++++++++++++++++++++++++++++++++++*/ + +void DeleteTagList(TagList *tags) +{ + int i; + + for(i=0;intags;i++) + { + if(tags->k[i]) free(tags->k[i]); + if(tags->v[i]) free(tags->v[i]); + } + + if(tags->ntags) + { + free(tags->k); + free(tags->v); + } + + free(tags); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Apply a set of tagging rules to a set of tags. + + TagList *ApplyTaggingRules Returns the list of output tags after modification. + + TaggingRuleList *rules The tagging rules to apply. + + TagList *tags The tags to be modified. + ++++++++++++++++++++++++++++++++++++++*/ + +TagList *ApplyTaggingRules(TaggingRuleList *rules,TagList *tags) +{ + TagList *result=NewTagList(); + int i,j; + + for(i=0;inrules;i++) + { + if(rules->rules[i].k && rules->rules[i].v) + { + for(j=0;jntags;j++) + if(!strcmp(tags->k[j],rules->rules[i].k) && !strcmp(tags->v[j],rules->rules[i].v)) + apply_actions(&rules->rules[i],j,tags,result); + } + else if(rules->rules[i].k && !rules->rules[i].v) + { + for(j=0;jntags;j++) + if(!strcmp(tags->k[j],rules->rules[i].k)) + apply_actions(&rules->rules[i],j,tags,result); + } + else if(!rules->rules[i].k && rules->rules[i].v) + { + for(j=0;jntags;j++) + if(!strcmp(tags->v[j],rules->rules[i].v)) + apply_actions(&rules->rules[i],j,tags,result); + } + else /* if(!rules->rules[i].k && !rules->rules[i].v) */ + { + for(j=0;jntags;j++) + apply_actions(&rules->rules[i],j,tags,result); + } + } + + return(result); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Apply a set of actions to a matching tag. + + TaggingRule *rule The rule that matched (containing the actions). + + int match The matching tag number. + + TagList *input The input tags. + + TagList *output The output tags. + ++++++++++++++++++++++++++++++++++++++*/ + +static void apply_actions(TaggingRule *rule,int match,TagList *input,TagList *output) +{ + int i; + + for(i=0;inactions;i++) + { + char *k,*v; + + if(rule->actions[i].k) + k=rule->actions[i].k; + else + k=input->k[match]; + + if(rule->actions[i].v) + v=rule->actions[i].v; + else + v=input->v[match]; + + if(rule->actions[i].output) + ModifyTag(output,k,v); + else + ModifyTag(input,k,v); + } +} diff --git a/src/tagging.h b/src/tagging.h new file mode 100644 index 0000000..4dfdbb8 --- /dev/null +++ b/src/tagging.h @@ -0,0 +1,95 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/tagging.h,v 1.2 2010/05/23 10:18:59 amb Exp $ + + The data types for the tagging rules. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + +#ifndef TAGGING_H +#define TAGGING_H /*+ To stop multiple inclusions. +*/ + + +/* Data types */ + +/*+ A structure to contain the tagging action. +*/ +typedef struct _TaggingAction +{ + int output; /*+ A flag to indicate if the output tags or input tags are to be changed. +*/ + + char *k; /*+ The tag key (or NULL). +*/ + char *v; /*+ The tag value (or NULL). +*/ +} + TaggingAction; + + +/*+ A structure to contain the tagging rule. +*/ +typedef struct _TaggingRule +{ + char *k; /*+ The tag key (or NULL). +*/ + char *v; /*+ The tag value (or NULL). +*/ + + TaggingAction *actions; /*+ The actions to take. +*/ + int nactions; /*+ The number of actions. +*/ +} + TaggingRule; + + +/*+ A structure to contain the list of rules and associated information. +*/ +typedef struct _TaggingRuleList +{ + TaggingRule *rules; /*+ The array of rules. +*/ + int nrules; /*+ The number of rules. +*/ +} + TaggingRuleList; + + +/*+ A structure to hold a list of tags to be processed. +*/ +typedef struct _TagList +{ + int ntags; /*+ The number of tags. +*/ + + char **k; /*+ The list of tag keys. +*/ + char **v; /*+ The list of tag values. +*/ +} + TagList; + + +/* Variables */ + +extern TaggingRuleList NodeRules; +extern TaggingRuleList WayRules; +extern TaggingRuleList RelationRules; + + +/* Functions */ + +int ParseXMLTaggingRules(const char *filename); + +TaggingRule *AppendTaggingRule(TaggingRuleList *rules,const char *k,const char *v); +void AppendTaggingAction(TaggingRule *rule,const char *k,const char *v,int output); + +TagList *NewTagList(void); +void AppendTag(TagList *tags,const char *k,const char *v); +void ModifyTag(TagList *tags,const char *k,const char *v); +void DeleteTagList(TagList *tags); + +TagList *ApplyTaggingRules(TaggingRuleList *rules,TagList *tags); + + +#endif /* TAGGING_H */ diff --git a/src/tagmodifier.c b/src/tagmodifier.c new file mode 100644 index 0000000..06bcc87 --- /dev/null +++ b/src/tagmodifier.c @@ -0,0 +1,626 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/tagmodifier.c,v 1.5 2010/05/30 18:18:54 amb Exp $ + + Test application for OSM XML file parser / tagging rule testing. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include +#include + +#include "functions.h" +#include "xmlparse.h" +#include "tagging.h" + + +/* Local variables */ + +static long nnodes=0,nways=0,nrelations=0; +TagList *current_tags=NULL; + + +/* Local functions */ + +static void print_usage(int detail); + + +/* The XML tag processing function prototypes */ + +static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding); +static int osmType_function(const char *_tag_,int _type_,const char *version,const char *generator); +static int relationType_function(const char *_tag_,int _type_,const char *id,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action); +static int wayType_function(const char *_tag_,int _type_,const char *id,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action); +static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role); +static int ndType_function(const char *_tag_,int _type_,const char *ref); +static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action); +static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v); +static int boundType_function(const char *_tag_,int _type_,const char *box,const char *origin); +static int boundsType_function(const char *_tag_,int _type_,const char *minlat,const char *minlon,const char *maxlat,const char *maxlon,const char *origin); + + +/* The XML tag definitions */ + +/*+ The boundsType type tag. +*/ +static xmltag boundsType_tag= + {"bounds", + 5, {"minlat","minlon","maxlat","maxlon","origin"}, + boundsType_function, + {NULL}}; + +/*+ The boundType type tag. +*/ +static xmltag boundType_tag= + {"bound", + 2, {"box","origin"}, + boundType_function, + {NULL}}; + +/*+ The tagType type tag. +*/ +static xmltag tagType_tag= + {"tag", + 2, {"k","v"}, + tagType_function, + {NULL}}; + +/*+ The nodeType type tag. +*/ +static xmltag nodeType_tag= + {"node", + 9, {"id","lat","lon","timestamp","uid","user","visible","version","action"}, + nodeType_function, + {&tagType_tag,NULL}}; + +/*+ The ndType type tag. +*/ +static xmltag ndType_tag= + {"nd", + 1, {"ref"}, + ndType_function, + {NULL}}; + +/*+ The memberType type tag. +*/ +static xmltag memberType_tag= + {"member", + 3, {"type","ref","role"}, + memberType_function, + {NULL}}; + +/*+ The wayType type tag. +*/ +static xmltag wayType_tag= + {"way", + 7, {"id","timestamp","uid","user","visible","version","action"}, + wayType_function, + {&ndType_tag,&tagType_tag,NULL}}; + +/*+ The relationType type tag. +*/ +static xmltag relationType_tag= + {"relation", + 7, {"id","timestamp","uid","user","visible","version","action"}, + relationType_function, + {&memberType_tag,&tagType_tag,NULL}}; + +/*+ The osmType type tag. +*/ +static xmltag osmType_tag= + {"osm", + 2, {"version","generator"}, + osmType_function, + {&boundsType_tag,&boundType_tag,&nodeType_tag,&wayType_tag,&relationType_tag,NULL}}; + +/*+ The xmlDeclaration type tag. +*/ +static xmltag xmlDeclaration_tag= + {"xml", + 2, {"version","encoding"}, + xmlDeclaration_function, + {NULL}}; + + +/*+ The complete set of tags at the top level. +*/ +static xmltag *xml_toplevel_tags[]={&xmlDeclaration_tag,&osmType_tag,NULL}; + + +/* The XML tag processing functions */ + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the boundsType XSD type is seen + + int boundsType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *minlat The contents of the 'minlat' attribute (or NULL if not defined). + + const char *minlon The contents of the 'minlon' attribute (or NULL if not defined). + + const char *maxlat The contents of the 'maxlat' attribute (or NULL if not defined). + + const char *maxlon The contents of the 'maxlon' attribute (or NULL if not defined). + + const char *origin The contents of the 'origin' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int boundsType_function(const char *_tag_,int _type_,const char *minlat,const char *minlon,const char *maxlat,const char *maxlon,const char *origin) +{ + printf(" <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_); + if(minlat) printf(" minlat=\"%s\"",ParseXML_Encode_Safe_XML(minlat)); + if(minlon) printf(" minlon=\"%s\"",ParseXML_Encode_Safe_XML(minlon)); + if(maxlat) printf(" maxlat=\"%s\"",ParseXML_Encode_Safe_XML(maxlat)); + if(maxlon) printf(" maxlon=\"%s\"",ParseXML_Encode_Safe_XML(maxlon)); + if(origin) printf(" origin=\"%s\"",ParseXML_Encode_Safe_XML(origin)); + printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":""); + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the boundType XSD type is seen + + int boundType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *box The contents of the 'box' attribute (or NULL if not defined). + + const char *origin The contents of the 'origin' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int boundType_function(const char *_tag_,int _type_,const char *box,const char *origin) +{ + printf(" <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_); + if(box) printf(" box=\"%s\"",ParseXML_Encode_Safe_XML(box)); + if(origin) printf(" origin=\"%s\"",ParseXML_Encode_Safe_XML(origin)); + printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":""); + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the tagType XSD type is seen + + int tagType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *k The contents of the 'k' attribute (or NULL if not defined). + + const char *v The contents of the 'v' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v) +{ + if(_type_&XMLPARSE_TAG_START) + { + XMLPARSE_ASSERT_STRING(_tag_,k); + XMLPARSE_ASSERT_STRING(_tag_,v); + + AppendTag(current_tags,k,v); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the nodeType XSD type is seen + + int nodeType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *id The contents of the 'id' attribute (or NULL if not defined). + + const char *lat The contents of the 'lat' attribute (or NULL if not defined). + + const char *lon The contents of the 'lon' attribute (or NULL if not defined). + + const char *timestamp The contents of the 'timestamp' attribute (or NULL if not defined). + + const char *uid The contents of the 'uid' attribute (or NULL if not defined). + + const char *user The contents of the 'user' attribute (or NULL if not defined). + + const char *visible The contents of the 'visible' attribute (or NULL if not defined). + + const char *version The contents of the 'version' attribute (or NULL if not defined). + + const char *action The contents of the 'action' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action) +{ + if(_type_&XMLPARSE_TAG_START) + { + nnodes++; + + if(!(nnodes%1000)) + fprintf(stderr,"\rReading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations); + + current_tags=NewTagList(); + } + + if(_type_&XMLPARSE_TAG_END) + { + TagList *result=ApplyTaggingRules(&NodeRules,current_tags); + int i; + + for(i=0;intags;i++) + { + printf(" k[i])); + printf(" v=\"%s\"",ParseXML_Encode_Safe_XML(result->v[i])); + printf(" />\n"); + } + + DeleteTagList(current_tags); + DeleteTagList(result); + } + + printf(" <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_); + if(id) printf(" id=\"%s\"",ParseXML_Encode_Safe_XML(id)); + if(lat) printf(" lat=\"%s\"",ParseXML_Encode_Safe_XML(lat)); + if(lon) printf(" lon=\"%s\"",ParseXML_Encode_Safe_XML(lon)); + if(timestamp) printf(" timestamp=\"%s\"",ParseXML_Encode_Safe_XML(timestamp)); + if(uid) printf(" uid=\"%s\"",ParseXML_Encode_Safe_XML(uid)); + if(user) printf(" user=\"%s\"",ParseXML_Encode_Safe_XML(user)); + if(visible) printf(" visible=\"%s\"",ParseXML_Encode_Safe_XML(visible)); + if(version) printf(" version=\"%s\"",ParseXML_Encode_Safe_XML(version)); + if(action) printf(" action=\"%s\"",ParseXML_Encode_Safe_XML(action)); + printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":""); + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the ndType XSD type is seen + + int ndType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *ref The contents of the 'ref' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int ndType_function(const char *_tag_,int _type_,const char *ref) +{ + printf(" <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_); + if(ref) printf(" ref=\"%s\"",ParseXML_Encode_Safe_XML(ref)); + printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":""); + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the memberType XSD type is seen + + int memberType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *type The contents of the 'type' attribute (or NULL if not defined). + + const char *ref The contents of the 'ref' attribute (or NULL if not defined). + + const char *role The contents of the 'role' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role) +{ + printf(" <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_); + if(type) printf(" type=\"%s\"",ParseXML_Encode_Safe_XML(type)); + if(ref) printf(" ref=\"%s\"",ParseXML_Encode_Safe_XML(ref)); + if(role) printf(" role=\"%s\"",ParseXML_Encode_Safe_XML(role)); + printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":""); + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the wayType XSD type is seen + + int wayType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *id The contents of the 'id' attribute (or NULL if not defined). + + const char *timestamp The contents of the 'timestamp' attribute (or NULL if not defined). + + const char *uid The contents of the 'uid' attribute (or NULL if not defined). + + const char *user The contents of the 'user' attribute (or NULL if not defined). + + const char *visible The contents of the 'visible' attribute (or NULL if not defined). + + const char *version The contents of the 'version' attribute (or NULL if not defined). + + const char *action The contents of the 'action' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int wayType_function(const char *_tag_,int _type_,const char *id,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action) +{ + if(_type_&XMLPARSE_TAG_START) + { + nways++; + + if(!(nways%1000)) + fprintf(stderr,"\rReading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations); + + current_tags=NewTagList(); + } + + if(_type_&XMLPARSE_TAG_END) + { + TagList *result=ApplyTaggingRules(&WayRules,current_tags); + int i; + + for(i=0;intags;i++) + { + printf(" k[i])); + printf(" v=\"%s\"",ParseXML_Encode_Safe_XML(result->v[i])); + printf(" />\n"); + } + + DeleteTagList(current_tags); + DeleteTagList(result); + } + + printf(" <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_); + if(id) printf(" id=\"%s\"",ParseXML_Encode_Safe_XML(id)); + if(timestamp) printf(" timestamp=\"%s\"",ParseXML_Encode_Safe_XML(timestamp)); + if(uid) printf(" uid=\"%s\"",ParseXML_Encode_Safe_XML(uid)); + if(user) printf(" user=\"%s\"",ParseXML_Encode_Safe_XML(user)); + if(visible) printf(" visible=\"%s\"",ParseXML_Encode_Safe_XML(visible)); + if(version) printf(" version=\"%s\"",ParseXML_Encode_Safe_XML(version)); + if(action) printf(" action=\"%s\"",ParseXML_Encode_Safe_XML(action)); + printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":""); + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the relationType XSD type is seen + + int relationType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *id The contents of the 'id' attribute (or NULL if not defined). + + const char *timestamp The contents of the 'timestamp' attribute (or NULL if not defined). + + const char *uid The contents of the 'uid' attribute (or NULL if not defined). + + const char *user The contents of the 'user' attribute (or NULL if not defined). + + const char *visible The contents of the 'visible' attribute (or NULL if not defined). + + const char *version The contents of the 'version' attribute (or NULL if not defined). + + const char *action The contents of the 'action' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int relationType_function(const char *_tag_,int _type_,const char *id,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action) +{ + if(_type_&XMLPARSE_TAG_START) + { + nrelations++; + + if(!(nrelations%1000)) + fprintf(stderr,"\rReading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations); + + current_tags=NewTagList(); + } + + if(_type_&XMLPARSE_TAG_END) + { + TagList *result=ApplyTaggingRules(&RelationRules,current_tags); + int i; + + for(i=0;intags;i++) + { + printf(" k[i])); + printf(" v=\"%s\"",ParseXML_Encode_Safe_XML(result->v[i])); + printf(" />\n"); + } + + DeleteTagList(current_tags); + DeleteTagList(result); + } + + printf(" <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_); + if(id) printf(" id=\"%s\"",ParseXML_Encode_Safe_XML(id)); + if(timestamp) printf(" timestamp=\"%s\"",ParseXML_Encode_Safe_XML(timestamp)); + if(uid) printf(" uid=\"%s\"",ParseXML_Encode_Safe_XML(uid)); + if(user) printf(" user=\"%s\"",ParseXML_Encode_Safe_XML(user)); + if(visible) printf(" visible=\"%s\"",ParseXML_Encode_Safe_XML(visible)); + if(version) printf(" version=\"%s\"",ParseXML_Encode_Safe_XML(version)); + if(action) printf(" action=\"%s\"",ParseXML_Encode_Safe_XML(action)); + printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":""); + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the osmType XSD type is seen + + int osmType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *version The contents of the 'version' attribute (or NULL if not defined). + + const char *generator The contents of the 'generator' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int osmType_function(const char *_tag_,int _type_,const char *version,const char *generator) +{ + printf("<%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_); + if(version) printf(" version=\"%s\"",ParseXML_Encode_Safe_XML(version)); + if(generator) printf(" generator=\"%s\"",ParseXML_Encode_Safe_XML(generator)); + printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":""); + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the XML declaration is seen + + int xmlDeclaration_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *version The contents of the 'version' attribute (or NULL if not defined). + + const char *encoding The contents of the 'encoding' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding) +{ + printf("\n"); + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The main program for the planetsplitter. + ++++++++++++++++++++++++++++++++++++++*/ + +int main(int argc,char **argv) +{ + char *tagging=NULL,*filename=NULL; + FILE *file; + int arg,retval; + + /* Parse the command line arguments */ + + for(arg=1;arg]\n" + " []\n"); + + if(detail) + fprintf(stderr, + "\n" + "--help Prints this information.\n" + "\n" + "--tagging= The name of the XML file containing the tagging rules\n" + " (defaults to 'tagging.xml' in current directory).\n" + "\n" + " The name of the file to process (by default data is\n" + " read from standard input).\n"); + + exit(!detail); +} diff --git a/src/translations.c b/src/translations.c new file mode 100644 index 0000000..c00fdff --- /dev/null +++ b/src/translations.c @@ -0,0 +1,1050 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/translations.c,v 1.10 2010/07/03 10:58:37 amb Exp $ + + Load the translations from a file and the functions for handling them. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include + +#include "functions.h" +#include "translations.h" +#include "xmlparse.h" + + +/* Global variables - default English values */ + +char *translate_copyright_creator[2]={"Creator","Routino - http://www.routino.org/"}; +char *translate_copyright_source[2] ={NULL,NULL}; +char *translate_copyright_license[2]={NULL,NULL}; + +char *translate_heading[9]={"South","South-West","West","North-West","North","North-East","East","South-East","South"}; +char *translate_turn[9] ={"Very sharp left","Sharp left","Left","Slight left","Straight on","Slight right","Right","Sharp right","Very sharp right"}; + +char *translate_highway[Way_Count]={"","motorway","trunk road","primary road","secondary road","tertiary road","unclassified road","residential road","service road","track","cycleway","path","steps"}; + +char *translate_route_shortest="Shortest"; +char *translate_route_quickest="Quickest"; + +char *translate_html_waypoint="Waypoint"; +char *translate_html_junction="Junction"; + +char *translate_html_title="%s Route"; +char *translate_html_start[2]={"Start","At %s, head %s"}; +char *translate_html_segment[2]={"Follow","%s for %.3f km, %.1f min"}; +char *translate_html_node[2]={"At","%s, go %s heading %s"}; +char *translate_html_stop[2]={"Stop","At %s"}; +char *translate_html_total[2]={"Total","%.1f km, %.0f minutes"}; + +char *translate_gpx_desc ="%s between 'start' and 'finish' waypoints"; +char *translate_gpx_name ="%s Route"; +char *translate_gpx_step ="%s on '%s' for %.3f km, %.1 min"; +char *translate_gpx_final="Total Journey %.1f km, %d minutes"; + +char *translate_gpx_start="START"; +char *translate_gpx_inter="INTER"; +char *translate_gpx_trip="TRIP"; +char *translate_gpx_finish="FINISH"; + + +/* Local variables */ + +/*+ The language that is to be stored. +*/ +static const char *store_lang=NULL; + +/*+ This current language is to be stored. +*/ +static int store=0; + +/*+ The chosen language has been stored. +*/ +static int stored=0; + + +/* The XML tag processing function prototypes */ + +//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding); +//static int RoutinoTranslationsType_function(const char *_tag_,int _type_); +static int languageType_function(const char *_tag_,int _type_,const char *lang); +//static int GPXType_function(const char *_tag_,int _type_); +static int GPXFinalType_function(const char *_tag_,int _type_,const char *text); +static int GPXStepType_function(const char *_tag_,int _type_,const char *text); +static int GPXNameType_function(const char *_tag_,int _type_,const char *text); +static int GPXDescType_function(const char *_tag_,int _type_,const char *text); +//static int HTMLType_function(const char *_tag_,int _type_); +static int HTMLTotalType_function(const char *_tag_,int _type_,const char *string,const char *text); +static int HTMLStopType_function(const char *_tag_,int _type_,const char *string,const char *text); +static int HTMLSegmentType_function(const char *_tag_,int _type_,const char *string,const char *text); +static int HTMLNodeType_function(const char *_tag_,int _type_,const char *string,const char *text); +static int HTMLStartType_function(const char *_tag_,int _type_,const char *string,const char *text); +static int HTMLTitleType_function(const char *_tag_,int _type_,const char *text); +//static int CopyrightType_function(const char *_tag_,int _type_); +static int GPXWaypointType_function(const char *_tag_,int _type_,const char *type,const char *string); +static int HTMLWaypointType_function(const char *_tag_,int _type_,const char *type,const char *string); +static int RouteType_function(const char *_tag_,int _type_,const char *type,const char *string); +static int HighwayType_function(const char *_tag_,int _type_,const char *type,const char *string); +static int HeadingType_function(const char *_tag_,int _type_,const char *direction,const char *string); +static int TurnType_function(const char *_tag_,int _type_,const char *direction,const char *string); +static int CopyrightLicenseType_function(const char *_tag_,int _type_,const char *string,const char *text); +static int CopyrightSourceType_function(const char *_tag_,int _type_,const char *string,const char *text); +static int CopyrightCreatorType_function(const char *_tag_,int _type_,const char *string,const char *text); + + +/* The XML tag definitions */ + +/*+ The CopyrightCreatorType type tag. +*/ +static xmltag CopyrightCreatorType_tag= + {"creator", + 2, {"string","text"}, + CopyrightCreatorType_function, + {NULL}}; + +/*+ The CopyrightSourceType type tag. +*/ +static xmltag CopyrightSourceType_tag= + {"source", + 2, {"string","text"}, + CopyrightSourceType_function, + {NULL}}; + +/*+ The CopyrightLicenseType type tag. +*/ +static xmltag CopyrightLicenseType_tag= + {"license", + 2, {"string","text"}, + CopyrightLicenseType_function, + {NULL}}; + +/*+ The TurnType type tag. +*/ +static xmltag TurnType_tag= + {"turn", + 2, {"direction","string"}, + TurnType_function, + {NULL}}; + +/*+ The HeadingType type tag. +*/ +static xmltag HeadingType_tag= + {"heading", + 2, {"direction","string"}, + HeadingType_function, + {NULL}}; + +/*+ The HighwayType type tag. +*/ +static xmltag HighwayType_tag= + {"highway", + 2, {"type","string"}, + HighwayType_function, + {NULL}}; + +/*+ The RouteType type tag. +*/ +static xmltag RouteType_tag= + {"route", + 2, {"type","string"}, + RouteType_function, + {NULL}}; + +/*+ The HTMLWaypointType type tag. +*/ +static xmltag HTMLWaypointType_tag= + {"waypoint", + 2, {"type","string"}, + HTMLWaypointType_function, + {NULL}}; + +/*+ The GPXWaypointType type tag. +*/ +static xmltag GPXWaypointType_tag= + {"waypoint", + 2, {"type","string"}, + GPXWaypointType_function, + {NULL}}; + +/*+ The CopyrightType type tag. +*/ +static xmltag CopyrightType_tag= + {"copyright", + 0, {NULL}, + NULL, + {&CopyrightCreatorType_tag,&CopyrightSourceType_tag,&CopyrightLicenseType_tag,NULL}}; + +/*+ The HTMLTitleType type tag. +*/ +static xmltag HTMLTitleType_tag= + {"title", + 1, {"text"}, + HTMLTitleType_function, + {NULL}}; + +/*+ The HTMLStartType type tag. +*/ +static xmltag HTMLStartType_tag= + {"start", + 2, {"string","text"}, + HTMLStartType_function, + {NULL}}; + +/*+ The HTMLNodeType type tag. +*/ +static xmltag HTMLNodeType_tag= + {"node", + 2, {"string","text"}, + HTMLNodeType_function, + {NULL}}; + +/*+ The HTMLSegmentType type tag. +*/ +static xmltag HTMLSegmentType_tag= + {"segment", + 2, {"string","text"}, + HTMLSegmentType_function, + {NULL}}; + +/*+ The HTMLStopType type tag. +*/ +static xmltag HTMLStopType_tag= + {"stop", + 2, {"string","text"}, + HTMLStopType_function, + {NULL}}; + +/*+ The HTMLTotalType type tag. +*/ +static xmltag HTMLTotalType_tag= + {"total", + 2, {"string","text"}, + HTMLTotalType_function, + {NULL}}; + +/*+ The HTMLType type tag. +*/ +static xmltag HTMLType_tag= + {"output-html", + 0, {NULL}, + NULL, + {&HTMLWaypointType_tag,&HTMLTitleType_tag,&HTMLStartType_tag,&HTMLNodeType_tag,&HTMLSegmentType_tag,&HTMLStopType_tag,&HTMLTotalType_tag,NULL}}; + +/*+ The GPXDescType type tag. +*/ +static xmltag GPXDescType_tag= + {"desc", + 1, {"text"}, + GPXDescType_function, + {NULL}}; + +/*+ The GPXNameType type tag. +*/ +static xmltag GPXNameType_tag= + {"name", + 1, {"text"}, + GPXNameType_function, + {NULL}}; + +/*+ The GPXStepType type tag. +*/ +static xmltag GPXStepType_tag= + {"step", + 1, {"text"}, + GPXStepType_function, + {NULL}}; + +/*+ The GPXFinalType type tag. +*/ +static xmltag GPXFinalType_tag= + {"final", + 1, {"text"}, + GPXFinalType_function, + {NULL}}; + +/*+ The GPXType type tag. +*/ +static xmltag GPXType_tag= + {"output-gpx", + 0, {NULL}, + NULL, + {&GPXWaypointType_tag,&GPXDescType_tag,&GPXNameType_tag,&GPXStepType_tag,&GPXFinalType_tag,NULL}}; + +/*+ The languageType type tag. +*/ +static xmltag languageType_tag= + {"language", + 1, {"lang"}, + languageType_function, + {&CopyrightType_tag,&TurnType_tag,&HeadingType_tag,&HighwayType_tag,&RouteType_tag,&HTMLType_tag,&GPXType_tag,NULL}}; + +/*+ The RoutinoTranslationsType type tag. +*/ +static xmltag RoutinoTranslationsType_tag= + {"routino-translations", + 0, {NULL}, + NULL, + {&languageType_tag,NULL}}; + +/*+ The xmlDeclaration type tag. +*/ +static xmltag xmlDeclaration_tag= + {"xml", + 2, {"version","encoding"}, + NULL, + {NULL}}; + + +/*+ The complete set of tags at the top level. +*/ +static xmltag *xml_toplevel_tags[]={&xmlDeclaration_tag,&RoutinoTranslationsType_tag,NULL}; + + +/* The XML tag processing functions */ + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the CopyrightCreatorType XSD type is seen + + int CopyrightCreatorType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *string The contents of the 'string' attribute (or NULL if not defined). + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int CopyrightCreatorType_function(const char *_tag_,int _type_,const char *string,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,string); + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_copyright_creator[0]=strcpy(malloc(strlen(string)+1),string); + translate_copyright_creator[1]=strcpy(malloc(strlen(text)+1),text); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the CopyrightSourceType XSD type is seen + + int CopyrightSourceType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *string The contents of the 'string' attribute (or NULL if not defined). + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int CopyrightSourceType_function(const char *_tag_,int _type_,const char *string,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,string); + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_copyright_source[0]=strcpy(malloc(strlen(string)+1),string); + translate_copyright_source[1]=strcpy(malloc(strlen(text)+1),text); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the CopyrightLicenseType XSD type is seen + + int CopyrightLicenseType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *string The contents of the 'string' attribute (or NULL if not defined). + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int CopyrightLicenseType_function(const char *_tag_,int _type_,const char *string,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,string); + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_copyright_license[0]=strcpy(malloc(strlen(string)+1),string); + translate_copyright_license[1]=strcpy(malloc(strlen(text)+1),text); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the TurnType XSD type is seen + + int TurnType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *direction The contents of the 'direction' attribute (or NULL if not defined). + + const char *string The contents of the 'string' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int TurnType_function(const char *_tag_,int _type_,const char *direction,const char *string) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + int d; + + XMLPARSE_ASSERT_INTEGER(_tag_,direction,d); + XMLPARSE_ASSERT_STRING(_tag_,string); + + d+=4; + + if(d<0 || d>8) + XMLPARSE_INVALID(_tag_,direction); + + translate_turn[d]=strcpy(malloc(strlen(string)+1),string); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the HeadingType XSD type is seen + + int HeadingType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *direction The contents of the 'direction' attribute (or NULL if not defined). + + const char *string The contents of the 'string' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int HeadingType_function(const char *_tag_,int _type_,const char *direction,const char *string) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + int d; + + XMLPARSE_ASSERT_INTEGER(_tag_,direction,d); + XMLPARSE_ASSERT_STRING(_tag_,string); + + d+=4; + + if(d<0 || d>8) + XMLPARSE_INVALID(_tag_,direction); + + translate_heading[d]=strcpy(malloc(strlen(string)+1),string); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the HighwayType XSD type is seen + + int HighwayType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *type The contents of the 'type' attribute (or NULL if not defined). + + const char *string The contents of the 'string' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int HighwayType_function(const char *_tag_,int _type_,const char *type,const char *string) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + Highway highway; + + XMLPARSE_ASSERT_STRING(_tag_,type); + XMLPARSE_ASSERT_STRING(_tag_,string); + + highway=HighwayType(type); + + if(highway==Way_Count) + XMLPARSE_INVALID(_tag_,type); + + translate_highway[highway]=strcpy(malloc(strlen(string)+1),string); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the RouteType XSD type is seen + + int RouteType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *type The contents of the 'type' attribute (or NULL if not defined). + + const char *string The contents of the 'string' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int RouteType_function(const char *_tag_,int _type_,const char *type,const char *string) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,type); + XMLPARSE_ASSERT_STRING(_tag_,string); + + if(!strcmp(type,"shortest")) + translate_route_shortest=strcpy(malloc(strlen(string)+1),string); + else if(!strcmp(type,"quickest")) + translate_route_quickest=strcpy(malloc(strlen(string)+1),string); + else + XMLPARSE_INVALID(_tag_,type); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the HTMLWaypointType XSD type is seen + + int HTMLWaypointType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *type The contents of the 'type' attribute (or NULL if not defined). + + const char *string The contents of the 'string' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int HTMLWaypointType_function(const char *_tag_,int _type_,const char *type,const char *string) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,type); + XMLPARSE_ASSERT_STRING(_tag_,string); + + if(!strcmp(type,"waypoint")) + { + translate_html_waypoint=malloc(strlen(string)+1+sizeof("")+sizeof("")); + sprintf(translate_html_waypoint,"%s",string); + } + else if(!strcmp(type,"junction")) + translate_html_junction=strcpy(malloc(strlen(string)+1),string); + else + XMLPARSE_INVALID(_tag_,type); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the GPXWaypointType XSD type is seen + + int GPXWaypointType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *type The contents of the 'type' attribute (or NULL if not defined). + + const char *string The contents of the 'string' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int GPXWaypointType_function(const char *_tag_,int _type_,const char *type,const char *string) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,type); + XMLPARSE_ASSERT_STRING(_tag_,string); + + if(!strcmp(type,"start")) + translate_gpx_start=strcpy(malloc(strlen(string)+1),string); + else if(!strcmp(type,"inter")) + translate_gpx_inter=strcpy(malloc(strlen(string)+1),string); + else if(!strcmp(type,"trip")) + translate_gpx_trip=strcpy(malloc(strlen(string)+1),string); + else if(!strcmp(type,"finish")) + translate_gpx_finish=strcpy(malloc(strlen(string)+1),string); + else + XMLPARSE_INVALID(_tag_,type); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the CopyrightType XSD type is seen + + int CopyrightType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int CopyrightType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the HTMLTitleType XSD type is seen + + int HTMLTitleType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int HTMLTitleType_function(const char *_tag_,int _type_,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_html_title=strcpy(malloc(strlen(text)+1),text); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the HTMLStartType XSD type is seen + + int HTMLStartType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *string The contents of the 'string' attribute (or NULL if not defined). + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int HTMLStartType_function(const char *_tag_,int _type_,const char *string,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,string); + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_html_start[0]=strcpy(malloc(strlen(string)+1),string); + translate_html_start[1]=malloc(strlen(text)+1+sizeof("")+sizeof("")); + sprintf(translate_html_start[1],text,"%s","%s"); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the HTMLNodeType XSD type is seen + + int HTMLNodeType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *string The contents of the 'string' attribute (or NULL if not defined). + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int HTMLNodeType_function(const char *_tag_,int _type_,const char *string,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,string); + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_html_node[0]=strcpy(malloc(strlen(string)+1),string); + translate_html_node[1]=malloc(strlen(text)+1+2*sizeof("")+2*sizeof("")); + sprintf(translate_html_node[1],text,"%s","%s","%s"); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the HTMLSegmentType XSD type is seen + + int HTMLSegmentType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *string The contents of the 'string' attribute (or NULL if not defined). + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int HTMLSegmentType_function(const char *_tag_,int _type_,const char *string,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + const char *p; + char *q; + + XMLPARSE_ASSERT_STRING(_tag_,string); + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_html_segment[0]=strcpy(malloc(strlen(string)+1),string); + translate_html_segment[1]=malloc(strlen(text)+1+2*sizeof("")+2*sizeof("")); + + p=text; + q=translate_html_segment[1]; + + while(*p!='%' && *(p+1)!='s') + *q++=*p++; + + p+=2; + strcpy(q,"%s"); q+=sizeof("%s")-1; + + while(*p!='%') + *q++=*p++; + + strcpy(q,""); q+=sizeof("")-1; + + strcpy(q,p); + strcat(q,""); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the HTMLStopType XSD type is seen + + int HTMLStopType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *string The contents of the 'string' attribute (or NULL if not defined). + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int HTMLStopType_function(const char *_tag_,int _type_,const char *string,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,string); + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_html_stop[0]=strcpy(malloc(strlen(string)+1),string); + translate_html_stop[1]=strcpy(malloc(strlen(text)+1),text); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the HTMLTotalType XSD type is seen + + int HTMLTotalType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *string The contents of the 'string' attribute (or NULL if not defined). + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int HTMLTotalType_function(const char *_tag_,int _type_,const char *string,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,string); + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_html_total[0]=strcpy(malloc(strlen(string)+1),string); + translate_html_total[1]=strcpy(malloc(strlen(text)+1),text); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the HTMLType XSD type is seen + + int HTMLType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int HTMLType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the GPXDescType XSD type is seen + + int GPXDescType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int GPXDescType_function(const char *_tag_,int _type_,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_gpx_desc=strcpy(malloc(strlen(text)+1),text); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the GPXNameType XSD type is seen + + int GPXNameType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int GPXNameType_function(const char *_tag_,int _type_,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_gpx_name=strcpy(malloc(strlen(text)+1),text); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the GPXStepType XSD type is seen + + int GPXStepType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int GPXStepType_function(const char *_tag_,int _type_,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_gpx_step=strcpy(malloc(strlen(text)+1),text); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the GPXFinalType XSD type is seen + + int GPXFinalType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *text The contents of the 'text' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int GPXFinalType_function(const char *_tag_,int _type_,const char *text) +{ + if(_type_&XMLPARSE_TAG_START && store) + { + XMLPARSE_ASSERT_STRING(_tag_,text); + + translate_gpx_final=strcpy(malloc(strlen(text)+1),text); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the GPXType XSD type is seen + + int GPXType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int GPXType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the languageType XSD type is seen + + int languageType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *lang The contents of the 'lang' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int languageType_function(const char *_tag_,int _type_,const char *lang) +{ + static int first=1; + + if(_type_&XMLPARSE_TAG_START) + { + XMLPARSE_ASSERT_STRING(_tag_,lang); + + if(!store_lang && first) + store=1; + else if(store_lang && !strcmp(store_lang,lang)) + store=1; + else + store=0; + + first=0; + } + + if(_type_&XMLPARSE_TAG_END && store) + { + store=0; + stored=1; + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the RoutinoTranslationsType XSD type is seen + + int RoutinoTranslationsType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +//static int RoutinoTranslationsType_function(const char *_tag_,int _type_) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the XML declaration is seen + + int xmlDeclaration_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *version The contents of the 'version' attribute (or NULL if not defined). + + const char *encoding The contents of the 'encoding' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding) +//{ +// return(0); +//} + + +/*++++++++++++++++++++++++++++++++++++++ + The XML translation parser. + + int ParseXMLTranslations Returns 0 if OK or something else in case of an error. + + const char *filename The name of the file to read. + + const char *language The language to search for (NULL means first in file). + ++++++++++++++++++++++++++++++++++++++*/ + +int ParseXMLTranslations(const char *filename,const char *language) +{ + int retval; + + store_lang=language; + + if(!ExistsFile(filename)) + { + fprintf(stderr,"Error: Specified translations file '%s' does not exist.\n",filename); + return(1); + } + + FILE *file=fopen(filename,"r"); + + if(!file) + { + fprintf(stderr,"Error: Cannot open translations file '%s' for reading.\n",filename); + return(1); + } + + retval=ParseXML(file,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_ERRNONAME|XMLPARSE_RETURN_ATTR_ENCODED); + + fclose(file); + + if(retval) + return(1); + + if(language && !stored) + fprintf(stderr,"Warning: Cannot find translations for language '%s' using English instead.\n",language); + + return(0); +} diff --git a/src/translations.h b/src/translations.h new file mode 100644 index 0000000..13902ed --- /dev/null +++ b/src/translations.h @@ -0,0 +1,69 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/translations.h,v 1.4 2010/05/29 13:54:23 amb Exp $ + + Load the translations from a file and the functions for handling them. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef TRANSLATIONS_H +#define TRANSLATIONS_H /*+ To stop multiple inclusions. +*/ + +#include "types.h" + + +/* Variable declations */ + +extern char *translate_copyright_creator[2]; +extern char *translate_copyright_source[2]; +extern char *translate_copyright_license[2]; + +extern char *translate_heading[9]; +extern char *translate_turn[9]; + +extern char *translate_highway[Way_Count]; + +extern char *translate_route_shortest; +extern char *translate_route_quickest; + +extern char *translate_html_waypoint; +extern char *translate_html_junction; + +extern char *translate_html_title; +extern char *translate_html_start[2]; +extern char *translate_html_segment[2]; +extern char *translate_html_node[2]; +extern char *translate_html_stop[2]; +extern char *translate_html_total[2]; + +extern char *translate_gpx_desc; +extern char *translate_gpx_name; +extern char *translate_gpx_step; +extern char *translate_gpx_final; + +extern char *translate_gpx_start; +extern char *translate_gpx_inter; +extern char *translate_gpx_trip; +extern char *translate_gpx_finish; + +/* Functions */ + +int ParseXMLTranslations(const char *filename,const char *language); + +#endif /* TRANSLATIONS_H */ diff --git a/src/types.c b/src/types.c new file mode 100644 index 0000000..3670992 --- /dev/null +++ b/src/types.c @@ -0,0 +1,488 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/types.c,v 1.3 2010/05/27 17:25:23 amb Exp $ + + Functions for handling the data types. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include + +#include "types.h" + + +/*++++++++++++++++++++++++++++++++++++++ + Decide on the type of a way given the "highway" parameter. + + Highway HighwayType Returns the highway type of the way. + + const char *highway The string containing the type of the way. + ++++++++++++++++++++++++++++++++++++++*/ + +Highway HighwayType(const char *highway) +{ + switch(*highway) + { + case 'c': + if(!strcmp(highway,"cycleway")) return(Way_Cycleway); + return(Way_Count); + + case 'm': + if(!strcmp(highway,"motorway")) return(Way_Motorway); + return(Way_Count); + + case 'p': + if(!strcmp(highway,"primary")) return(Way_Primary); + if(!strcmp(highway,"path")) return(Way_Path); + return(Way_Count); + + case 'r': + if(!strcmp(highway,"residential")) return(Way_Residential); + return(Way_Count); + + case 's': + if(!strcmp(highway,"secondary")) return(Way_Secondary); + if(!strcmp(highway,"service")) return(Way_Service); + if(!strcmp(highway,"steps")) return(Way_Steps); + return(Way_Count); + + case 't': + if(!strcmp(highway,"trunk")) return(Way_Trunk); + if(!strcmp(highway,"tertiary")) return(Way_Tertiary); + if(!strcmp(highway,"track")) return(Way_Track); + return(Way_Count); + + case 'u': + if(!strcmp(highway,"unclassified")) return(Way_Unclassified); + return(Way_Count); + + default: + ; + } + + return(Way_Count); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Decide on the type of transport given the name of it. + + Transport TransportType Returns the type of the transport. + + const char *transport The string containing the method of transport. + ++++++++++++++++++++++++++++++++++++++*/ + +Transport TransportType(const char *transport) +{ + switch(*transport) + { + case 'b': + if(!strcmp(transport,"bicycle")) + return(Transport_Bicycle); + break; + + case 'f': + if(!strcmp(transport,"foot")) + return(Transport_Foot); + break; + + case 'g': + if(!strcmp(transport,"goods")) + return(Transport_Goods); + break; + + case 'h': + if(!strcmp(transport,"horse")) + return(Transport_Horse); + if(!strcmp(transport,"hgv")) + return(Transport_HGV); + break; + + case 'm': + if(!strcmp(transport,"moped")) + return(Transport_Moped); + if(!strcmp(transport,"motorbike")) + return(Transport_Motorbike); + if(!strcmp(transport,"motorcar")) + return(Transport_Motorcar); + break; + + case 'p': + if(!strcmp(transport,"psv")) + return(Transport_PSV); + break; + + case 'w': + if(!strcmp(transport,"wheelchair")) + return(Transport_Wheelchair); + break; + + default: + return(Transport_None); + } + + return(Transport_None); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Decide on the type of property given the name of it. + + Property PropertyType Returns the type of the property. + + const char *property The string containing the method of property. + ++++++++++++++++++++++++++++++++++++++*/ + +Property PropertyType(const char *property) +{ + switch(*property) + { + case 'b': + if(!strcmp(property,"bridge")) + return(Property_Bridge); + break; + + case 'm': + if(!strcmp(property,"multilane")) + return(Property_Multilane); + break; + + case 'p': + if(!strcmp(property,"paved")) + return(Property_Paved); + break; + + case 't': + if(!strcmp(property,"tunnel")) + return(Property_Tunnel); + break; + + default: + return(Property_None); + } + + return(Property_None); +} + + +/*++++++++++++++++++++++++++++++++++++++ + A string containing the name of a type of highway. + + const char *HighwayName Returns the name. + + Highway highway The highway type. + ++++++++++++++++++++++++++++++++++++++*/ + +const char *HighwayName(Highway highway) +{ + switch(highway) + { + case Way_Motorway: + return("motorway"); + case Way_Trunk: + return("trunk"); + case Way_Primary: + return("primary"); + case Way_Secondary: + return("secondary"); + case Way_Tertiary: + return("tertiary"); + case Way_Unclassified: + return("unclassified"); + case Way_Residential: + return("residential"); + case Way_Service: + return("service"); + case Way_Track: + return("track"); + case Way_Cycleway: + return("cycleway"); + case Way_Path: + return("path"); + case Way_Steps: + return("steps"); + + case Way_Count: + ; + + case Way_OneWay: + case Way_Roundabout: + ; + } + + return(NULL); +} + + +/*++++++++++++++++++++++++++++++++++++++ + A string containing the name of a type of transport. + + const char *TransportName Returns the name. + + Transport transport The transport type. + ++++++++++++++++++++++++++++++++++++++*/ + +const char *TransportName(Transport transport) +{ + switch(transport) + { + case Transport_None: + return("NONE"); + + case Transport_Foot: + return("foot"); + case Transport_Horse: + return("horse"); + case Transport_Wheelchair: + return("wheelchair"); + case Transport_Bicycle: + return("bicycle"); + case Transport_Moped: + return("moped"); + case Transport_Motorbike: + return("motorbike"); + case Transport_Motorcar: + return("motorcar"); + case Transport_Goods: + return("goods"); + case Transport_HGV: + return("hgv"); + case Transport_PSV: + return("psv"); + + case Transport_Count: + ; + } + + return(NULL); +} + + +/*++++++++++++++++++++++++++++++++++++++ + A string containing the name of a highway property. + + const char *PropertyName Returns the name. + + Property property The property type. + ++++++++++++++++++++++++++++++++++++++*/ + +const char *PropertyName(Property property) +{ + switch(property) + { + case Property_None: + return("NONE"); + + case Property_Paved: + return("paved"); + + case Property_Multilane: + return("multilane"); + + case Property_Bridge: + return("bridge"); + + case Property_Tunnel: + return("tunnel"); + + case Property_Count: + ; + } + + return(NULL); +} + + +/*++++++++++++++++++++++++++++++++++++++ + A string containing the names of allowed transports on a way. + + const char *AllowedNameList Returns the list of names. + + wayallow_t allowed The allowed type. + ++++++++++++++++++++++++++++++++++++++*/ + +const char *AllowedNameList(wayallow_t allowed) +{ + static char string[256]; + + string[0]=0; + + if(allowed & Allow_Foot) + strcat(string,"foot"); + + if(allowed & Allow_Horse) + { + if(*string) strcat(string,", "); + strcat(string,"horse"); + } + + if(allowed & Allow_Wheelchair) + { + if(*string) strcat(string,", "); + strcat(string,"wheelchair"); + } + + if(allowed & Allow_Bicycle) + { + if(*string) strcat(string,", "); + strcat(string,"bicycle"); + } + + if(allowed & Allow_Moped) + { + if(*string) strcat(string,", "); + strcat(string,"moped"); + } + + if(allowed & Allow_Motorbike) + { + if(*string) strcat(string,", "); + strcat(string,"motorbike"); + } + + if(allowed & Allow_Motorcar) + { + if(*string) strcat(string,", "); + strcat(string,"motorcar"); + } + + if(allowed & Allow_Goods) + { + if(*string) strcat(string,", "); + strcat(string,"goods"); + } + + if(allowed & Allow_HGV) + { + if(*string) strcat(string,", "); + strcat(string,"hgv"); + } + + if(allowed & Allow_PSV) + { + if(*string) strcat(string,", "); + strcat(string,"psv"); + } + + return(string); +} + + +/*++++++++++++++++++++++++++++++++++++++ + A string containing the names of the properties of a way. + + const char *PropertiesNameList Returns the list of names. + + wayprop_t properties The properties of the way. + ++++++++++++++++++++++++++++++++++++++*/ + +const char *PropertiesNameList(wayprop_t properties) +{ + static char string[256]; + + string[0]=0; + + if(properties & Properties_Paved) + { + if(*string) strcat(string,", "); + strcat(string,"paved"); + } + + if(properties & Properties_Multilane) + { + if(*string) strcat(string,", "); + strcat(string,"multilane"); + } + + if(properties & Properties_Bridge) + { + if(*string) strcat(string,", "); + strcat(string,"bridge"); + } + + if(properties & Properties_Tunnel) + { + if(*string) strcat(string,", "); + strcat(string,"tunnel"); + } + + return(string); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Returns a list of all the highway types. + + const char *HighwayList Return a list of all the highway types. + ++++++++++++++++++++++++++++++++++++++*/ + +const char *HighwayList(void) +{ + return " motorway = Motorway\n" + " trunk = Trunk\n" + " primary = Primary\n" + " secondary = Secondary\n" + " tertiary = Tertiary\n" + " unclassified = Unclassified\n" + " residential = Residential\n" + " service = Service\n" + " track = Track\n" + " cycleway = Cycleway\n" + " path = Path\n" + " steps = Steps\n" + ; +} + + +/*++++++++++++++++++++++++++++++++++++++ + Returns a list of all the transport types. + + const char *TransportList Return a list of all the transport types. + ++++++++++++++++++++++++++++++++++++++*/ + +const char *TransportList(void) +{ + return " foot = Foot\n" + " bicycle = Bicycle\n" + " wheelchair = Wheelchair\n" + " horse = Horse\n" + " moped = Moped (Small motorbike, limited speed)\n" + " motorbike = Motorbike\n" + " motorcar = Motorcar\n" + " goods = Goods (Small lorry, van)\n" + " hgv = HGV (Heavy Goods Vehicle - large lorry)\n" + " psv = PSV (Public Service Vehicle - bus, coach)\n" + ; +} + + +/*++++++++++++++++++++++++++++++++++++++ + Returns a list of all the property types. + + const char *PropertyList Return a list of all the highway proprties. + ++++++++++++++++++++++++++++++++++++++*/ + +const char *PropertyList(void) +{ + return " paved = Paved (suitable for normal wheels)\n" + " multilane = Multiple lanes\n" + " bridge = Bridge\n" + " Tunnel = Tunnel\n" + ; +} diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..852122f --- /dev/null +++ b/src/types.h @@ -0,0 +1,350 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/types.h,v 1.40 2010/05/27 17:25:23 amb Exp $ + + Type definitions + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef TYPES_H +#define TYPES_H /*+ To stop multiple inclusions. +*/ + +#include +#include + + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +/* Constants and macros for handling them */ + + +/*+ The latitude and longitude conversion factor from floating point (radians) to integer. +*/ +#define LAT_LONG_SCALE (1024*65536) + +/*+ The latitude and longitude integer range within each bin. +*/ +#define LAT_LONG_BIN 65536 + + +/*+ A flag to mark a node as a super-node. +*/ +#define NODE_SUPER ((index_t)0x80000000) + +/*+ A segment index excluding the super-node flag. +*/ +#define SEGMENT(xxx) (index_t)((xxx)&(~NODE_SUPER)) + + +/*+ An undefined node index. +*/ +#define NO_NODE (~(index_t)0) + +/*+ An undefined segment index. +*/ +#define NO_SEGMENT (~(index_t)0) + +/*+ An undefined way index. +*/ +#define NO_WAY (~(index_t)0) + + +/*+ A flag to mark a segment as one-way from node1 to node2. +*/ +#define ONEWAY_1TO2 ((distance_t)0x80000000) + +/*+ A flag to mark a segment as one-way node2 to node1. +*/ +#define ONEWAY_2TO1 ((distance_t)0x40000000) + +/*+ A flag to mark a segment as a super-segment. +*/ +#define SEGMENT_SUPER ((distance_t)0x20000000) + +/*+ A flag to mark a segment as a normal segment. +*/ +#define SEGMENT_NORMAL ((distance_t)0x10000000) + +/*+ The real distance ignoring the ONEWAY_* and SEGMENT_* flags. +*/ +#define DISTANCE(xx) ((distance_t)(xx)&(~(ONEWAY_1TO2|ONEWAY_2TO1|SEGMENT_SUPER|SEGMENT_NORMAL))) + +/*+ The distance flags selecting only the ONEWAY_* and SEGMENT_* flags. +*/ +#define DISTFLAG(xx) ((distance_t)(xx)&(ONEWAY_1TO2|ONEWAY_2TO1|SEGMENT_SUPER|SEGMENT_NORMAL)) + + +/*+ A very large almost infinite distance. +*/ +#define INF_DISTANCE DISTANCE(~0) + +/*+ A very large almost infinite score. +*/ +#define INF_SCORE (score_t)1E30 + + +/* Simple Types */ + + +/*+ A node, segment or way index. +*/ +typedef uint32_t index_t; + + +/*+ A node latitude or longitude. +*/ +typedef int32_t latlong_t; + +/*+ A node latitude or longitude bin number. +*/ +typedef int16_t ll_bin_t; + +/*+ A node latitude or longitude offset. +*/ +typedef uint16_t ll_off_t; + + +/*+ Conversion from a latlong (integer latitude or longitude) to a bin number. +*/ +#define latlong_to_bin(xxx) (ll_bin_t)((latlong_t)((xxx)&~(LAT_LONG_BIN-1))/LAT_LONG_BIN) + +/*+ Conversion from a bin number to a latlong (integer latitude or longitude). +*/ +#define bin_to_latlong(xxx) ((latlong_t)(xxx)*LAT_LONG_BIN) + +/*+ Conversion from a latlong (integer latitude or longitude) to a bin offset. +*/ +#define latlong_to_off(xxx) (ll_off_t)((latlong_t)(xxx)&(LAT_LONG_BIN-1)) + +/*+ Conversion from a bin offset to a latlong (integer latitude or longitude). +*/ +#define off_to_latlong(xxx) ((latlong_t)(xxx)) + + +/*+ Conversion from a latitude or longitude in radians to a latlong (integer latitude or longitude). +*/ +#define radians_to_latlong(xxx) ((latlong_t)floor((xxx)*LAT_LONG_SCALE)) + +/*+ Conversion from a latlong (integer latitude or longitude) to a latitude or longitude in radians. +*/ +#define latlong_to_radians(xxx) ((double)(xxx)/LAT_LONG_SCALE) + + +/*+ Conversion from radians to degrees. +*/ +#define radians_to_degrees(xxx) ((xxx)*(180.0/M_PI)) + +/*+ Conversion from degrees to radians. +*/ +#define degrees_to_radians(xxx) ((xxx)*(M_PI/180.0)) + + +/*+ A distance, measured in metres. +*/ +typedef uint32_t distance_t; + +/*+ A duration, measured in 1/10th seconds. +*/ +typedef uint32_t duration_t; + +/*+ A routing optimisation score. +*/ +typedef float score_t; + + +/*+ Conversion from distance_t to kilometres. +*/ +#define distance_to_km(xx) ((double)(xx)/1000.0) + +/*+ Conversion from metres to distance_t. +*/ +#define km_to_distance(xx) ((distance_t)((double)(xx)*1000.0)) + +/*+ Conversion from duration_t to minutes. +*/ +#define duration_to_minutes(xx) ((double)(xx)/600.0) + +/*+ Conversion from duration_t to hours. +*/ +#define duration_to_hours(xx) ((double)(xx)/36000.0) + +/*+ Conversion from hours to duration_t. +*/ +#define hours_to_duration(xx) ((duration_t)((double)(xx)*36000.0)) + +/*+ Conversion from distance_t and speed_t to duration_t. +*/ +#define distance_speed_to_duration(xx,yy) ((duration_t)(((double)(xx)/(double)(yy))*(36000.0/1000.0))) + + +/*+ The type of a way. +*/ +typedef uint8_t waytype_t; + +/*+ The different types of a way. +*/ +typedef enum _Highway + { + Way_Motorway = 1, + Way_Trunk = 2, + Way_Primary = 3, + Way_Secondary = 4, + Way_Tertiary = 5, + Way_Unclassified= 6, + Way_Residential = 7, + Way_Service = 8, + Way_Track = 9, + Way_Cycleway =10, + Way_Path =11, + Way_Steps =12, + + Way_Count =13, /* One more than the number of highway types. */ + + Way_OneWay =32, + Way_Roundabout =64 + } + Highway; + +#define HIGHWAY(xx) ((xx)&0x1f) + + +/*+ The different methods of transport. +*/ +typedef enum _Transport + { + Transport_None = 0, + + Transport_Foot = 1, + Transport_Horse = 2, + Transport_Wheelchair = 3, + Transport_Bicycle = 4, + Transport_Moped = 5, + Transport_Motorbike = 6, + Transport_Motorcar = 7, + Transport_Goods = 8, + Transport_HGV = 9, + Transport_PSV = 10, + + Transport_Count = 11 /*+ One more than the number of transport types. +*/ + } + Transport; + + +/*+ The allowed traffic on a way. +*/ +typedef uint16_t wayallow_t; + +#define ALLOWED(xx) (1<<((xx)-1)) + +/*+ The different allowed traffic on a way. +*/ +typedef enum _Allowed + { + Allow_Foot = ALLOWED(Transport_Foot ), + Allow_Horse = ALLOWED(Transport_Horse ), + Allow_Wheelchair = ALLOWED(Transport_Wheelchair), + Allow_Bicycle = ALLOWED(Transport_Bicycle ), + Allow_Moped = ALLOWED(Transport_Moped ), + Allow_Motorbike = ALLOWED(Transport_Motorbike ), + Allow_Motorcar = ALLOWED(Transport_Motorcar ), + Allow_Goods = ALLOWED(Transport_Goods ), + Allow_HGV = ALLOWED(Transport_HGV ), + Allow_PSV = ALLOWED(Transport_PSV ), + + Allow_ALL = 65535 + } + Allowed; + + +/*+ The individual properties of a highway. +*/ +typedef enum _Property + { + Property_None = 0, + + Property_Paved = 1, + Property_Multilane = 2, + Property_Bridge = 3, + Property_Tunnel = 4, + + Property_Count = 5 /* One more than the number of property types. */ + } + Property; + + +/*+ The combined set of properties of a way. +*/ +typedef uint8_t wayprop_t; + +#define PROPERTIES(xx) (1<<((xx)-1)) + +/*+ The different properties of a way. +*/ +typedef enum _Properties + { + Properties_Paved = PROPERTIES(Property_Paved), + Properties_Multilane = PROPERTIES(Property_Multilane), + Properties_Bridge = PROPERTIES(Property_Bridge), + Properties_Tunnel = PROPERTIES(Property_Tunnel), + + Properties_ALL = 255 + } + Properties; + + +/*+ The speed limit of a way, measured in km/hour. +*/ +typedef uint8_t speed_t; + +/*+ The maximum weight of a way, measured in 0.2 tonnes. +*/ +typedef uint8_t weight_t; + +/*+ The maximum height of a way, measured in 0.1 metres. +*/ +typedef uint8_t height_t; + +/*+ The maximum width of a way, measured in 0.1 metres. +*/ +typedef uint8_t width_t; + +/*+ The maximum length of a way, measured in 0.1 metres. +*/ +typedef uint8_t length_t; + + +/*+ Conversion of km/hr to speed_t. +*/ +#define kph_to_speed(xxx) (speed_t)(xxx) + +/*+ Conversion of speed_t to km/hr. +*/ +#define speed_to_kph(xxx) (int)(xxx) + +/*+ Conversion of tonnes to weight_t. +*/ +#define tonnes_to_weight(xxx) (weight_t)((xxx)*5) + +/*+ Conversion of weight_t to tonnes. +*/ +#define weight_to_tonnes(xxx) ((double)(xxx)/5.0) + +/*+ Conversion of metres to height_t. +*/ +#define metres_to_height(xxx) (height_t)((xxx)*10) + +/*+ Conversion of height_t to metres. +*/ +#define height_to_metres(xxx) ((double)(xxx)/10.0) + +/*+ Conversion of metres to width_t. +*/ +#define metres_to_width(xxx) (width_t)((xxx)*10) + +/*+ Conversion of width_t to metres. +*/ +#define width_to_metres(xxx) ((double)(xxx)/10.0) + +/*+ Conversion of metres to length_t. +*/ +#define metres_to_length(xxx) (length_t)((xxx)*10) + +/*+ Conversion of length_t to metres. +*/ +#define length_to_metres(xxx) ((double)(xxx)/10.0) + + +/* Data structures */ + +typedef struct _Node Node; + +typedef struct _Nodes Nodes; + +typedef struct _Segment Segment; + +typedef struct _Segments Segments; + +typedef struct _Way Way; + +typedef struct _Ways Ways; + + +/* Functions */ + +Highway HighwayType(const char *highway); +Transport TransportType(const char *transport); +Property PropertyType(const char *property); + +const char *HighwayName(Highway highway); +const char *TransportName(Transport transport); +const char *PropertyName(Property property); + +const char *AllowedNameList(wayallow_t allowed); +const char *PropertiesNameList(wayprop_t properties); + +const char *HighwayList(void); +const char *TransportList(void); +const char *PropertyList(void); + + +#endif /* TYPES_H */ diff --git a/src/typesx.h b/src/typesx.h new file mode 100644 index 0000000..25a350d --- /dev/null +++ b/src/typesx.h @@ -0,0 +1,56 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/typesx.h,v 1.3 2009/10/09 18:47:40 amb Exp $ + + Type definitions for eXtended types. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008,2009 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef TYPESX_H +#define TYPESX_H /*+ To stop multiple inclusions. +*/ + + +#include + + +/* Simple Types */ + +/*+ A node identifier - must be at least as large as index_t. +*/ +typedef uint32_t node_t; + +/*+ A way identifier - must be at least as large as index_t. +*/ +typedef uint32_t way_t; + + +/* Data structures */ + +typedef struct _NodeX NodeX; + +typedef struct _NodesX NodesX; + +typedef struct _SegmentX SegmentX; + +typedef struct _SegmentsX SegmentsX; + +typedef struct _WayX WayX; + +typedef struct _WaysX WaysX; + + +#endif /* TYPESX_H */ diff --git a/src/visualiser.c b/src/visualiser.c new file mode 100644 index 0000000..c4a5da4 --- /dev/null +++ b/src/visualiser.c @@ -0,0 +1,628 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/visualiser.c,v 1.7 2009/07/09 18:34:38 amb Exp $ + + Extract data from Routino. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008,2009 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include + +#include "types.h" +#include "visualiser.h" +#include "nodes.h" +#include "segments.h" +#include "ways.h" + + +#define SPEED_LIMIT 1 +#define WEIGHT_LIMIT 2 +#define HEIGHT_LIMIT 3 +#define WIDTH_LIMIT 4 +#define LENGTH_LIMIT 5 + +/* Local types */ + +typedef void (*callback_t)(index_t node,double latitude,double longitude); + +/* Local variables */ + +static Nodes *OSMNodes; +static Segments *OSMSegments; +static Ways *OSMWays; + +static double LatMin; +static double LatMax; +static double LonMin; +static double LonMax; + +static int limit_type=0; + +/* Local functions */ + +static void find_all_nodes(Nodes *nodes,callback_t callback); +static void output_junctions(index_t node,double latitude,double longitude); +static void output_super(index_t node,double latitude,double longitude); +static void output_oneway(index_t node,double latitude,double longitude); +static void output_limits(index_t node,double latitude,double longitude); + + +/*++++++++++++++++++++++++++++++++++++++ + Output the data for junctions. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + double latmin The minimum latitude. + + double latmax The maximum latitude. + + double lonmin The minimum longitude. + + double lonmax The maximum longitude. + ++++++++++++++++++++++++++++++++++++++*/ + +void OutputJunctions(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax) +{ + /* Use local variables so that the callback doesn't need to pass them backwards and forwards */ + + OSMNodes=nodes; + OSMSegments=segments; + OSMWays=ways; + + LatMin=latmin; + LatMax=latmax; + LonMin=lonmin; + LonMax=lonmax; + + /* Iterate through the nodes and process them */ + + find_all_nodes(nodes,(callback_t)output_junctions); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Process a single node (called as a callback). + + index_t node The node to output. + + double latitude The latitude of the node. + + double longitude The longitude of the node. + ++++++++++++++++++++++++++++++++++++++*/ + +static void output_junctions(index_t node,double latitude,double longitude) +{ + Segment *segment; + Way *firstway; + int count=0,difference=0; + + segment=FirstSegment(OSMSegments,OSMNodes,node); + firstway=LookupWay(OSMWays,segment->way); + + do + { + Way *way=LookupWay(OSMWays,segment->way); + + if(IsNormalSegment(segment)) + count++; + + if(WaysCompare(firstway,way)) + difference=1; + + segment=NextSegment(OSMSegments,segment,node); + } + while(segment); + + if(count!=2 || difference) + printf("%.6f %.6f %d\n",radians_to_degrees(latitude),radians_to_degrees(longitude),count); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Output the data for super-nodes and super-segments. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + double latmin The minimum latitude. + + double latmax The maximum latitude. + + double lonmin The minimum longitude. + + double lonmax The maximum longitude. + ++++++++++++++++++++++++++++++++++++++*/ + +void OutputSuper(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax) +{ + /* Use local variables so that the callback doesn't need to pass them backwards and forwards */ + + OSMNodes=nodes; + OSMSegments=segments; + OSMWays=ways; + + LatMin=latmin; + LatMax=latmax; + LonMin=lonmin; + LonMax=lonmax; + + /* Iterate through the nodes and process them */ + + find_all_nodes(nodes,(callback_t)output_super); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Process a single node (called as a callback). + + index_t node The node to output. + + double latitude The latitude of the node. + + double longitude The longitude of the node. + ++++++++++++++++++++++++++++++++++++++*/ + +static void output_super(index_t node,double latitude,double longitude) +{ + Segment *segment; + + if(!IsSuperNode(OSMNodes,node)) + return; + + printf("%.6f %.6f n\n",radians_to_degrees(latitude),radians_to_degrees(longitude)); + + segment=FirstSegment(OSMSegments,OSMNodes,node); + + do + { + if(IsSuperSegment(segment)) + { + index_t othernode=OtherNode(segment,node); + double lat,lon; + + GetLatLong(OSMNodes,othernode,&lat,&lon); + + if(node>othernode || (latLatMax || lonLonMax)) + printf("%.6f %.6f s\n",radians_to_degrees(lat),radians_to_degrees(lon)); + } + + segment=NextSegment(OSMSegments,segment,node); + } + while(segment); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Output the data for one-way segments. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + double latmin The minimum latitude. + + double latmax The maximum latitude. + + double lonmin The minimum longitude. + + double lonmax The maximum longitude. + ++++++++++++++++++++++++++++++++++++++*/ + +void OutputOneway(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax) +{ + /* Use local variables so that the callback doesn't need to pass them backwards and forwards */ + + OSMNodes=nodes; + OSMSegments=segments; + OSMWays=ways; + + LatMin=latmin; + LatMax=latmax; + LonMin=lonmin; + LonMax=lonmax; + + /* Iterate through the nodes and process them */ + + find_all_nodes(nodes,(callback_t)output_oneway); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Process a single node (called as a callback). + + index_t node The node to output. + + double latitude The latitude of the node. + + double longitude The longitude of the node. + ++++++++++++++++++++++++++++++++++++++*/ + +static void output_oneway(index_t node,double latitude,double longitude) +{ + Segment *segment; + + segment=FirstSegment(OSMSegments,OSMNodes,node); + + do + { + if(IsNormalSegment(segment)) + { + index_t othernode=OtherNode(segment,node); + + if(node>othernode) + { + double lat,lon; + + GetLatLong(OSMNodes,othernode,&lat,&lon); + + if(IsOnewayFrom(segment,node)) + printf("%.6f %.6f %.6f %.6f\n",radians_to_degrees(latitude),radians_to_degrees(longitude),radians_to_degrees(lat),radians_to_degrees(lon)); + else if(IsOnewayFrom(segment,othernode)) + printf("%.6f %.6f %.6f %.6f\n",radians_to_degrees(lat),radians_to_degrees(lon),radians_to_degrees(latitude),radians_to_degrees(longitude)); + } + } + + segment=NextSegment(OSMSegments,segment,node); + } + while(segment); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Output the data for speed limits. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + double latmin The minimum latitude. + + double latmax The maximum latitude. + + double lonmin The minimum longitude. + + double lonmax The maximum longitude. + ++++++++++++++++++++++++++++++++++++++*/ + +void OutputSpeedLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax) +{ + /* Use local variables so that the callback doesn't need to pass them backwards and forwards */ + + OSMNodes=nodes; + OSMSegments=segments; + OSMWays=ways; + + LatMin=latmin; + LatMax=latmax; + LonMin=lonmin; + LonMax=lonmax; + + /* Iterate through the nodes and process them */ + + limit_type=SPEED_LIMIT; + + find_all_nodes(nodes,(callback_t)output_limits); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Output the data for weight limits. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + double latmin The minimum latitude. + + double latmax The maximum latitude. + + double lonmin The minimum longitude. + + double lonmax The maximum longitude. + ++++++++++++++++++++++++++++++++++++++*/ + +void OutputWeightLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax) +{ + /* Use local variables so that the callback doesn't need to pass them backwards and forwards */ + + OSMNodes=nodes; + OSMSegments=segments; + OSMWays=ways; + + LatMin=latmin; + LatMax=latmax; + LonMin=lonmin; + LonMax=lonmax; + + /* Iterate through the nodes and process them */ + + limit_type=WEIGHT_LIMIT; + + find_all_nodes(nodes,(callback_t)output_limits); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Output the data for height limits. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + double latmin The minimum latitude. + + double latmax The maximum latitude. + + double lonmin The minimum longitude. + + double lonmax The maximum longitude. + ++++++++++++++++++++++++++++++++++++++*/ + +void OutputHeightLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax) +{ + /* Use local variables so that the callback doesn't need to pass them backwards and forwards */ + + OSMNodes=nodes; + OSMSegments=segments; + OSMWays=ways; + + LatMin=latmin; + LatMax=latmax; + LonMin=lonmin; + LonMax=lonmax; + + /* Iterate through the nodes and process them */ + + limit_type=HEIGHT_LIMIT; + + find_all_nodes(nodes,(callback_t)output_limits); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Output the data for width limits. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + double latmin The minimum latitude. + + double latmax The maximum latitude. + + double lonmin The minimum longitude. + + double lonmax The maximum longitude. + ++++++++++++++++++++++++++++++++++++++*/ + +void OutputWidthLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax) +{ + /* Use local variables so that the callback doesn't need to pass them backwards and forwards */ + + OSMNodes=nodes; + OSMSegments=segments; + OSMWays=ways; + + LatMin=latmin; + LatMax=latmax; + LonMin=lonmin; + LonMax=lonmax; + + /* Iterate through the nodes and process them */ + + limit_type=WIDTH_LIMIT; + + find_all_nodes(nodes,(callback_t)output_limits); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Output the data for length limits. + + Nodes *nodes The set of nodes to use. + + Segments *segments The set of segments to use. + + Ways *ways The set of ways to use. + + double latmin The minimum latitude. + + double latmax The maximum latitude. + + double lonmin The minimum longitude. + + double lonmax The maximum longitude. + ++++++++++++++++++++++++++++++++++++++*/ + +void OutputLengthLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax) +{ + /* Use local variables so that the callback doesn't need to pass them backwards and forwards */ + + OSMNodes=nodes; + OSMSegments=segments; + OSMWays=ways; + + LatMin=latmin; + LatMax=latmax; + LonMin=lonmin; + LonMax=lonmax; + + /* Iterate through the nodes and process them */ + + limit_type=LENGTH_LIMIT; + + find_all_nodes(nodes,(callback_t)output_limits); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Process a single node (called as a callback). + + index_t node The node to output. + + double latitude The latitude of the node. + + double longitude The longitude of the node. + ++++++++++++++++++++++++++++++++++++++*/ + +static void output_limits(index_t node,double latitude,double longitude) +{ + Segment *segment,*segments[16]; + Way *ways[16]; + int limits[16]; + int count=0; + int i,j,same=0; + + segment=FirstSegment(OSMSegments,OSMNodes,node); + + do + { + if(IsNormalSegment(segment) && count<16) + { + ways [count]=LookupWay(OSMWays,segment->way); + segments[count]=segment; + + switch(limit_type) + { + case SPEED_LIMIT: limits[count]=ways[count]->speed; break; + case WEIGHT_LIMIT: limits[count]=ways[count]->weight; break; + case HEIGHT_LIMIT: limits[count]=ways[count]->height; break; + case WIDTH_LIMIT: limits[count]=ways[count]->width; break; + case LENGTH_LIMIT: limits[count]=ways[count]->length; break; + } + + if(limits[count] || ways[count]->typelatzero; + int32_t latmaxbin=latlong_to_bin(radians_to_latlong(LatMax))-nodes->latzero; + int32_t lonminbin=latlong_to_bin(radians_to_latlong(LonMin))-nodes->lonzero; + int32_t lonmaxbin=latlong_to_bin(radians_to_latlong(LonMax))-nodes->lonzero; + int latb,lonb,llbin; + index_t node; + + /* Loop through all of the nodes. */ + + for(latb=latminbin;latb<=latmaxbin;latb++) + for(lonb=lonminbin;lonb<=lonmaxbin;lonb++) + { + llbin=lonb*nodes->latbins+latb; + + if(llbin<0 || llbin>(nodes->latbins*nodes->lonbins)) + continue; + + for(node=nodes->offsets[llbin];nodeoffsets[llbin+1];node++) + { + double lat=latlong_to_radians(bin_to_latlong(nodes->latzero+latb)+off_to_latlong(nodes->nodes[node].latoffset)); + double lon=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb)+off_to_latlong(nodes->nodes[node].lonoffset)); + + if(lat>LatMin && latLonMin && lon. + ***************************************/ + + +#ifndef VISUALISER_H +#define VISUALISER_H /*+ To stop multiple inclusions. +*/ + +#include "types.h" + + +/* In visualiser.c */ + +void OutputJunctions(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax); + +void OutputSuper(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax); + +void OutputOneway(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax); + +void OutputSpeedLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax); + +void OutputWeightLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax); + +void OutputHeightLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax); +void OutputWidthLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax); +void OutputLengthLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax); + + +#endif /* VISUALISER_H */ diff --git a/src/ways.c b/src/ways.c new file mode 100644 index 0000000..3142415 --- /dev/null +++ b/src/ways.c @@ -0,0 +1,103 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/ways.c,v 1.44 2010/04/28 17:27:02 amb Exp $ + + Way data type functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include + +#include "functions.h" +#include "ways.h" + + +/*++++++++++++++++++++++++++++++++++++++ + Load in a way list from a file. + + Ways* LoadWayList Returns the way list. + + const char *filename The name of the file to load. + ++++++++++++++++++++++++++++++++++++++*/ + +Ways *LoadWayList(const char *filename) +{ + void *data; + Ways *ways; + + ways=(Ways*)malloc(sizeof(Ways)); + + data=MapFile(filename); + + /* Copy the Ways structure from the loaded data */ + + *ways=*((Ways*)data); + + /* Adjust the pointers in the Ways structure. */ + + ways->data =data; + ways->ways =(Way *)(data+sizeof(Ways)); + ways->names=(char*)(data+(sizeof(Ways)+ways->number*sizeof(Way))); + + return(ways); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Return 0 if the two ways are the same (in respect of their types and limits), + otherwise return positive or negative to allow sorting. + + int WaysCompare Returns a comparison. + + Way *way1 The first way. + + Way *way2 The second way. + ++++++++++++++++++++++++++++++++++++++*/ + +int WaysCompare(Way *way1,Way *way2) +{ + if(way1==way2) + return(0); + + if(way1->type!=way2->type) + return((int)way1->type - (int)way2->type); + + if(way1->allow!=way2->allow) + return((int)way1->allow - (int)way2->allow); + + if(way1->props!=way2->props) + return((int)way1->props - (int)way2->props); + + if(way1->speed!=way2->speed) + return((int)way1->speed - (int)way2->speed); + + if(way1->weight!=way2->weight) + return((int)way1->weight - (int)way2->weight); + + if(way1->height!=way2->height) + return((int)way1->height - (int)way2->height); + + if(way1->width!=way2->width) + return((int)way1->width - (int)way2->width); + + if(way1->length!=way2->length) + return((int)way1->length - (int)way2->length); + + return(0); +} diff --git a/src/ways.h b/src/ways.h new file mode 100644 index 0000000..7a5a94a --- /dev/null +++ b/src/ways.h @@ -0,0 +1,96 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/ways.h,v 1.37 2010/05/29 13:54:24 amb Exp $ + + A header file for the ways. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef WAYS_H +#define WAYS_H /*+ To stop multiple inclusions. +*/ + +#include + +#include "types.h" + + +/* Data structures */ + + +/*+ A structure containing a single way (members ordered to minimise overall size). +*/ +struct _Way +{ + index_t name; /*+ The offset of the name of the way in the names array. +*/ + + wayallow_t allow; /*+ The type of traffic allowed on the way. +*/ + + waytype_t type; /*+ The highway type of the way. +*/ + + wayprop_t props; /*+ The properties of the way. +*/ + + speed_t speed; /*+ The defined maximum speed limit of the way. +*/ + + weight_t weight; /*+ The defined maximum weight of traffic on the way. +*/ + height_t height; /*+ The defined maximum height of traffic on the way. +*/ + width_t width; /*+ The defined maximum width of traffic on the way. +*/ + length_t length; /*+ The defined maximum length of traffic on the way. +*/ +}; + + +/*+ A structure containing a set of ways (mmap format). +*/ +struct _Ways +{ + uint32_t number; /*+ How many ways are stored? +*/ + uint32_t onumber; /*+ How many ways were there originally? +*/ + + wayallow_t allow; /*+ The types of traffic that were seen when parsing. +*/ + wayprop_t props; /*+ The properties that were seen when parsing. +*/ + + Way *ways; /*+ An array of ways. +*/ + char *names; /*+ An array of characters containing the names. +*/ + + void *data; /*+ The memory mapped data. +*/ +}; + + +/* Macros */ + + +/*+ Return a Way* pointer given a set of ways and an index. +*/ +#define LookupWay(xxx,yyy) (&(xxx)->ways[yyy]) + +/*+ Return the raw name of a way given the Way pointer and a set of ways. +*/ +#define WayNameRaw(xxx,yyy) (&(xxx)->names[(yyy)->name]) + +/*+ Decide if a way has a name or not. +*/ +#define WayNamed(xxx,yyy) ((xxx)->names[(yyy)->name]) + +/*+ Return the name of a way if it has one or the name of the highway type otherwise. +*/ +#define WayNameHighway(xxx,yyy) (WayNamed(xxx,yyy)?WayNameRaw(xxx,yyy):HighwayName(HIGHWAY(yyy->type))) + + +/* Functions */ + + +Ways *LoadWayList(const char *filename); + +int WaysCompare(Way *way1,Way *way2); + + +#endif /* WAYS_H */ diff --git a/src/waysx.c b/src/waysx.c new file mode 100644 index 0000000..3c4635b --- /dev/null +++ b/src/waysx.c @@ -0,0 +1,623 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/waysx.c,v 1.38 2010/05/22 18:40:47 amb Exp $ + + Extended Way data type functions. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include + +#include "functions.h" +#include "waysx.h" +#include "ways.h" + + +/* Variables */ + +/*+ The command line '--slim' option. +*/ +extern int option_slim; + +/*+ The command line '--tmpdir' option or its default value. +*/ +extern char *option_tmpdirname; + +/*+ A temporary file-local variable for use by the sort functions. +*/ +static WaysX *sortwaysx; + +/* Functions */ + +static int sort_by_name_and_prop_and_id(WayX *a,WayX *b); +static int deduplicate_by_id(WayX *wayx,index_t index); + +static int sort_by_id(WayX *a,WayX *b); +static int index_by_id(WayX *wayx,index_t index); + + +/*++++++++++++++++++++++++++++++++++++++ + Allocate a new way list (create a new file or open an existing one). + + WaysX *NewWayList Returns the way list. + + int append Set to 1 if the file is to be opened for appending (now or later). + ++++++++++++++++++++++++++++++++++++++*/ + +WaysX *NewWayList(int append) +{ + WaysX *waysx; + + waysx=(WaysX*)calloc(1,sizeof(WaysX)); + + assert(waysx); /* Check calloc() worked */ + + waysx->filename=(char*)malloc(strlen(option_tmpdirname)+32); + + if(append) + sprintf(waysx->filename,"%s/ways.input.tmp",option_tmpdirname); + else + sprintf(waysx->filename,"%s/ways.%p.tmp",option_tmpdirname,waysx); + + if(append) + { + off_t size,position=0; + + waysx->fd=AppendFile(waysx->filename); + + size=SizeFile(waysx->filename); + + while(positionfd,position); + ReadFile(waysx->fd,&waysize,FILESORT_VARSIZE); + + waysx->xnumber++; + position+=waysize+FILESORT_VARSIZE; + } + + SeekFile(waysx->fd,size); + } + else + waysx->fd=OpenFile(waysx->filename); + + waysx->nfilename=(char*)malloc(strlen(option_tmpdirname)+32); + sprintf(waysx->nfilename,"%s/waynames.%p.tmp",option_tmpdirname,waysx); + + return(waysx); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Free a way list. + + WaysX *waysx The list to be freed. + + int keep Set to 1 if the file is to be kept. + ++++++++++++++++++++++++++++++++++++++*/ + +void FreeWayList(WaysX *waysx,int keep) +{ + if(!keep) + DeleteFile(waysx->filename); + + free(waysx->filename); + + if(waysx->idata) + free(waysx->idata); + + DeleteFile(waysx->nfilename); + + free(waysx->nfilename); + + free(waysx); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Append a way to a way list. + + void AppendWay Returns the newly appended way. + + WaysX* waysx The set of ways to process. + + way_t id The ID of the way. + + Way *way The way data itself. + + const char *name The name or reference of the way. + ++++++++++++++++++++++++++++++++++++++*/ + +void AppendWay(WaysX* waysx,way_t id,Way *way,const char *name) +{ + WayX wayx; + FILESORT_VARINT size; + + assert(!waysx->idata); /* Must not have idata filled in => unsorted */ + + wayx.id=id; + wayx.prop=0; + wayx.way=*way; + + size=sizeof(WayX)+strlen(name)+1; + + WriteFile(waysx->fd,&size,FILESORT_VARSIZE); + WriteFile(waysx->fd,&wayx,sizeof(WayX)); + WriteFile(waysx->fd,name,strlen(name)+1); + + waysx->xnumber++; +} + + +/*++++++++++++++++++++++++++++++++++++++ + Sort the list of ways. + + WaysX* waysx The set of ways to process. + ++++++++++++++++++++++++++++++++++++++*/ + +void SortWayList(WaysX* waysx) +{ + index_t i; + int fd,nfd; + char *names[2]={NULL,NULL}; + int namelen[2]={0,0}; + int nnames=0,nprops=0; + uint32_t lastlength=0; + Way lastway; + + /* Check the start conditions */ + + assert(!waysx->idata); /* Must not have idata filled in => unsorted */ + + /* Print the start message */ + + printf("Sorting Ways"); + fflush(stdout); + + /* Close the file and re-open it (finished appending) */ + + CloseFile(waysx->fd); + waysx->fd=ReOpenFile(waysx->filename); + + DeleteFile(waysx->filename); + + fd=OpenFile(waysx->filename); + + /* Sort the ways to allow compacting them and remove duplicates */ + + sortwaysx=waysx; + + filesort_vary(waysx->fd,fd,(int (*)(const void*,const void*))sort_by_name_and_prop_and_id,(int (*)(void*,index_t))deduplicate_by_id); + + /* Close the files */ + + CloseFile(waysx->fd); + CloseFile(fd); + + /* Print the final message */ + + printf("\rSorted Ways: Ways=%d Duplicates=%d\n",waysx->xnumber,waysx->xnumber-waysx->number); + fflush(stdout); + + + /* Print the start message */ + + printf("Compacting Ways: Ways=0 Names=0 Properties=0"); + fflush(stdout); + + /* Open the files */ + + waysx->fd=ReOpenFile(waysx->filename); + + DeleteFile(waysx->filename); + + fd=OpenFile(waysx->filename); + nfd=OpenFile(waysx->nfilename); + + /* Copy from the single file into two files and index as we go. */ + + for(i=0;inumber;i++) + { + WayX wayx; + FILESORT_VARINT size; + + ReadFile(waysx->fd,&size,FILESORT_VARSIZE); + + if(namelen[nnames%2]fd,&wayx,sizeof(WayX)); + ReadFile(waysx->fd,names[nnames%2],size-sizeof(WayX)); + + if(nnames==0 || strcmp(names[0],names[1])) + { + WriteFile(nfd,names[nnames%2],size-sizeof(WayX)); + + lastlength=waysx->nlength; + waysx->nlength+=size-sizeof(WayX); + + nnames++; + } + + wayx.way.name=lastlength; + + if(nprops==0 || wayx.way.name!=lastway.name || WaysCompare(&lastway,&wayx.way)) + { + lastway=wayx.way; + + waysx->cnumber++; + + nprops++; + } + + wayx.prop=nprops-1; + + WriteFile(fd,&wayx,sizeof(WayX)); + + if(!((i+1)%10000)) + { + printf("\rCompacting Ways: Ways=%d Names=%d Properties=%d",i+1,nnames,nprops); + fflush(stdout); + } + } + + if(names[0]) free(names[0]); + if(names[1]) free(names[1]); + + /* Close the files */ + + CloseFile(waysx->fd); + CloseFile(fd); + + waysx->fd=ReOpenFile(waysx->filename); + + CloseFile(nfd); + + /* Print the final message */ + + printf("\rCompacted Ways: Ways=%d Names=%d Properties=%d \n",waysx->number,nnames,nprops); + fflush(stdout); + + + /* Print the start message */ + + printf("Sorting Ways"); + fflush(stdout); + + /* Open the files */ + + waysx->fd=ReOpenFile(waysx->filename); + + DeleteFile(waysx->filename); + + fd=OpenFile(waysx->filename); + + /* Allocate the array of indexes */ + + waysx->idata=(way_t*)malloc(waysx->number*sizeof(way_t)); + + assert(waysx->idata); /* Check malloc() worked */ + + /* Sort the ways by index and index them */ + + sortwaysx=waysx; + + filesort_fixed(waysx->fd,fd,sizeof(WayX),(int (*)(const void*,const void*))sort_by_id,(int (*)(void*,index_t))index_by_id); + + /* Close the files and re-open them */ + + CloseFile(waysx->fd); + CloseFile(fd); + + waysx->fd=ReOpenFile(waysx->filename); + + /* Print the final message */ + + printf("\rSorted Ways: Ways=%d\n",waysx->number); + fflush(stdout); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Sort the ways into id order. + + int sort_by_id Returns the comparison of the id fields. + + WayX *a The first extended way. + + WayX *b The second extended way. + ++++++++++++++++++++++++++++++++++++++*/ + +static int sort_by_id(WayX *a,WayX *b) +{ + way_t a_id=a->id; + way_t b_id=b->id; + + if(a_idb_id) + return(1); + else + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Sort the ways into name, properties and id order. + + int sort_by_name_and_prop_and_id Returns the comparison of the name, properties and id fields. + + WayX *a The first extended Way. + + WayX *b The second extended Way. + ++++++++++++++++++++++++++++++++++++++*/ + +static int sort_by_name_and_prop_and_id(WayX *a,WayX *b) +{ + int compare; + char *a_name=(char*)a+sizeof(WayX); + char *b_name=(char*)b+sizeof(WayX); + + compare=strcmp(a_name,b_name); + + if(compare) + return(compare); + + compare=WaysCompare(&a->way,&b->way); + + if(compare) + return(compare); + + return(sort_by_id(a,b)); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Deduplicate the extended ways using the id after sorting. + + int deduplicate_by_id Return 1 if the value is to be kept, otherwise zero. + + WayX *wayx The extended way. + + index_t index The index of this way in the total. + ++++++++++++++++++++++++++++++++++++++*/ + +static int deduplicate_by_id(WayX *wayx,index_t index) +{ + static way_t previd; + + if(index==0 || wayx->id!=previd) + { + previd=wayx->id; + + sortwaysx->number++; + + return(1); + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Index the ways after sorting. + + int index_by_id Return 1 if the value is to be kept, otherwise zero. + + WayX *wayx The extended way. + + index_t index The index of this way in the total. + ++++++++++++++++++++++++++++++++++++++*/ + +static int index_by_id(WayX *wayx,index_t index) +{ + sortwaysx->idata[index]=wayx->id; + + return(1); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Find a particular way index. + + index_t IndexWayX Returns the index of the extended way with the specified id. + + WaysX* waysx The set of ways to process. + + way_t id The way id to look for. + ++++++++++++++++++++++++++++++++++++++*/ + +index_t IndexWayX(WaysX* waysx,way_t id) +{ + int start=0; + int end=waysx->number-1; + int mid; + + assert(waysx->idata); /* Must have idata filled in => sorted */ + + /* Binary search - search key exact match only is required. + * + * # <- start | Check mid and move start or end if it doesn't match + * # | + * # | Since an exact match is wanted we can set end=mid-1 + * # <- mid | or start=mid+1 because we know that mid doesn't match. + * # | + * # | Eventually either end=start or end=start+1 and one of + * # <- end | start or end is the wanted one. + */ + + if(endidata[start]) /* Check key is not before start */ + return(NO_WAY); + else if(id>waysx->idata[end]) /* Check key is not after end */ + return(NO_WAY); + else + { + do + { + mid=(start+end)/2; /* Choose mid point */ + + if(waysx->idata[mid]idata[mid]>id) /* Mid point is too high */ + end=mid-1; + else /* Mid point is correct */ + return(mid); + } + while((end-start)>1); + + if(waysx->idata[start]==id) /* Start is correct */ + return(start); + + if(waysx->idata[end]==id) /* End is correct */ + return(end); + } + + return(NO_WAY); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Lookup a particular way. + + WayX *LookupWayX Returns a pointer to the extended way with the specified id. + + WaysX* waysx The set of ways to process. + + index_t index The way index to look for. + + int position The position in the cache to use. + ++++++++++++++++++++++++++++++++++++++*/ + +WayX *LookupWayX(WaysX* waysx,index_t index,int position) +{ + assert(index!=NO_WAY); /* Must be a valid way */ + + if(option_slim) + { + SeekFile(waysx->fd,index*sizeof(WayX)); + + ReadFile(waysx->fd,&waysx->cached[position-1],sizeof(WayX)); + + return(&waysx->cached[position-1]); + } + else + { + return(&waysx->xdata[index]); + } +} + + +/*++++++++++++++++++++++++++++++++++++++ + Save the way list to a file. + + WaysX* waysx The set of ways to save. + + const char *filename The name of the file to save. + ++++++++++++++++++++++++++++++++++++++*/ + +void SaveWayList(WaysX* waysx,const char *filename) +{ + index_t i; + int fd,nfd; + int position=0; + Ways *ways; + + printf("Writing Ways: Ways=0"); + fflush(stdout); + + if(!option_slim) + waysx->xdata=MapFile(waysx->filename); + + /* Fill in a Ways structure with the offset of the real data in the file after + the Way structure itself. */ + + ways=calloc(1,sizeof(Ways)); + + assert(ways); /* Check calloc() worked */ + + ways->number=waysx->cnumber; + ways->onumber=waysx->number; + + ways->allow=0; + ways->props=0; + + ways->data=NULL; + ways->ways=NULL; + ways->names=NULL; + + /* Write out the Ways structure and then the real data. */ + + fd=OpenFile(filename); + + for(i=0;inumber;i++) + { + WayX *wayx=LookupWayX(waysx,i,1); + + ways->allow|=wayx->way.allow; + ways->props|=wayx->way.props; + + SeekFile(fd,sizeof(Ways)+wayx->prop*sizeof(Way)); + WriteFile(fd,&wayx->way,sizeof(Way)); + + if(!((i+1)%10000)) + { + printf("\rWriting Ways: Ways=%d",i+1); + fflush(stdout); + } + } + + SeekFile(fd,0); + WriteFile(fd,ways,sizeof(Ways)); + + if(!option_slim) + waysx->xdata=UnmapFile(waysx->filename); + + SeekFile(fd,sizeof(Ways)+ways->number*sizeof(Way)); + + nfd=ReOpenFile(waysx->nfilename); + + while(positionnlength) + { + int len=1024; + char temp[1024]; + + if((waysx->nlength-position)<1024) + len=waysx->nlength-position; + + ReadFile(nfd,temp,len); + WriteFile(fd,temp,len); + + position+=len; + } + + CloseFile(nfd); + + CloseFile(fd); + + printf("\rWrote Ways: Ways=%d \n",waysx->number); + fflush(stdout); + + /* Free the fake Ways */ + + free(ways); +} diff --git a/src/waysx.h b/src/waysx.h new file mode 100644 index 0000000..1aa8b62 --- /dev/null +++ b/src/waysx.h @@ -0,0 +1,87 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/waysx.h,v 1.21 2010/05/22 18:40:47 amb Exp $ + + A header file for the extended Ways structure. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2008-2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef WAYSX_H +#define WAYSX_H /*+ To stop multiple inclusions. +*/ + +#include + +#include "typesx.h" +#include "types.h" +#include "ways.h" + + +/* Data structures */ + + +/*+ An extended structure containing a single way. +*/ +struct _WayX +{ + way_t id; /*+ The way identifier. +*/ + + index_t prop; /*+ The index of the properties of the way in the compacted list. +*/ + + Way way; /*+ The real Way data. +*/ +}; + + +/*+ A structure containing a set of ways (memory format). +*/ +struct _WaysX +{ + char *filename; /*+ The name of the temporary file (for the WaysX). +*/ + int fd; /*+ The file descriptor of the temporary file (for the WaysX). +*/ + + uint32_t xnumber; /*+ The number of unsorted extended ways. +*/ + + WayX *xdata; /*+ The extended data for the Ways (sorted). +*/ + WayX cached[2]; /*+ Two cached ways read from the file in slim mode. +*/ + + uint32_t number; /*+ How many entries are still useful? +*/ + + uint32_t cnumber; /*+ How many entries are there after compacting? +*/ + + index_t *idata; /*+ The index of the extended data for the Ways (sorted by ID). +*/ + + char *nfilename; /*+ The name of the temporary file (for the names). +*/ + + uint32_t nlength; /*+ How long is the string of name entries? +*/ +}; + + +/* Functions */ + + +WaysX *NewWayList(int append); +void FreeWayList(WaysX *waysx,int keep); + +void SaveWayList(WaysX *waysx,const char *filename); + +index_t IndexWayX(WaysX* waysx,way_t id); +WayX *LookupWayX(WaysX* waysx,index_t index,int position); + +void AppendWay(WaysX* waysx,way_t id,Way *way,const char *name); + +void SortWayList(WaysX *waysx); + +#endif /* WAYSX_H */ diff --git a/src/xml/Makefile b/src/xml/Makefile new file mode 100644 index 0000000..81bfd04 --- /dev/null +++ b/src/xml/Makefile @@ -0,0 +1,134 @@ +# $Header: /home/amb/routino/src/xml/RCS/Makefile,v 1.10 2010/07/07 17:26:24 amb Exp $ +# +# XML test programs Makefile +# +# Part of the Routino routing software. +# +# This file Copyright 2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Programs + +CC=gcc +LD=gcc + +# Program options + +CFLAGS=-Wall -Wmissing-prototypes -O0 -g +LDFLAGS=-lm -lc + +# Required to use stdio with files > 2GiB on 32-bit system. + +FLAGS64=-D_FILE_OFFSET_BITS=64 + +# Compilation targets + +XMLDIR=../../xml + +X=$(notdir $(wildcard $(XMLDIR)/*.xsd)) +C=$(foreach f,$(X),$(addsuffix -skeleton.c,$(basename $f))) +D=$(foreach f,$(C),$(addprefix .deps/,$(addsuffix .d,$(basename $f)))) +O=$(foreach f,$(C),$(addsuffix .o,$(basename $f))) +E=$(foreach f,$(C),$(basename $f)) + +EXE=xsd-to-xmlparser + +######## + +all : $(EXE) $(C) $(E) + @true + +######## + +xsd-to-xmlparser : xsd-to-xmlparser.o ../xmlparse.o + $(LD) xsd-to-xmlparser.o ../xmlparse.o -o $@ $(LDFLAGS) + +######## + +%-skeleton.c : $(XMLDIR)/%.xsd xsd-to-xmlparser + -./xsd-to-xmlparser < $< > $@ + @test -s $@ || rm $@ + +%-skeleton : %-skeleton.o ../xmlparse.o + $(LD) $< ../xmlparse.o -o $@ $(LDFLAGS) + +.SECONDARY : $(O) + +######## + +../xmlparse.o : ../xmlparse.c ../xmlparse.h + cd .. && $(MAKE) xmlparse.o + +../xmlparse.c : ../xmlparse.l + cd .. && $(MAKE) xmlparse.o + +######## + +%.o : %.c + $(CC) -c $(CFLAGS) $(FLAGS64) -I.. $< -o $@ -MMD -MP -MF $(addprefix .deps/,$(addsuffix .d,$(basename $<))) + +######## + +test : all test-skeleton .FORCE + @status=true ;\ + echo "" ;\ + for good in test/good*.xml; do \ + echo "Testing: $$good ... " ;\ + if ./test-skeleton < $$good > /dev/null; then echo "... passed"; else echo "... FAILED"; status=false; fi ;\ + echo "" ;\ + done ;\ + for bad in test/bad*.xml; do \ + echo "Testing: $$bad ... " ;\ + if ./test-skeleton < $$bad > /dev/null; then echo "... FAILED"; status=false; else echo "... passed"; fi ;\ + echo "" ;\ + done ;\ + if $$status; then echo "Success: all tests passed"; else echo "Warning: Some tests FAILED"; fi ;\ + $$status + +test-skeleton : test-skeleton.o + $(LD) $< ../xmlparse.o -o $@ $(LDFLAGS) + +test-skeleton.c : test/test.xsd xsd-to-xmlparser + ./xsd-to-xmlparser < $< | sed -e 's/XMLPARSE_UNKNOWN_ATTR_WARN/XMLPARSE_UNKNOWN_ATTR_ERROR/' > $@ + +######## + +clean: + rm -f *.o + rm -f *~ + +######## + +distclean: clean + -rm -f $(EXE) + -rm -f $(E) test-skeleton + -rm -f $(D) .deps/test-skeleton.d + -rm -f $(C) test-skeleton.c + -rm -fr .deps + +######## + +.deps : .FORCE + @[ -d .deps ] || mkdir $@ + +$(D) : .deps + @touch $@ + +include $(D) + +######## + +.FORCE : diff --git a/src/xml/test/bad-attr-character-ref.xml b/src/xml/test/bad-attr-character-ref.xml new file mode 100644 index 0000000..6ab951c --- /dev/null +++ b/src/xml/test/bad-attr-character-ref.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-attr-entity-ref.xml b/src/xml/test/bad-attr-entity-ref.xml new file mode 100644 index 0000000..7a3a5ba --- /dev/null +++ b/src/xml/test/bad-attr-entity-ref.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-cdata-start.xml b/src/xml/test/bad-cdata-start.xml new file mode 100644 index 0000000..cd9c4ed --- /dev/null +++ b/src/xml/test/bad-cdata-start.xml @@ -0,0 +1,13 @@ + + + + + + + + + ]]> + + + + diff --git a/src/xml/test/bad-comment-ends-triple-dash.xml b/src/xml/test/bad-comment-ends-triple-dash.xml new file mode 100644 index 0000000..17a105a --- /dev/null +++ b/src/xml/test/bad-comment-ends-triple-dash.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-double-quote-attr-amp.xml b/src/xml/test/bad-double-quote-attr-amp.xml new file mode 100644 index 0000000..fd58f46 --- /dev/null +++ b/src/xml/test/bad-double-quote-attr-amp.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-double-quote-attr-left-angle.xml b/src/xml/test/bad-double-quote-attr-left-angle.xml new file mode 100644 index 0000000..c6dc80b --- /dev/null +++ b/src/xml/test/bad-double-quote-attr-left-angle.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-double-quote-attr-right-angle.xml b/src/xml/test/bad-double-quote-attr-right-angle.xml new file mode 100644 index 0000000..f4c0428 --- /dev/null +++ b/src/xml/test/bad-double-quote-attr-right-angle.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-early-end-of-file.xml b/src/xml/test/bad-early-end-of-file.xml new file mode 100644 index 0000000..7990b44 --- /dev/null +++ b/src/xml/test/bad-early-end-of-file.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/xml/test/bad-end-tag-space-at-begin1.xml b/src/xml/test/bad-end-tag-space-at-begin1.xml new file mode 100644 index 0000000..ca9f42a --- /dev/null +++ b/src/xml/test/bad-end-tag-space-at-begin1.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-end-tag-space-at-begin2.xml b/src/xml/test/bad-end-tag-space-at-begin2.xml new file mode 100644 index 0000000..aeae822 --- /dev/null +++ b/src/xml/test/bad-end-tag-space-at-begin2.xml @@ -0,0 +1,12 @@ + + + + + + + + + + < /level1> + + diff --git a/src/xml/test/bad-end-tag-space-at-end.xml b/src/xml/test/bad-end-tag-space-at-end.xml new file mode 100644 index 0000000..b060674 --- /dev/null +++ b/src/xml/test/bad-end-tag-space-at-end.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-end-tag-with-attr.xml b/src/xml/test/bad-end-tag-with-attr.xml new file mode 100644 index 0000000..dab05b1 --- /dev/null +++ b/src/xml/test/bad-end-tag-with-attr.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-single-quote-attr-amp.xml b/src/xml/test/bad-single-quote-attr-amp.xml new file mode 100644 index 0000000..30200c5 --- /dev/null +++ b/src/xml/test/bad-single-quote-attr-amp.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-single-quote-attr-left-angle.xml b/src/xml/test/bad-single-quote-attr-left-angle.xml new file mode 100644 index 0000000..10c8ba0 --- /dev/null +++ b/src/xml/test/bad-single-quote-attr-left-angle.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-single-quote-attr-right-angle.xml b/src/xml/test/bad-single-quote-attr-right-angle.xml new file mode 100644 index 0000000..d043b8a --- /dev/null +++ b/src/xml/test/bad-single-quote-attr-right-angle.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-start-tag-space-at-begin.xml b/src/xml/test/bad-start-tag-space-at-begin.xml new file mode 100644 index 0000000..02e81bb --- /dev/null +++ b/src/xml/test/bad-start-tag-space-at-begin.xml @@ -0,0 +1,12 @@ + + + + + + + < level1> + + + + + diff --git a/src/xml/test/bad-tag-attr-no-quotes.xml b/src/xml/test/bad-tag-attr-no-quotes.xml new file mode 100644 index 0000000..bdc476e --- /dev/null +++ b/src/xml/test/bad-tag-attr-no-quotes.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-tag-attr-space-after-equal.xml b/src/xml/test/bad-tag-attr-space-after-equal.xml new file mode 100644 index 0000000..1ba6847 --- /dev/null +++ b/src/xml/test/bad-tag-attr-space-after-equal.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-tag-attr-space-before-equal.xml b/src/xml/test/bad-tag-attr-space-before-equal.xml new file mode 100644 index 0000000..06236c6 --- /dev/null +++ b/src/xml/test/bad-tag-attr-space-before-equal.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-tag-level-nesting.xml b/src/xml/test/bad-tag-level-nesting.xml new file mode 100644 index 0000000..dba5592 --- /dev/null +++ b/src/xml/test/bad-tag-level-nesting.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-unbalanced-tag-start-end.xml b/src/xml/test/bad-unbalanced-tag-start-end.xml new file mode 100644 index 0000000..e375475 --- /dev/null +++ b/src/xml/test/bad-unbalanced-tag-start-end.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-unexpected-attribute-name.xml b/src/xml/test/bad-unexpected-attribute-name.xml new file mode 100644 index 0000000..9b17fdd --- /dev/null +++ b/src/xml/test/bad-unexpected-attribute-name.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-unexpected-end-tag.xml b/src/xml/test/bad-unexpected-end-tag.xml new file mode 100644 index 0000000..219d79b --- /dev/null +++ b/src/xml/test/bad-unexpected-end-tag.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-unexpected-left-angle.xml b/src/xml/test/bad-unexpected-left-angle.xml new file mode 100644 index 0000000..d8ecbea --- /dev/null +++ b/src/xml/test/bad-unexpected-left-angle.xml @@ -0,0 +1,13 @@ + + + + + + + + + < + + + + diff --git a/src/xml/test/bad-unexpected-right-angle.xml b/src/xml/test/bad-unexpected-right-angle.xml new file mode 100644 index 0000000..358524e --- /dev/null +++ b/src/xml/test/bad-unexpected-right-angle.xml @@ -0,0 +1,13 @@ + + + + + + + + + > + + + + diff --git a/src/xml/test/bad-xml-header-at-begin.xml b/src/xml/test/bad-xml-header-at-begin.xml new file mode 100644 index 0000000..e19fc5f --- /dev/null +++ b/src/xml/test/bad-xml-header-at-begin.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-xml-header-at-end.xml b/src/xml/test/bad-xml-header-at-end.xml new file mode 100644 index 0000000..2a3857d --- /dev/null +++ b/src/xml/test/bad-xml-header-at-end.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/bad-xml-header-not-first.xml b/src/xml/test/bad-xml-header-not-first.xml new file mode 100644 index 0000000..cdabc6b --- /dev/null +++ b/src/xml/test/bad-xml-header-not-first.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/xml/test/good.xml b/src/xml/test/good.xml new file mode 100644 index 0000000..f7e207c --- /dev/null +++ b/src/xml/test/good.xml @@ -0,0 +1,13 @@ + + + + + + + + + ]]> + + + + diff --git a/src/xml/test/test.xsd b/src/xml/test/test.xsd new file mode 100644 index 0000000..fce04ee --- /dev/null +++ b/src/xml/test/test.xsd @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/xml/xsd-to-xmlparser.c b/src/xml/xsd-to-xmlparser.c new file mode 100644 index 0000000..6e15d9d --- /dev/null +++ b/src/xml/xsd-to-xmlparser.c @@ -0,0 +1,514 @@ +/*************************************** + $Header: /home/amb/routino/src/xml/RCS/xsd-to-xmlparser.c,v 1.10 2010/04/23 18:41:20 amb Exp $ + + An XML parser for simplified XML Schema Definitions to create XML parser skeletons. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include + +#include "xmlparse.h" + + +/*+ A forward definition of the xmltagx +*/ +typedef struct _xmltagx xmltagx; + + +/*+ A structure to hold the extended definition of a tag. +*/ +struct _xmltagx +{ + char *name; /*+ The name of the tag. +*/ + char *type; /*+ The type of the tag. +*/ + + int nattributes; /*+ The number of valid attributes for the tag. +*/ + char *attributes[XMLPARSE_MAX_ATTRS]; /*+ The valid attributes for the tag. +*/ + + int nsubtagsx; /*+ The number of valid attributes for the tag. +*/ + xmltagx *subtagsx[XMLPARSE_MAX_SUBTAGS]; /*+ The list of types for the subtags contained within this one. +*/ +}; + + +/* The local variables and functions */ + +int ntagsx=0; +xmltagx **tagsx=NULL; +char *currenttype=NULL; + +static char *safe(const char *name); + + +/* The XML tag processing function prototypes */ + +static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding); +static int schemaType_function(const char *_tag_,int _type_,const char *elementFormDefault,const char *xmlns_xsd); +static int complexType_function(const char *_tag_,int _type_,const char *name); +static int attributeType_function(const char *_tag_,int _type_,const char *name,const char *type); +static int sequenceType_function(const char *_tag_,int _type_); +static int elementType_function(const char *_tag_,int _type_,const char *name,const char *type,const char *minOccurs,const char *maxOccurs); + + +/* The XML tag definitions */ + +/*+ The elementType type tag. +*/ +static xmltag elementType_tag= + {"xsd:element", + 4, {"name","type","minOccurs","maxOccurs"}, + elementType_function, + {NULL}}; + +/*+ The sequenceType type tag. +*/ +static xmltag sequenceType_tag= + {"xsd:sequence", + 0, {NULL}, + sequenceType_function, + {&elementType_tag,NULL}}; + +/*+ The attributeType type tag. +*/ +static xmltag attributeType_tag= + {"xsd:attribute", + 2, {"name","type"}, + attributeType_function, + {NULL}}; + +/*+ The complexType type tag. +*/ +static xmltag complexType_tag= + {"xsd:complexType", + 1, {"name"}, + complexType_function, + {&sequenceType_tag,&attributeType_tag,NULL}}; + +/*+ The schemaType type tag. +*/ +static xmltag schemaType_tag= + {"xsd:schema", + 2, {"elementFormDefault","xmlns:xsd"}, + schemaType_function, + {&elementType_tag,&complexType_tag,NULL}}; + +/*+ The xmlDeclaration type tag. +*/ +static xmltag xmlDeclaration_tag= + {"xml", + 2, {"version","encoding"}, + xmlDeclaration_function, + {NULL}}; + + +/*+ The complete set of tags at the top level. +*/ +static xmltag *xml_toplevel_tags[]={&xmlDeclaration_tag,&schemaType_tag,NULL}; + + +/* The XML tag processing functions */ + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the elementType XSD type is seen + + int elementType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *name The contents of the 'name' attribute (or NULL if not defined). + + const char *type The contents of the 'type' attribute (or NULL if not defined). + + const char *minOccurs The contents of the 'minOccurs' attribute (or NULL if not defined). + + const char *maxOccurs The contents of the 'maxOccurs' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int elementType_function(const char *_tag_,int _type_,const char *name,const char *type,const char *minOccurs,const char *maxOccurs) +{ + xmltagx *tagx=NULL; + int i; + + if(_type_==XMLPARSE_TAG_END) + return(0); + + for(i=0;itype) && !strcmp(name,tagsx[i]->name)) + tagx=tagsx[i]; + + if(!tagx) + { + ntagsx++; + tagsx=(xmltagx**)realloc((void*)tagsx,ntagsx*sizeof(xmltagx*)); + + tagsx[ntagsx-1]=(xmltagx*)calloc(1,sizeof(xmltagx)); + tagsx[ntagsx-1]->name=strcpy(malloc(strlen(name)+1),name); + tagsx[ntagsx-1]->type=strcpy(malloc(strlen(type)+1),type); + + tagx=tagsx[ntagsx-1]; + } + + if(!currenttype) + return(0); + + for(i=0;itype,currenttype)) + { + tagsx[i]->subtagsx[tagsx[i]->nsubtagsx]=tagx; + tagsx[i]->nsubtagsx++; + + if(tagsx[i]->nsubtagsx==XMLPARSE_MAX_SUBTAGS) + {fprintf(stderr,"Too many subtags seen for type '%s'.\n",currenttype); exit(1);} + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the sequenceType XSD type is seen + + int sequenceType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + ++++++++++++++++++++++++++++++++++++++*/ + +static int sequenceType_function(const char *_tag_,int _type_) +{ + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the attributeType XSD type is seen + + int attributeType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *name The contents of the 'name' attribute (or NULL if not defined). + + const char *type The contents of the 'type' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int attributeType_function(const char *_tag_,int _type_,const char *name,const char *type) +{ + int i; + + if(_type_==XMLPARSE_TAG_END) + return(0); + + for(i=0;itype,currenttype)) + { + tagsx[i]->attributes[tagsx[i]->nattributes]=strcpy(malloc(strlen(name)+1),name); + tagsx[i]->nattributes++; + + if(tagsx[i]->nattributes==XMLPARSE_MAX_ATTRS) + {fprintf(stderr,"Too many attributes seen for type '%s'.\n",currenttype); exit(1);} + } + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the complexType XSD type is seen + + int complexType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *name The contents of the 'name' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int complexType_function(const char *_tag_,int _type_,const char *name) +{ + if(_type_==XMLPARSE_TAG_END) + return(0); + + currenttype=strcpy(realloc(currenttype,strlen(name)+1),name); + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the schemaType XSD type is seen + + int schemaType_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *elementFormDefault The contents of the 'elementFormDefault' attribute (or NULL if not defined). + + const char *xmlns_xsd The contents of the 'xmlns:xsd' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int schemaType_function(const char *_tag_,int _type_,const char *elementFormDefault,const char *xmlns_xsd) +{ + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The function that is called when the XML declaration is seen + + int xmlDeclaration_function Returns 0 if no error occured or something else otherwise. + + const char *_tag_ Set to the name of the element tag that triggered this function call. + + int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. + + const char *version The contents of the 'version' attribute (or NULL if not defined). + + const char *encoding The contents of the 'encoding' attribute (or NULL if not defined). + ++++++++++++++++++++++++++++++++++++++*/ + +static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding) +{ + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + The XML Schema Definition XML parser and C program generator. + ++++++++++++++++++++++++++++++++++++++*/ + +int main(int argc,char **argv) +{ + int i,j,k; + + if(ParseXML(stdin,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE)) + { + fprintf(stderr,"Cannot parse XML file - exiting.\n"); + exit(1); + } + + /* Add the XML declaration as a tag. */ + + currenttype=NULL; + elementType_function("xsd:element",XMLPARSE_TAG_START|XMLPARSE_TAG_END,"xml","xmlDeclaration",NULL,NULL); + complexType_function("xsd:complexType",XMLPARSE_TAG_START,"xmlDeclaration"); + attributeType_function("xsd:attribute",XMLPARSE_TAG_START|XMLPARSE_TAG_END,"version",NULL); + attributeType_function("xsd:attribute",XMLPARSE_TAG_START|XMLPARSE_TAG_END,"encoding",NULL); + complexType_function("xsd:complexType",XMLPARSE_TAG_END,NULL); + + /* Sort the tags */ + + sorttags: + + for(i=0;insubtagsx;j++) + { + for(k=0;ksubtagsx[j]==tagsx[k]) + break; + + if(i\n"); + printf("\n"); + printf("#include \"xmlparse.h\"\n"); + + /* Print the function prototypes */ + + printf("\n"); + printf("\n"); + printf("/* The XML tag processing function prototypes */\n"); + printf("\n"); + + for(i=ntagsx-1;i>=0;i--) + { + printf("static int %s_function(const char *_tag_,int _type_",safe(tagsx[i]->type)); + + for(j=0;jnattributes;j++) + printf(",const char *%s",safe(tagsx[i]->attributes[j])); + + printf(");\n"); + } + + /* Print the xmltag variables */ + + printf("\n"); + printf("\n"); + printf("/* The XML tag definitions */\n"); + + for(i=0;itype); + printf("static xmltag %s_tag=\n",safe(tagsx[i]->type)); + printf(" {\"%s\",\n",tagsx[i]->name); + + printf(" %d, {",tagsx[i]->nattributes); + for(j=0;jnattributes;j++) + printf("%s\"%s\"",(j?",":""),tagsx[i]->attributes[j]); + printf("%s},\n",(tagsx[i]->nattributes?"":"NULL")); + + printf(" %s_function,\n",safe(tagsx[i]->type)); + + printf(" {"); + for(j=0;jnsubtagsx;j++) + printf("&%s_tag,",safe(tagsx[i]->subtagsx[j]->type)); + printf("NULL}};\n"); + } + + printf("\n"); + printf("\n"); + printf("/*+ The complete set of tags at the top level. +*/\n"); + printf("static xmltag *xml_toplevel_tags[]={"); + printf("&%s_tag,",safe(tagsx[ntagsx-1]->type)); + printf("&%s_tag,",safe(tagsx[ntagsx-2]->type)); + printf("NULL};\n"); + + /* Print the functions */ + + printf("\n"); + printf("\n"); + printf("/* The XML tag processing functions */\n"); + + for(i=0;itype); + printf("\n"); + printf(" int %s_function Returns 0 if no error occured or something else otherwise.\n",safe(tagsx[i]->type)); + printf("\n"); + printf(" const char *_tag_ Set to the name of the element tag that triggered this function call.\n"); + printf("\n"); + printf(" int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.\n"); + for(j=0;jnattributes;j++) + { + printf("\n"); + printf(" const char *%s The contents of the '%s' attribute (or NULL if not defined).\n",safe(tagsx[i]->attributes[j]),tagsx[i]->attributes[j]); + } + printf(" ++++++++++++++++++++++++++++++++++++++*/\n"); + printf("\n"); + + printf("static int %s_function(const char *_tag_,int _type_",safe(tagsx[i]->type)); + + for(j=0;jnattributes;j++) + printf(",const char *%s",safe(tagsx[i]->attributes[j])); + + printf(")\n"); + + printf("{\n"); + + if(i==(ntagsx-1)) /* XML tag */ + { + printf(" printf(\"nattributes;j++) + { + char *safename=safe(tagsx[i]->attributes[j]); + printf(" if(%s) printf(\" %s=\\\"%%s\\\"\",ParseXML_Encode_Safe_XML(%s));\n",safename,tagsx[i]->attributes[j],safename); + } + printf(" printf(\" ?>\\n\");\n"); + } + else + { + printf(" printf(\"<%%s%%s\",(_type_==XMLPARSE_TAG_END)?\"/\":\"\",_tag_);\n"); + for(j=0;jnattributes;j++) + { + char *safename=safe(tagsx[i]->attributes[j]); + printf(" if(%s) printf(\" %s=\\\"%%s\\\"\",ParseXML_Encode_Safe_XML(%s));\n",safename,tagsx[i]->attributes[j],safename); + } + printf(" printf(\"%%s>\\n\",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?\" /\":\"\");\n"); + } + + printf(" return(0);\n"); + printf("}\n"); + } + + /* Print the main function */ + + printf("\n"); + printf("\n"); + printf("/*++++++++++++++++++++++++++++++++++++++\n"); + printf(" A skeleton XML parser.\n"); + printf(" ++++++++++++++++++++++++++++++++++++++*/\n"); + printf("\n"); + printf("int main(int argc,char **argv)\n"); + printf("{\n"); + printf(" if(ParseXML(stdin,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_WARN))\n"); + printf(" return(1);\n"); + printf(" else\n"); + printf(" return(0);\n"); + printf("}\n"); + + return(0); +} + + +/*++++++++++++++++++++++++++++++++++++++ + A function to return a safe C identifier from an XML tag or attribute name. + + char *safe Returns the safe name in a private string (only use once). + + const char *name The name to convert. + ++++++++++++++++++++++++++++++++++++++*/ + +static char *safe(const char *name) +{ + static char *safe=NULL; + int i; + + safe=realloc(safe,strlen(name)+1); + + for(i=0;name[i];i++) + if(isalnum(name[i])) + safe[i]=name[i]; + else + safe[i]='_'; + + safe[i]=0; + + return(safe); +} diff --git a/src/xmlparse.h b/src/xmlparse.h new file mode 100644 index 0000000..93ff0c9 --- /dev/null +++ b/src/xmlparse.h @@ -0,0 +1,136 @@ +/*************************************** + $Header: /home/amb/routino/src/RCS/xmlparse.h,v 1.12 2010/05/14 17:55:56 amb Exp $ + + A simple XML parser + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#ifndef XMLPARSE_H +#define XMLPARSE_H /*+ To stop multiple inclusions. +*/ + +#include + + +/*+ The maximum number of attributes per tag. +*/ +#define XMLPARSE_MAX_ATTRS 16 + +/*+ The maximum number of subtags per tag. +*/ +#define XMLPARSE_MAX_SUBTAGS 16 + +/*+ A flag to indicate the start and/or end of a tag. +*/ +#define XMLPARSE_TAG_START 1 +#define XMLPARSE_TAG_END 2 + + +/*+ A forward definition of the xmltag +*/ +typedef struct _xmltag xmltag; + + +/*+ A structure to hold the definition of a tag. +*/ +struct _xmltag +{ + char *name; /*+ The name of the tag. +*/ + + int nattributes; /*+ The number of valid attributes for the tag. +*/ + char *attributes[XMLPARSE_MAX_ATTRS]; /*+ The valid attributes for the tag. +*/ + + int (*callback)(); /*+ The callback function when the tag is seen. +*/ + + xmltag *subtags[XMLPARSE_MAX_SUBTAGS]; /*+ The list of valid tags contained within this one (null terminated). +*/ +}; + + +/* XML Parser options */ + +#define XMLPARSE_UNKNOWN_ATTRIBUTES 0x0003 +#define XMLPARSE_UNKNOWN_ATTR_ERROR 0x0000 /* Flag an error and exit. */ +#define XMLPARSE_UNKNOWN_ATTR_ERRNONAME 0x0001 /* Flag an error and exit unless a namespace is specified. */ +#define XMLPARSE_UNKNOWN_ATTR_WARN 0x0002 /* Warn about the problem and continue. */ +#define XMLPARSE_UNKNOWN_ATTR_IGNORE 0x0003 /* Ignore the potential problem. */ + +#define XMLPARSE_RETURN_ATTR_ENCODED 0x0004 /* Return the XML attribute strings without decoding them. */ + + +/* XML parser functions */ + +int ParseXML(FILE *file,xmltag **tags,int options); + +unsigned long ParseXML_LineNumber(void); + +char *ParseXML_Decode_Entity_Ref(const char *string); +char *ParseXML_Decode_Char_Ref(const char *string); +char *ParseXML_Encode_Safe_XML(const char *string); + +int ParseXML_GetInteger(const char *string,int *number); +int ParseXML_GetFloating(const char *string,double *number); + +/* Macros to simplify the callback functions */ + +#define XMLPARSE_MESSAGE(tag,message) \ + do \ + { \ + fprintf(stderr,"XML Parser: Error on line %ld: " message " in <%s> tag.\n",ParseXML_LineNumber(),tag); \ + return(1); \ + } \ + while(0) + +#define XMLPARSE_INVALID(tag,attribute) \ + do \ + { \ + fprintf(stderr,"XML Parser: Error on line %ld: Invalid value for '" #attribute "' attribute in <%s> tag.\n",ParseXML_LineNumber(),tag); \ + return(1); \ + } \ + while(0) + +#define XMLPARSE_ASSERT_STRING(tag,attribute) \ + do \ + { \ + if(!attribute) \ + { \ + fprintf(stderr,"XML Parser: Error on line %ld: '" #attribute "' attribute must be specified in <%s> tag.\n",ParseXML_LineNumber(),tag); \ + return(1); \ + } \ + } \ + while(0) + +#define XMLPARSE_ASSERT_INTEGER(tag,attribute,result) \ + do \ + { \ + if(!attribute || !*attribute || !ParseXML_GetInteger(attribute,&result)) \ + { \ + fprintf(stderr,"XML Parser: Error on line %ld: '" #attribute "' attribute must be a integer in <%s> tag.\n",ParseXML_LineNumber(),tag); \ + return(1); \ + } \ + } \ + while(0) + +#define XMLPARSE_ASSERT_FLOATING(tag,attribute,result) \ + do \ + { \ + if(!attribute || !*attribute || !ParseXML_GetFloating(attribute,&result)) \ + { \ + fprintf(stderr,"XML Parser: Error on line %ld: '" #attribute "' attribute must be a number in <%s> tag.\n",ParseXML_LineNumber(),tag); \ + return(1); \ + } \ + } \ + while(0) + + +#endif /* XMLPARSE_H */ diff --git a/src/xmlparse.l b/src/xmlparse.l new file mode 100644 index 0000000..c64fdf0 --- /dev/null +++ b/src/xmlparse.l @@ -0,0 +1,784 @@ +%{ +/*************************************** + $Header: /home/amb/routino/src/RCS/xmlparse.l,v 1.17 2010/05/25 18:24:20 amb Exp $ + + A simple generic XML parser where the structure comes from the function parameters. + Not intended to be fully conforming to XML staandard or a validating parser but + sufficient to parse OSM XML and simple program configuration files. + + Part of the Routino routing software. + ******************/ /****************** + This file Copyright 2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ***************************************/ + + +#include +#include +#include +#include + +#include "xmlparse.h" + + +/* Parser outputs */ + +#define LEX_EOF 0 + +#define LEX_TAG_BEGIN 1 +#define LEX_XML_DECL_BEGIN 2 +#define LEX_TAG_POP 3 +#define LEX_TAG_PUSH 4 +#define LEX_XML_DECL_FINISH 6 +#define LEX_TAG_FINISH 7 +#define LEX_ATTR_KEY 8 +#define LEX_ATTR_VAL 9 + +#define LEX_ERROR 100 + +#define LEX_ERROR_TAG_START 101 +#define LEX_ERROR_XML_DECL_START 102 +#define LEX_ERROR_TAG 103 +#define LEX_ERROR_XML_DECL 104 +#define LEX_ERROR_ATTR 105 +#define LEX_ERROR_END_TAG 106 +#define LEX_ERROR_COMMENT 107 +#define LEX_ERROR_CLOSE 108 +#define LEX_ERROR_ATTR_VAL 109 +#define LEX_ERROR_ENTITY_REF 110 +#define LEX_ERROR_CHAR_REF 111 + +#define LEX_ERROR_UNEXP_TAG 201 +#define LEX_ERROR_UNBALANCED 202 +#define LEX_ERROR_NO_START 203 +#define LEX_ERROR_UNEXP_ATT 204 +#define LEX_ERROR_UNEXP_EOF 205 +#define LEX_ERROR_XML_NOT_FIRST 206 + +#define LEX_ERROR_CALLBACK 255 + + +/* Lexer definitions */ + +#define YY_SKIP_YYWRAP 1 /* Remove error with prototype of ..._yywrap */ +#ifndef yywrap +/*+ Needed in lex but does nothing. +*/ +#define yywrap() 1 +#endif + +/*+ Reset the current string. +*/ +#define reset_string \ + if(!string) string=(char*)malloc(16); \ + *string=0; \ + stringused=0; + +/*+ append information to the current string. +*/ +#define append_string(xx) \ + newlen=strlen(xx); \ + if((stringused+newlen)>=stringlen) \ + string=(char*)realloc((void*)string,stringlen=(stringused+newlen+16)); \ + strcpy(string+stringused,xx); \ + stringused+=newlen; + +#define YY_NO_INPUT + + +/* Lexer functions and variables */ + +extern int yylex(void); + +static char *yylval=NULL; + +static int xmlparse_options; + +%} + +%option 8bit +%option pointer +%option batch +%option yylineno + +%option nodefault +%option perf-report +%option fast +%option nounput + + + /* Grammar based on http://www.w3.org/TR/2004/REC-xml-20040204/ but for ASCII not Unicode. */ + +S [ \t\r\n] + +letter [a-zA-Z] +digit [0-9] +xdigit [a-fA-F0-9] + +namechar ({letter}|{digit}|[-._:]) +name ({letter}|[_:]){namechar}* + +entityref &{name}; +charref &#({digit}+|x{xdigit}+); + + +%x COMMENT +%x CDATA +%x DOCTYPE +%x XML_DECL_START XML_DECL +%x TAG_START TAG +%x ATTR_KEY ATTR_VAL +%x END_TAG1 END_TAG2 +%x DQUOTED SQUOTED + +%% + /* Must use static variables since the parser returns often. */ + static char *string=NULL; + static int stringlen=0,stringused=0; + static int after_attr=0; + int newlen; + int doctype_depth=0; + + /* Handle top level entities */ + +"" { return(LEX_ERROR_COMMENT); } +"-->" { BEGIN(INITIAL); } +"--"[^->]+ { } +[^-]+ { } +"-" { } + + /* CDATA */ + +"]]>" { BEGIN(INITIAL); } +"]" { } +[^]]+ { } + + /* CDATA */ + +"<" { doctype_depth++; } +">" { if(doctype_depth==0) BEGIN(INITIAL); else doctype_depth--; } +[^<>]+ { } + + /* XML Declaration start */ + +{name} { BEGIN(XML_DECL); yylval=yytext; return(LEX_XML_DECL_BEGIN); } +.|\n { return(LEX_ERROR_XML_DECL_START); } + + /* Tag middle */ + +"?>" { BEGIN(INITIAL); return(LEX_XML_DECL_FINISH); } +{S}+ { } +{name} { after_attr=XML_DECL; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); } +.|\n { return(LEX_ERROR_XML_DECL); } + + /* Any tag start */ + +{name} { BEGIN(TAG); yylval=yytext; return(LEX_TAG_BEGIN); } +.|\n { return(LEX_ERROR_TAG_START); } + + /* End-tag start */ + +{name} { BEGIN(END_TAG2); yylval=yytext; return(LEX_TAG_POP); } +.|\n { return(LEX_ERROR_END_TAG); } + +">" { BEGIN(INITIAL); } +.|\n { return(LEX_ERROR_END_TAG); } + + /* Any tag middle */ + +"/>" { BEGIN(INITIAL); return(LEX_TAG_FINISH); } +">" { BEGIN(INITIAL); return(LEX_TAG_PUSH); } +{S}+ { } +{name} { after_attr=TAG; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); } +.|\n { return(LEX_ERROR_TAG); } + + /* Attributes */ + += { BEGIN(ATTR_VAL); } +.|\n { return(LEX_ERROR_ATTR); } + +\" { BEGIN(DQUOTED); reset_string; } +\' { BEGIN(SQUOTED); reset_string; } +.|\n { return(LEX_ERROR_ATTR); } + + /* Quoted strings */ + +\" { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); } +{entityref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);} + else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } } +{charref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);} + else { const char *str=ParseXML_Decode_Char_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } } +[<>&] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); } +[^<>&\"]+ { append_string(yytext); } + +\' { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); } +{entityref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);} + else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } } +{charref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);} + else { const char *str=ParseXML_Decode_Char_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } } +[<>&] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); } +[^<>&\']+ { append_string(yytext); } + + /* End of file */ + +<> { free(string); string=NULL; stringlen=stringused=0; BEGIN(INITIAL); return(LEX_EOF); } + +%% + + +/*++++++++++++++++++++++++++++++++++++++ + A function to call the callback function with the parameters needed. + + int call_callback Returns 1 if the callback returned with an error. + + const char *name The name of the tag. + + int (*callback)() The callback function. + + int type The type of tag (start and/or end). + + int nattributes The number of attributes collected. + + char *attributes[XMLPARSE_MAX_ATTRS] The list of attributes. + ++++++++++++++++++++++++++++++++++++++*/ + +static inline int call_callback(const char *name,int (*callback)(),int type,int nattributes,char *attributes[XMLPARSE_MAX_ATTRS]) +{ + switch(nattributes) + { + case 0: return (*callback)(name,type); + case 1: return (*callback)(name,type,attributes[0]); + case 2: return (*callback)(name,type,attributes[0],attributes[1]); + case 3: return (*callback)(name,type,attributes[0],attributes[1],attributes[2]); + case 4: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3]); + case 5: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4]); + case 6: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5]); + case 7: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6]); + case 8: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7]); + case 9: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8]); + case 10: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9]); + case 11: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10]); + case 12: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11]); + case 13: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12]); + case 14: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13]); + case 15: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13],attributes[14]); + case 16: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13],attributes[14],attributes[15]); + + default: + fprintf(stderr,"XML Parser: Error on line %d: too many attributes for tag '%s' source code needs changing.\n",yylineno,name); + exit(1); + } +} + + +/*++++++++++++++++++++++++++++++++++++++ + Parse the XML and call the functions for each tag as seen. + + int ParseXML Returns 0 if OK or something else in case of an error. + + FILE *file The file to parse. + + xmltag **tags The array of pointers to tags for the top level. + + int options A list of XML Parser options OR-ed together. + ++++++++++++++++++++++++++++++++++++++*/ + +int ParseXML(FILE *file,xmltag **tags,int options) +{ + int yychar,i; + + char *attributes[XMLPARSE_MAX_ATTRS]={NULL}; + int attribute=0; + + int stackdepth=0,stackused=0; + xmltag ***tags_stack=NULL; + xmltag **tag_stack=NULL; + xmltag *tag=NULL; + + /* The actual parser. */ + + xmlparse_options=options; + + yyin=file; + + yyrestart(yyin); + + yylineno=1; + + BEGIN(INITIAL); + + do + { + yychar=yylex(); + + switch(yychar) + { + /* The start of a tag for an XML declaration */ + + case LEX_XML_DECL_BEGIN: + + if(tag_stack) + { + fprintf(stderr,"XML Parser: Error on line %d: XML declaration not before all other tags.\n",yylineno); + yychar=LEX_ERROR_XML_NOT_FIRST; + break; + } + + /* The start of a tag for an element */ + + case LEX_TAG_BEGIN: + + tag=NULL; + + for(i=0;tags[i];i++) + if(!strcasecmp(yylval,tags[i]->name)) + { + tag=tags[i]; + + for(i=0;inattributes;i++) + if(attributes[i]) + { + free(attributes[i]); + attributes[i]=NULL; + } + + break; + } + + if(tag==NULL) + { + fprintf(stderr,"XML Parser: Error on line %d: unexpected tag '%s'.\n",yylineno,yylval); + yychar=LEX_ERROR_UNEXP_TAG; + } + + break; + + /* The end of the start-tag for an element */ + + case LEX_TAG_PUSH: + + if(stackused==stackdepth) + { + tag_stack =(xmltag**) realloc((void*)tag_stack ,(stackdepth+=8)*sizeof(xmltag*)); + tags_stack=(xmltag***)realloc((void*)tags_stack,(stackdepth+=8)*sizeof(xmltag**)); + } + + tag_stack [stackused]=tag; + tags_stack[stackused]=tags; + stackused++; + + if(tag->callback) + if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START,tag->nattributes,attributes)) + yychar=LEX_ERROR_CALLBACK; + + tags=tag->subtags; + + break; + + /* The end of the empty-element-tag for an XML declaration */ + + case LEX_XML_DECL_FINISH: + + /* The end of the empty-element-tag for an element */ + + case LEX_TAG_FINISH: + + if(tag->callback) + if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START|XMLPARSE_TAG_END,tag->nattributes,attributes)) + yychar=LEX_ERROR_CALLBACK; + + if(stackused>0) + tag=tag_stack[stackused-1]; + else + tag=NULL; + + break; + + /* The end of the end-tag for an element */ + + case LEX_TAG_POP: + + stackused--; + tags=tags_stack[stackused]; + tag =tag_stack [stackused]; + + if(strcmp(tag->name,yylval)) + { + fprintf(stderr,"XML Parser: Error on line %d: end tag '' doesn't match start tag '<%s ...>'.\n",yylineno,yylval,tag->name); + yychar=LEX_ERROR_UNBALANCED; + } + + if(stackused<0) + { + fprintf(stderr,"XML Parser: Error on line %d: end tag '' seen but there was no start tag '<%s ...>'.\n",yylineno,yylval,yylval); + yychar=LEX_ERROR_NO_START; + } + + for(i=0;inattributes;i++) + if(attributes[i]) + { + free(attributes[i]); + attributes[i]=NULL; + } + + if(tag->callback) + if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_END,tag->nattributes,attributes)) + yychar=LEX_ERROR_CALLBACK; + + if(stackused>0) + tag=tag_stack[stackused-1]; + else + tag=NULL; + + break; + + /* An attribute key */ + + case LEX_ATTR_KEY: + + attribute=-1; + + for(i=0;inattributes;i++) + if(!strcasecmp(yylval,tag->attributes[i])) + { + attribute=i; + + break; + } + + if(attribute==-1) + { + if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERROR || + ((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERRNONAME && !strchr(yylval,':'))) + { + fprintf(stderr,"XML Parser: Error on line %d: unexpected attribute '%s' for tag '%s'.\n",yylineno,yylval,tag->name); + yychar=LEX_ERROR_UNEXP_ATT; + } + else if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_WARN) + fprintf(stderr,"XML Parser: Warning on line %d: unexpected attribute '%s' for tag '%s'.\n",yylineno,yylval,tag->name); + } + + break; + + /* An attribute value */ + + case LEX_ATTR_VAL: + + if(tag->callback && attribute!=-1 && yylval) + attributes[attribute]=strcpy(malloc(strlen(yylval)+1),yylval); + + break; + + /* End of file */ + + case LEX_EOF: + + if(tag) + { + fprintf(stderr,"XML Parser: Error on line %d: end of file seen without end tag ''.\n",yylineno,tag->name); + yychar=LEX_ERROR_UNEXP_EOF; + } + + break; + + case LEX_ERROR_TAG_START: + fprintf(stderr,"XML Parser: Error on line %d: character '<' seen not at start of tag.\n",yylineno); + break; + + case LEX_ERROR_XML_DECL_START: + fprintf(stderr,"XML Parser: Error on line %d: characters ''.\n",yylineno,tag->name); + break; + + case LEX_ERROR_XML_DECL: + fprintf(stderr,"XML Parser: Error on line %d: invalid character seen inside XML declaration ''.\n",yylineno,tag->name); + break; + + case LEX_ERROR_ATTR: + fprintf(stderr,"XML Parser: Error on line %d: invalid attribute definition seen in tag.\n",yylineno); + break; + + case LEX_ERROR_END_TAG: + fprintf(stderr,"XML Parser: Error on line %d: invalid character seen in end-tag.\n",yylineno); + break; + + case LEX_ERROR_COMMENT: + fprintf(stderr,"XML Parser: Error on line %d: invalid comment seen.\n",yylineno); + break; + + case LEX_ERROR_CLOSE: + fprintf(stderr,"XML Parser: Error on line %d: character '>' seen not at end of tag.\n",yylineno); + break; + + case LEX_ERROR_ATTR_VAL: + fprintf(stderr,"XML Parser: Error on line %d: invalid character '%s' seen in attribute value.\n",yylineno,yylval); + break; + + case LEX_ERROR_ENTITY_REF: + fprintf(stderr,"XML Parser: Error on line %d: invalid entity reference '%s' seen in attribute value.\n",yylineno,yylval); + break; + + case LEX_ERROR_CHAR_REF: + fprintf(stderr,"XML Parser: Error on line %d: invalid character reference '%s' seen in attribute value.\n",yylineno,yylval); + break; + } + } + while(yychar>LEX_EOF && yychar"); + if(!strcmp(string,"'")) return("'"); + if(!strcmp(string,""")) return("\""); + return(NULL); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Convert an XML character reference into an ASCII string. + + char *ParseXML_Decode_Char_Ref Returns a pointer to the replacement decoded string. + + const char *string The character reference string. + ++++++++++++++++++++++++++++++++++++++*/ + +char *ParseXML_Decode_Char_Ref(const char *string) +{ + static char result[2]=" "; + long int val; + + if(string[2]=='x') val=strtol(string+3,NULL,16); + else val=strtol(string+2,NULL,10); + + if(val<0 || val>255) + return(NULL); + + result[0]=val&0xff; + + return(result); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Convert a string into something that is safe to output in an XML file. + + char *ParseXML_Encode_Safe_XML Returns a pointer to the replacement encoded string (or the original if no change needed). + + const char *string The string to convert. + ++++++++++++++++++++++++++++++++++++++*/ + +char *ParseXML_Encode_Safe_XML(const char *string) +{ + static const char hexstring[17]="0123456789ABCDEF"; + int i=0,j=0,len; + char *result; + + for(i=0;string[i];i++) + if(string[i]=='<' || string[i]=='>' || string[i]=='&' || string[i]=='\'' || string[i]=='"' || string[i]<32 || string[i]>126) + break; + + if(!string[i]) + return((char*)string); + + len=i+256-6; + + result=(char*)malloc(len+7); + strncpy(result,string,j=i); + + do + { + for(;j') + { + result[j++]='&'; + result[j++]='g'; + result[j++]='t'; + result[j++]=';'; + } + else if(string[i]=='&') + { + result[j++]='&'; + result[j++]='a'; + result[j++]='m'; + result[j++]='p'; + result[j++]=';'; + } + else if(string[i]=='\'') + { + result[j++]='&'; + result[j++]='a'; + result[j++]='p'; + result[j++]='o'; + result[j++]='s'; + result[j++]=';'; + } + else if(string[i]=='"') + { + result[j++]='&'; + result[j++]='q'; + result[j++]='u'; + result[j++]='o'; + result[j++]='t'; + result[j++]=';'; + } + else if(string[i]<32 || string[i]>126) + { + result[j++]='&'; + result[j++]='#'; + result[j++]='x'; + result[j++]=hexstring[(string[i]&0xf0)>>4]; + result[j++]=hexstring[ string[i]&0x0f ]; + result[j++]=';'; + } + else + result[j++]=string[i]; + + if(string[i]) /* Not finished */ + { + len+=256; + result=(char*)realloc((void*)result,len+7); + } + } + while(string[i]); + + result[j]=0; + + return(result); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Convert a string to a integer (checking that it really is a integer). + + int ParseXML_GetInteger Returns 1 if a integer could be found or 0 otherwise. + + const char *string The string to be parsed. + + int *number Returns the number. + ++++++++++++++++++++++++++++++++++++++*/ + +int ParseXML_GetInteger(const char *string,int *number) +{ + const char *p=string; + + if(*p=='-' || *p=='+') + p++; + + while(isdigit(*p)) + p++; + + if(*p) + return(0); + + *number=atoi(string); + + return(1); +} + + +/*++++++++++++++++++++++++++++++++++++++ + Convert a string to a floating point number (checking that it really is a number). + + int ParseXML_GetFloating Returns 1 if a number could be found or 0 otherwise. + + const char *string The string to be parsed. + + int *number Returns the number. + ++++++++++++++++++++++++++++++++++++++*/ + +int ParseXML_GetFloating(const char *string,double *number) +{ + const char *p=string; + + if(*p=='-' || *p=='+') + p++; + + while(isdigit(*p) || *p=='.') + p++; + + if(*p=='e' || *p=='E') + { + p++; + + if(*p=='-' || *p=='+') + p++; + + while(isdigit(*p)) + p++; + } + + if(*p) + return(0); + + *number=atof(string); + + return(1); +} diff --git a/web/INSTALL.txt b/web/INSTALL.txt new file mode 120000 index 0000000..4c0523b --- /dev/null +++ b/web/INSTALL.txt @@ -0,0 +1 @@ +../doc/INSTALL.txt \ No newline at end of file diff --git a/web/data/create.sh b/web/data/create.sh new file mode 100755 index 0000000..e1d5a81 --- /dev/null +++ b/web/data/create.sh @@ -0,0 +1,30 @@ +#!/bin/sh -x + +# This script can download either from GeoFabrik or Cloudmade. + + +# EDIT THIS to set the names of the files to download. +files="europe/great_britain.osm.bz2 europe/ireland.osm.bz2 europe/isle_of_man.osm.bz2" + +# Download the files + +for file in $files; do + wget -N http://download.geofabrik.de/osm/$file +done + + +## EDIT THIS to set the names of the files to download. +#files="europe/united_kingdom/united_kingdom.osm.bz2 europe/ireland/ireland.osm.bz2 europe/isle_of_man/isle_of_man.osm.bz2" +# +## Download the files +# +#for file in $files; do +# wget -N http://downloads.cloudmade.com/$file +#done + + +# Process the data + +bunzip2 *.bz2 + +../bin/planetsplitter *.osm diff --git a/web/www/openlayers/install.sh b/web/www/openlayers/install.sh new file mode 100755 index 0000000..60a6eee --- /dev/null +++ b/web/www/openlayers/install.sh @@ -0,0 +1,25 @@ +#!/bin/sh -x + +version=2.9.1 + +# Download the file. + +wget http://openlayers.org/download/OpenLayers-$version.tar.gz + +# Uncompress it. + +tar -xzf OpenLayers-$version.tar.gz + +# Create a custom OpenLayers file + +(cd OpenLayers-$version/build && python build.py ../../routino.cfg && cp OpenLayers.js ..) + +# Copy the files. + +cp -p OpenLayers-$version/OpenLayers.js . +cp -pr OpenLayers-$version/img . +cp -pr OpenLayers-$version/theme . + +# Delete the remainder + +rm -rf OpenLayers-$version diff --git a/web/www/openlayers/routino.cfg b/web/www/openlayers/routino.cfg new file mode 100644 index 0000000..6f6226e --- /dev/null +++ b/web/www/openlayers/routino.cfg @@ -0,0 +1,44 @@ +# This is a configuration file to allow building an optimised OpenLayers +# Javascript file that contains all of the features required for Routino. + +[first] +OpenLayers/SingleFile.js +OpenLayers.js +OpenLayers/BaseTypes.js +OpenLayers/BaseTypes/Class.js +OpenLayers/Util.js +Rico/Corner.js + +[last] + +[include] +OpenLayers/Ajax.js +OpenLayers/BaseTypes/LonLat.js +OpenLayers/BaseTypes/Bounds.js +OpenLayers/Control/DragFeature.js +OpenLayers/Control/LayerSwitcher.js +OpenLayers/Control/Navigation.js +OpenLayers/Control/PanZoomBar.js +OpenLayers/Control/ScaleLine.js +OpenLayers/Feature/Vector.js +OpenLayers/Format/GML.js +OpenLayers/Format/GPX.js +OpenLayers/Geometry/LineString.js +OpenLayers/Geometry/Point.js +OpenLayers/Geometry/Polygon.js +OpenLayers/Layer/Boxes.js +OpenLayers/Layer/GML.js +OpenLayers/Layer/SphericalMercator.js +OpenLayers/Layer/TMS.js +OpenLayers/Layer/Vector.js +OpenLayers/Map.js +OpenLayers/Marker/Box.js +OpenLayers/Projection.js +OpenLayers/Renderer/Elements.js +OpenLayers/Renderer/Canvas.js +OpenLayers/Renderer/SVG.js +OpenLayers/Renderer/VML.js +OpenLayers/Rule.js +OpenLayers/Style.js + +[exclude] diff --git a/web/www/routino/.htaccess b/web/www/routino/.htaccess new file mode 100644 index 0000000..29ea962 --- /dev/null +++ b/web/www/routino/.htaccess @@ -0,0 +1,40 @@ +## +## Options for Apache web server for language specific web pages and to run +## Routino CGI scripts. +## + +# The translated router pages use the MultiViews option to serve up a version of +# the web page depending on the client language preference. If the line below +# is used in a .htaccess file like this one and the "AllowOverride none" option +# is set in the main Apache configuration file then the entry in the .htaccess +# file will not work. + +#Options +MultiViews + +# The English language option will be served if there is no other version +# present and no errors will be returned to the user in case of problems + +LanguagePriority en +ForceLanguagePriority Prefer Fallback + +# The Routino CGI scripts are stored in this directory and use the filename +# extension ".cgi". This filename extension needs to be registered with Apache +# for the scripts to be executed. + +AddHandler cgi-script .cgi + +# The ExecCGI option must be set for the CGIs in this directory to be executed +# by Apache. If the line below is used in a .htaccess file like this one and +# the "AllowOverride none" option is set in the main Apache configuration file +# then the entry in the .htaccess file will not work. + +#Options +ExecCGI + +# The CGI scripts that are used by Routino also call some other Perl scripts, to +# stop these scripts from being seen by web users they can be denied by the +# following entry. + + + Order deny,allow + Deny from all + diff --git a/web/www/routino/customrouter.cgi b/web/www/routino/customrouter.cgi new file mode 100755 index 0000000..454818e --- /dev/null +++ b/web/www/routino/customrouter.cgi @@ -0,0 +1,143 @@ +#!/usr/bin/perl +# +# Routino router custom link CGI +# +# Part of the Routino routing software. +# +# This file Copyright 2008-2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Use the generic router script +require "router.pl"; + +# Use the perl CGI module +use CGI ':cgi'; + +# Create the query and get the parameters + +$query=new CGI; + +@rawparams=$query->param; + +# Legal CGI parameters with regexp validity check + +%legalparams=( + "lon" => "[-0-9.]+", + "lat" => "[-0-9.]+", + "zoom" => "[0-9]+", + + "lon[1-9]" => "[-0-9.]+", + "lat[1-9]" => "[-0-9.]+", + "transport" => "[a-z]+", + "highway-[a-z]+" => "[0-9.]+", + "speed-[a-z]+" => "[0-9.]+", + "property-[a-z]+" => "[0-9.]+", + "oneway" => "(1|0|true|false|on|off)", + "weight" => "[0-9.]+", + "height" => "[0-9.]+", + "width" => "[0-9.]+", + "length" => "[0-9.]+", + + "language" => "[-a-zA-Z]+" + ); + +# Validate the CGI parameters, ignore invalid ones + +foreach $key (@rawparams) + { + foreach $test (keys (%legalparams)) + { + if($key =~ m%^$test$%) + { + $value=$query->param($key); + + if($value =~ m%^$legalparams{$test}$%) + { + $cgiparams{$key}=$value; + last; + } + } + } + } + +# Fill in the default parameters + +%fullparams=FillInDefaults(%cgiparams); + +# Open template file and output it + +$lang=$cgiparams{'language'}; + +if( -f "router.html.$lang") + { + open(TEMPLATE,") + { + if(m%^%) + { + s/'lat'/$cgiparams{'lat'}/ if(defined $cgiparams{'lat'}); + s/'lon'/$cgiparams{'lon'}/ if(defined $cgiparams{'lon'}); + s/'zoom'/$cgiparams{'zoom'}/ if(defined $cgiparams{'zoom'}); + print; + } + elsif(m%%) + { + $key=$1; + + m%type="([a-z]+)"%; + $type=$1; + + m%value="([a-z]+)"%; + $value=$1; + + if($type eq "radio") + { + $checked=""; + $checked="checked" if($fullparams{$key} eq $value); + + s%>% $checked>%; + } + elsif($type eq "checkbox") + { + $checked=""; + $checked="checked" if($fullparams{$key}); + + s%>% $checked>%; + } + elsif($type eq "text") + { + s%>% value="$fullparams{$key}">%; + } + + print; + } + else + { + print; + } + } + +close(TEMPLATE); diff --git a/web/www/routino/customvisualiser.cgi b/web/www/routino/customvisualiser.cgi new file mode 100755 index 0000000..4b28e57 --- /dev/null +++ b/web/www/routino/customvisualiser.cgi @@ -0,0 +1,82 @@ +#!/usr/bin/perl +# +# Routino data visualiser custom link CGI +# +# Part of the Routino routing software. +# +# This file Copyright 2008,2009 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Use the perl CGI module +use CGI ':cgi'; + +# Create the query and get the parameters + +$query=new CGI; + +@rawparams=$query->param; + +# Legal CGI parameters with regexp validity check + +%legalparams=( + "lon" => "[-0-9.]+", + "lat" => "[-0-9.]+", + "zoom" => "[0-9]+" + ); + +# Validate the CGI parameters, ignore invalid ones + +foreach $key (@rawparams) + { + foreach $test (keys (%legalparams)) + { + if($key =~ m%^$test$%) + { + $value=$query->param($key); + + if($value =~ m%^$legalparams{$test}$%) + { + $cgiparams{$key}=$value; + last; + } + } + } + } + +# Open template file and output it + +open(TEMPLATE,") + { + if(m%^%) + { + s/'lat'/$cgiparams{'lat'}/ if(defined $cgiparams{'lat'}); + s/'lon'/$cgiparams{'lon'}/ if(defined $cgiparams{'lon'}); + s/'zoom'/$cgiparams{'zoom'}/ if(defined $cgiparams{'zoom'}); + print; + } + else + { + print; + } + } + +close(TEMPLATE); diff --git a/web/www/routino/icons/ball-0.png b/web/www/routino/icons/ball-0.png new file mode 100644 index 0000000..d54adaa Binary files /dev/null and b/web/www/routino/icons/ball-0.png differ diff --git a/web/www/routino/icons/ball-1.png b/web/www/routino/icons/ball-1.png new file mode 100644 index 0000000..fba4e31 Binary files /dev/null and b/web/www/routino/icons/ball-1.png differ diff --git a/web/www/routino/icons/ball-2.png b/web/www/routino/icons/ball-2.png new file mode 100644 index 0000000..e664ba6 Binary files /dev/null and b/web/www/routino/icons/ball-2.png differ diff --git a/web/www/routino/icons/ball-3.png b/web/www/routino/icons/ball-3.png new file mode 100644 index 0000000..0b8c2bf Binary files /dev/null and b/web/www/routino/icons/ball-3.png differ diff --git a/web/www/routino/icons/ball-4.png b/web/www/routino/icons/ball-4.png new file mode 100644 index 0000000..e0b46c9 Binary files /dev/null and b/web/www/routino/icons/ball-4.png differ diff --git a/web/www/routino/icons/ball-5.png b/web/www/routino/icons/ball-5.png new file mode 100644 index 0000000..6c2aed0 Binary files /dev/null and b/web/www/routino/icons/ball-5.png differ diff --git a/web/www/routino/icons/ball-6.png b/web/www/routino/icons/ball-6.png new file mode 100644 index 0000000..01c37fe Binary files /dev/null and b/web/www/routino/icons/ball-6.png differ diff --git a/web/www/routino/icons/ball-7.png b/web/www/routino/icons/ball-7.png new file mode 100644 index 0000000..770ca73 Binary files /dev/null and b/web/www/routino/icons/ball-7.png differ diff --git a/web/www/routino/icons/ball-8.png b/web/www/routino/icons/ball-8.png new file mode 100644 index 0000000..770ca73 Binary files /dev/null and b/web/www/routino/icons/ball-8.png differ diff --git a/web/www/routino/icons/ball-9.png b/web/www/routino/icons/ball-9.png new file mode 100644 index 0000000..770ca73 Binary files /dev/null and b/web/www/routino/icons/ball-9.png differ diff --git a/web/www/routino/icons/create-icons.pl b/web/www/routino/icons/create-icons.pl new file mode 100755 index 0000000..b90964c --- /dev/null +++ b/web/www/routino/icons/create-icons.pl @@ -0,0 +1,156 @@ +#!/usr/bin/perl +# +# Routino icons Perl script +# +# Part of the Routino routing software. +# +# This file Copyright 2008-2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +use Graphics::Magick; + +# Markers for routing + +@names=("red","grey"); +@borders=("black","grey"); +@letters=("red","grey"); + +foreach $character ('0'..'9','home') + { + foreach $colour (0..$#names) + { + $image=Graphics::Magick->new; + $image->Set(size => "63x75"); + + $image->ReadImage('xc:white'); + $image->Transparent('white'); + + $image->Draw(primitive => polygon, points => '1,32 32,73 61,32 32,10', + stroke => $borders[$colour], fill => 'white', strokewidth => 6, + antialias => 'false'); + + $image->Draw(primitive => arc, points => '1,1 61,61 -180,0', + stroke => $borders[$colour], fill => 'white', strokewidth => 6, + antialias => 'false'); + + if($character eq 'home') + { + $home=Graphics::Magick->new; + + $home->ReadImage("home.png"); + + $home->Opaque(fill => $names[$colour], color => 'black'); + + $image->Composite(image => $home, compose => Over, + x => 32-$home->Get('width')/2, y => 26-$home->Get('height')/2); + } + else + { + ($x_ppem, $y_ppem, $ascender, $descender, $width, $height, $max_advance) = + $image->QueryFontMetrics(text => $character, font => 'Helvetica', pointsize => '36'); + + $image->Annotate(text => $character, font => 'Helvetica', pointsize => '36', + stroke => $letters[$colour], fill => $letters[$colour], + x => 32, y => 32-$descender, align => Center, + antialias => 'false'); + } + + $image->Resize(width => 21, height => 25); + + $image->Write("marker-$character-$names[$colour].png"); + + undef $image; + } + } + +# Balls for visualiser descriptions + +@colours=("#FFFFFF", + "#FF0000", + "#FFFF00", + "#00FF00", + "#8B4513", + "#00BFFF", + "#FF69B4", + "#000000", + "#000000", + "#000000"); + +foreach $colour (0..9) + { + $image=Graphics::Magick->new; + $image->Set(size => "9x9"); + + $image->ReadImage('xc:white'); + $image->Transparent('white'); + + $image->Draw(primitive => circle, points => '4,4 4,8', + fill => $colours[$colour], stroke => $colours[$colour], + antialias => 'false'); + + $image->Write("ball-$colour.png"); + + undef $image; + } + +# Limit signs + +foreach $limit (1..160) + { + &draw_limit($limit); + } + +foreach $limit (10..200) + { + &draw_limit(sprintf "%.1f",$limit/10); + } + +&draw_limit("no"); + +unlink "limit-0.png"; +link "limit-no.png","limit-0.png"; + +unlink "limit-0.0.png"; +link "limit-no.png","limit-0.0.png"; + +sub draw_limit + { + ($limit)=@_; + + $image=Graphics::Magick->new; + $image->Set(size => "57x57"); + + $image->ReadImage('xc:white'); + $image->Transparent('white'); + + $image->Draw(primitive => circle, points => '28,28 28,55', + stroke => 'red', fill => 'white', strokewidth => 3, + antialias => 'false'); + + ($x_ppem, $y_ppem, $ascender, $descender, $width, $height, $max_advance) = + $image->QueryFontMetrics(text => "$limit", font => 'Helvetica', pointsize => '22'); + + $image->Annotate(text => "$limit", font => 'Helvetica', pointsize => '22', + stroke => 'black', fill => 'black', + x => 28, y => 28-$descender, align => Center, + antialias => 'false'); + + $image->Resize(width => 19, height => 19); + + $image->Write("limit-$limit.png"); + + undef $image; + } diff --git a/web/www/routino/icons/home.png b/web/www/routino/icons/home.png new file mode 100644 index 0000000..1a7c261 Binary files /dev/null and b/web/www/routino/icons/home.png differ diff --git a/web/www/routino/icons/limit-0.0.png b/web/www/routino/icons/limit-0.0.png new file mode 100644 index 0000000..cbcf311 Binary files /dev/null and b/web/www/routino/icons/limit-0.0.png differ diff --git a/web/www/routino/icons/limit-0.png b/web/www/routino/icons/limit-0.png new file mode 100644 index 0000000..cbcf311 Binary files /dev/null and b/web/www/routino/icons/limit-0.png differ diff --git a/web/www/routino/icons/limit-1.0.png b/web/www/routino/icons/limit-1.0.png new file mode 100644 index 0000000..cd4da61 Binary files /dev/null and b/web/www/routino/icons/limit-1.0.png differ diff --git a/web/www/routino/icons/limit-1.1.png b/web/www/routino/icons/limit-1.1.png new file mode 100644 index 0000000..13757fa Binary files /dev/null and b/web/www/routino/icons/limit-1.1.png differ diff --git a/web/www/routino/icons/limit-1.2.png b/web/www/routino/icons/limit-1.2.png new file mode 100644 index 0000000..0b0b471 Binary files /dev/null and b/web/www/routino/icons/limit-1.2.png differ diff --git a/web/www/routino/icons/limit-1.3.png b/web/www/routino/icons/limit-1.3.png new file mode 100644 index 0000000..a4ea5e4 Binary files /dev/null and b/web/www/routino/icons/limit-1.3.png differ diff --git a/web/www/routino/icons/limit-1.4.png b/web/www/routino/icons/limit-1.4.png new file mode 100644 index 0000000..9a4b268 Binary files /dev/null and b/web/www/routino/icons/limit-1.4.png differ diff --git a/web/www/routino/icons/limit-1.5.png b/web/www/routino/icons/limit-1.5.png new file mode 100644 index 0000000..797e931 Binary files /dev/null and b/web/www/routino/icons/limit-1.5.png differ diff --git a/web/www/routino/icons/limit-1.6.png b/web/www/routino/icons/limit-1.6.png new file mode 100644 index 0000000..1d622a7 Binary files /dev/null and b/web/www/routino/icons/limit-1.6.png differ diff --git a/web/www/routino/icons/limit-1.7.png b/web/www/routino/icons/limit-1.7.png new file mode 100644 index 0000000..80ae411 Binary files /dev/null and b/web/www/routino/icons/limit-1.7.png differ diff --git a/web/www/routino/icons/limit-1.8.png b/web/www/routino/icons/limit-1.8.png new file mode 100644 index 0000000..930e9a7 Binary files /dev/null and b/web/www/routino/icons/limit-1.8.png differ diff --git a/web/www/routino/icons/limit-1.9.png b/web/www/routino/icons/limit-1.9.png new file mode 100644 index 0000000..dd9370a Binary files /dev/null and b/web/www/routino/icons/limit-1.9.png differ diff --git a/web/www/routino/icons/limit-1.png b/web/www/routino/icons/limit-1.png new file mode 100644 index 0000000..328b063 Binary files /dev/null and b/web/www/routino/icons/limit-1.png differ diff --git a/web/www/routino/icons/limit-10.0.png b/web/www/routino/icons/limit-10.0.png new file mode 100644 index 0000000..e77d2d9 Binary files /dev/null and b/web/www/routino/icons/limit-10.0.png differ diff --git a/web/www/routino/icons/limit-10.1.png b/web/www/routino/icons/limit-10.1.png new file mode 100644 index 0000000..e141d26 Binary files /dev/null and b/web/www/routino/icons/limit-10.1.png differ diff --git a/web/www/routino/icons/limit-10.2.png b/web/www/routino/icons/limit-10.2.png new file mode 100644 index 0000000..e4dde28 Binary files /dev/null and b/web/www/routino/icons/limit-10.2.png differ diff --git a/web/www/routino/icons/limit-10.3.png b/web/www/routino/icons/limit-10.3.png new file mode 100644 index 0000000..42168af Binary files /dev/null and b/web/www/routino/icons/limit-10.3.png differ diff --git a/web/www/routino/icons/limit-10.4.png b/web/www/routino/icons/limit-10.4.png new file mode 100644 index 0000000..d1266d1 Binary files /dev/null and b/web/www/routino/icons/limit-10.4.png differ diff --git a/web/www/routino/icons/limit-10.5.png b/web/www/routino/icons/limit-10.5.png new file mode 100644 index 0000000..ad68e70 Binary files /dev/null and b/web/www/routino/icons/limit-10.5.png differ diff --git a/web/www/routino/icons/limit-10.6.png b/web/www/routino/icons/limit-10.6.png new file mode 100644 index 0000000..d720a87 Binary files /dev/null and b/web/www/routino/icons/limit-10.6.png differ diff --git a/web/www/routino/icons/limit-10.7.png b/web/www/routino/icons/limit-10.7.png new file mode 100644 index 0000000..903a30d Binary files /dev/null and b/web/www/routino/icons/limit-10.7.png differ diff --git a/web/www/routino/icons/limit-10.8.png b/web/www/routino/icons/limit-10.8.png new file mode 100644 index 0000000..8f60285 Binary files /dev/null and b/web/www/routino/icons/limit-10.8.png differ diff --git a/web/www/routino/icons/limit-10.9.png b/web/www/routino/icons/limit-10.9.png new file mode 100644 index 0000000..360625a Binary files /dev/null and b/web/www/routino/icons/limit-10.9.png differ diff --git a/web/www/routino/icons/limit-10.png b/web/www/routino/icons/limit-10.png new file mode 100644 index 0000000..4acb3b0 Binary files /dev/null and b/web/www/routino/icons/limit-10.png differ diff --git a/web/www/routino/icons/limit-100.png b/web/www/routino/icons/limit-100.png new file mode 100644 index 0000000..6ba354e Binary files /dev/null and b/web/www/routino/icons/limit-100.png differ diff --git a/web/www/routino/icons/limit-101.png b/web/www/routino/icons/limit-101.png new file mode 100644 index 0000000..c92cc8b Binary files /dev/null and b/web/www/routino/icons/limit-101.png differ diff --git a/web/www/routino/icons/limit-102.png b/web/www/routino/icons/limit-102.png new file mode 100644 index 0000000..5ab7555 Binary files /dev/null and b/web/www/routino/icons/limit-102.png differ diff --git a/web/www/routino/icons/limit-103.png b/web/www/routino/icons/limit-103.png new file mode 100644 index 0000000..584e55f Binary files /dev/null and b/web/www/routino/icons/limit-103.png differ diff --git a/web/www/routino/icons/limit-104.png b/web/www/routino/icons/limit-104.png new file mode 100644 index 0000000..5e85bda Binary files /dev/null and b/web/www/routino/icons/limit-104.png differ diff --git a/web/www/routino/icons/limit-105.png b/web/www/routino/icons/limit-105.png new file mode 100644 index 0000000..272d0a2 Binary files /dev/null and b/web/www/routino/icons/limit-105.png differ diff --git a/web/www/routino/icons/limit-106.png b/web/www/routino/icons/limit-106.png new file mode 100644 index 0000000..7c265c1 Binary files /dev/null and b/web/www/routino/icons/limit-106.png differ diff --git a/web/www/routino/icons/limit-107.png b/web/www/routino/icons/limit-107.png new file mode 100644 index 0000000..df6a87a Binary files /dev/null and b/web/www/routino/icons/limit-107.png differ diff --git a/web/www/routino/icons/limit-108.png b/web/www/routino/icons/limit-108.png new file mode 100644 index 0000000..a24219f Binary files /dev/null and b/web/www/routino/icons/limit-108.png differ diff --git a/web/www/routino/icons/limit-109.png b/web/www/routino/icons/limit-109.png new file mode 100644 index 0000000..fea781d Binary files /dev/null and b/web/www/routino/icons/limit-109.png differ diff --git a/web/www/routino/icons/limit-11.0.png b/web/www/routino/icons/limit-11.0.png new file mode 100644 index 0000000..e1ec5ca Binary files /dev/null and b/web/www/routino/icons/limit-11.0.png differ diff --git a/web/www/routino/icons/limit-11.1.png b/web/www/routino/icons/limit-11.1.png new file mode 100644 index 0000000..8fa9bec Binary files /dev/null and b/web/www/routino/icons/limit-11.1.png differ diff --git a/web/www/routino/icons/limit-11.2.png b/web/www/routino/icons/limit-11.2.png new file mode 100644 index 0000000..af940fc Binary files /dev/null and b/web/www/routino/icons/limit-11.2.png differ diff --git a/web/www/routino/icons/limit-11.3.png b/web/www/routino/icons/limit-11.3.png new file mode 100644 index 0000000..d7af6e9 Binary files /dev/null and b/web/www/routino/icons/limit-11.3.png differ diff --git a/web/www/routino/icons/limit-11.4.png b/web/www/routino/icons/limit-11.4.png new file mode 100644 index 0000000..95a1725 Binary files /dev/null and b/web/www/routino/icons/limit-11.4.png differ diff --git a/web/www/routino/icons/limit-11.5.png b/web/www/routino/icons/limit-11.5.png new file mode 100644 index 0000000..16a06e0 Binary files /dev/null and b/web/www/routino/icons/limit-11.5.png differ diff --git a/web/www/routino/icons/limit-11.6.png b/web/www/routino/icons/limit-11.6.png new file mode 100644 index 0000000..4337fcc Binary files /dev/null and b/web/www/routino/icons/limit-11.6.png differ diff --git a/web/www/routino/icons/limit-11.7.png b/web/www/routino/icons/limit-11.7.png new file mode 100644 index 0000000..dd7b1fa Binary files /dev/null and b/web/www/routino/icons/limit-11.7.png differ diff --git a/web/www/routino/icons/limit-11.8.png b/web/www/routino/icons/limit-11.8.png new file mode 100644 index 0000000..3c14aa9 Binary files /dev/null and b/web/www/routino/icons/limit-11.8.png differ diff --git a/web/www/routino/icons/limit-11.9.png b/web/www/routino/icons/limit-11.9.png new file mode 100644 index 0000000..e636cac Binary files /dev/null and b/web/www/routino/icons/limit-11.9.png differ diff --git a/web/www/routino/icons/limit-11.png b/web/www/routino/icons/limit-11.png new file mode 100644 index 0000000..54d3db0 Binary files /dev/null and b/web/www/routino/icons/limit-11.png differ diff --git a/web/www/routino/icons/limit-110.png b/web/www/routino/icons/limit-110.png new file mode 100644 index 0000000..a711a9f Binary files /dev/null and b/web/www/routino/icons/limit-110.png differ diff --git a/web/www/routino/icons/limit-111.png b/web/www/routino/icons/limit-111.png new file mode 100644 index 0000000..3c0051d Binary files /dev/null and b/web/www/routino/icons/limit-111.png differ diff --git a/web/www/routino/icons/limit-112.png b/web/www/routino/icons/limit-112.png new file mode 100644 index 0000000..2f275ca Binary files /dev/null and b/web/www/routino/icons/limit-112.png differ diff --git a/web/www/routino/icons/limit-113.png b/web/www/routino/icons/limit-113.png new file mode 100644 index 0000000..eef9b1e Binary files /dev/null and b/web/www/routino/icons/limit-113.png differ diff --git a/web/www/routino/icons/limit-114.png b/web/www/routino/icons/limit-114.png new file mode 100644 index 0000000..2c05910 Binary files /dev/null and b/web/www/routino/icons/limit-114.png differ diff --git a/web/www/routino/icons/limit-115.png b/web/www/routino/icons/limit-115.png new file mode 100644 index 0000000..64930f2 Binary files /dev/null and b/web/www/routino/icons/limit-115.png differ diff --git a/web/www/routino/icons/limit-116.png b/web/www/routino/icons/limit-116.png new file mode 100644 index 0000000..ca9fae9 Binary files /dev/null and b/web/www/routino/icons/limit-116.png differ diff --git a/web/www/routino/icons/limit-117.png b/web/www/routino/icons/limit-117.png new file mode 100644 index 0000000..13700fa Binary files /dev/null and b/web/www/routino/icons/limit-117.png differ diff --git a/web/www/routino/icons/limit-118.png b/web/www/routino/icons/limit-118.png new file mode 100644 index 0000000..3739a4e Binary files /dev/null and b/web/www/routino/icons/limit-118.png differ diff --git a/web/www/routino/icons/limit-119.png b/web/www/routino/icons/limit-119.png new file mode 100644 index 0000000..fe6e3f4 Binary files /dev/null and b/web/www/routino/icons/limit-119.png differ diff --git a/web/www/routino/icons/limit-12.0.png b/web/www/routino/icons/limit-12.0.png new file mode 100644 index 0000000..9056c63 Binary files /dev/null and b/web/www/routino/icons/limit-12.0.png differ diff --git a/web/www/routino/icons/limit-12.1.png b/web/www/routino/icons/limit-12.1.png new file mode 100644 index 0000000..77fadc6 Binary files /dev/null and b/web/www/routino/icons/limit-12.1.png differ diff --git a/web/www/routino/icons/limit-12.2.png b/web/www/routino/icons/limit-12.2.png new file mode 100644 index 0000000..82a9870 Binary files /dev/null and b/web/www/routino/icons/limit-12.2.png differ diff --git a/web/www/routino/icons/limit-12.3.png b/web/www/routino/icons/limit-12.3.png new file mode 100644 index 0000000..395f1c5 Binary files /dev/null and b/web/www/routino/icons/limit-12.3.png differ diff --git a/web/www/routino/icons/limit-12.4.png b/web/www/routino/icons/limit-12.4.png new file mode 100644 index 0000000..4ed3146 Binary files /dev/null and b/web/www/routino/icons/limit-12.4.png differ diff --git a/web/www/routino/icons/limit-12.5.png b/web/www/routino/icons/limit-12.5.png new file mode 100644 index 0000000..cc0ebf4 Binary files /dev/null and b/web/www/routino/icons/limit-12.5.png differ diff --git a/web/www/routino/icons/limit-12.6.png b/web/www/routino/icons/limit-12.6.png new file mode 100644 index 0000000..1e1ba98 Binary files /dev/null and b/web/www/routino/icons/limit-12.6.png differ diff --git a/web/www/routino/icons/limit-12.7.png b/web/www/routino/icons/limit-12.7.png new file mode 100644 index 0000000..285c24e Binary files /dev/null and b/web/www/routino/icons/limit-12.7.png differ diff --git a/web/www/routino/icons/limit-12.8.png b/web/www/routino/icons/limit-12.8.png new file mode 100644 index 0000000..21d392f Binary files /dev/null and b/web/www/routino/icons/limit-12.8.png differ diff --git a/web/www/routino/icons/limit-12.9.png b/web/www/routino/icons/limit-12.9.png new file mode 100644 index 0000000..ef15df9 Binary files /dev/null and b/web/www/routino/icons/limit-12.9.png differ diff --git a/web/www/routino/icons/limit-12.png b/web/www/routino/icons/limit-12.png new file mode 100644 index 0000000..47e9b77 Binary files /dev/null and b/web/www/routino/icons/limit-12.png differ diff --git a/web/www/routino/icons/limit-120.png b/web/www/routino/icons/limit-120.png new file mode 100644 index 0000000..16cd836 Binary files /dev/null and b/web/www/routino/icons/limit-120.png differ diff --git a/web/www/routino/icons/limit-121.png b/web/www/routino/icons/limit-121.png new file mode 100644 index 0000000..4193181 Binary files /dev/null and b/web/www/routino/icons/limit-121.png differ diff --git a/web/www/routino/icons/limit-122.png b/web/www/routino/icons/limit-122.png new file mode 100644 index 0000000..a7be41d Binary files /dev/null and b/web/www/routino/icons/limit-122.png differ diff --git a/web/www/routino/icons/limit-123.png b/web/www/routino/icons/limit-123.png new file mode 100644 index 0000000..f2a4f17 Binary files /dev/null and b/web/www/routino/icons/limit-123.png differ diff --git a/web/www/routino/icons/limit-124.png b/web/www/routino/icons/limit-124.png new file mode 100644 index 0000000..ad882d2 Binary files /dev/null and b/web/www/routino/icons/limit-124.png differ diff --git a/web/www/routino/icons/limit-125.png b/web/www/routino/icons/limit-125.png new file mode 100644 index 0000000..4380e3b Binary files /dev/null and b/web/www/routino/icons/limit-125.png differ diff --git a/web/www/routino/icons/limit-126.png b/web/www/routino/icons/limit-126.png new file mode 100644 index 0000000..794dc21 Binary files /dev/null and b/web/www/routino/icons/limit-126.png differ diff --git a/web/www/routino/icons/limit-127.png b/web/www/routino/icons/limit-127.png new file mode 100644 index 0000000..f99d6e7 Binary files /dev/null and b/web/www/routino/icons/limit-127.png differ diff --git a/web/www/routino/icons/limit-128.png b/web/www/routino/icons/limit-128.png new file mode 100644 index 0000000..89f1522 Binary files /dev/null and b/web/www/routino/icons/limit-128.png differ diff --git a/web/www/routino/icons/limit-129.png b/web/www/routino/icons/limit-129.png new file mode 100644 index 0000000..16b4333 Binary files /dev/null and b/web/www/routino/icons/limit-129.png differ diff --git a/web/www/routino/icons/limit-13.0.png b/web/www/routino/icons/limit-13.0.png new file mode 100644 index 0000000..0007cc5 Binary files /dev/null and b/web/www/routino/icons/limit-13.0.png differ diff --git a/web/www/routino/icons/limit-13.1.png b/web/www/routino/icons/limit-13.1.png new file mode 100644 index 0000000..2638eee Binary files /dev/null and b/web/www/routino/icons/limit-13.1.png differ diff --git a/web/www/routino/icons/limit-13.2.png b/web/www/routino/icons/limit-13.2.png new file mode 100644 index 0000000..e3e3235 Binary files /dev/null and b/web/www/routino/icons/limit-13.2.png differ diff --git a/web/www/routino/icons/limit-13.3.png b/web/www/routino/icons/limit-13.3.png new file mode 100644 index 0000000..51d365e Binary files /dev/null and b/web/www/routino/icons/limit-13.3.png differ diff --git a/web/www/routino/icons/limit-13.4.png b/web/www/routino/icons/limit-13.4.png new file mode 100644 index 0000000..fc5bd7f Binary files /dev/null and b/web/www/routino/icons/limit-13.4.png differ diff --git a/web/www/routino/icons/limit-13.5.png b/web/www/routino/icons/limit-13.5.png new file mode 100644 index 0000000..240f106 Binary files /dev/null and b/web/www/routino/icons/limit-13.5.png differ diff --git a/web/www/routino/icons/limit-13.6.png b/web/www/routino/icons/limit-13.6.png new file mode 100644 index 0000000..cfc242d Binary files /dev/null and b/web/www/routino/icons/limit-13.6.png differ diff --git a/web/www/routino/icons/limit-13.7.png b/web/www/routino/icons/limit-13.7.png new file mode 100644 index 0000000..cff7b13 Binary files /dev/null and b/web/www/routino/icons/limit-13.7.png differ diff --git a/web/www/routino/icons/limit-13.8.png b/web/www/routino/icons/limit-13.8.png new file mode 100644 index 0000000..ebd5059 Binary files /dev/null and b/web/www/routino/icons/limit-13.8.png differ diff --git a/web/www/routino/icons/limit-13.9.png b/web/www/routino/icons/limit-13.9.png new file mode 100644 index 0000000..66af065 Binary files /dev/null and b/web/www/routino/icons/limit-13.9.png differ diff --git a/web/www/routino/icons/limit-13.png b/web/www/routino/icons/limit-13.png new file mode 100644 index 0000000..aa1e634 Binary files /dev/null and b/web/www/routino/icons/limit-13.png differ diff --git a/web/www/routino/icons/limit-130.png b/web/www/routino/icons/limit-130.png new file mode 100644 index 0000000..dd4d5c0 Binary files /dev/null and b/web/www/routino/icons/limit-130.png differ diff --git a/web/www/routino/icons/limit-131.png b/web/www/routino/icons/limit-131.png new file mode 100644 index 0000000..d322423 Binary files /dev/null and b/web/www/routino/icons/limit-131.png differ diff --git a/web/www/routino/icons/limit-132.png b/web/www/routino/icons/limit-132.png new file mode 100644 index 0000000..8b0450d Binary files /dev/null and b/web/www/routino/icons/limit-132.png differ diff --git a/web/www/routino/icons/limit-133.png b/web/www/routino/icons/limit-133.png new file mode 100644 index 0000000..b589818 Binary files /dev/null and b/web/www/routino/icons/limit-133.png differ diff --git a/web/www/routino/icons/limit-134.png b/web/www/routino/icons/limit-134.png new file mode 100644 index 0000000..b383a4d Binary files /dev/null and b/web/www/routino/icons/limit-134.png differ diff --git a/web/www/routino/icons/limit-135.png b/web/www/routino/icons/limit-135.png new file mode 100644 index 0000000..b479683 Binary files /dev/null and b/web/www/routino/icons/limit-135.png differ diff --git a/web/www/routino/icons/limit-136.png b/web/www/routino/icons/limit-136.png new file mode 100644 index 0000000..44ab498 Binary files /dev/null and b/web/www/routino/icons/limit-136.png differ diff --git a/web/www/routino/icons/limit-137.png b/web/www/routino/icons/limit-137.png new file mode 100644 index 0000000..7e0d0ae Binary files /dev/null and b/web/www/routino/icons/limit-137.png differ diff --git a/web/www/routino/icons/limit-138.png b/web/www/routino/icons/limit-138.png new file mode 100644 index 0000000..fce9d0c Binary files /dev/null and b/web/www/routino/icons/limit-138.png differ diff --git a/web/www/routino/icons/limit-139.png b/web/www/routino/icons/limit-139.png new file mode 100644 index 0000000..4fa82d9 Binary files /dev/null and b/web/www/routino/icons/limit-139.png differ diff --git a/web/www/routino/icons/limit-14.0.png b/web/www/routino/icons/limit-14.0.png new file mode 100644 index 0000000..7f93fa2 Binary files /dev/null and b/web/www/routino/icons/limit-14.0.png differ diff --git a/web/www/routino/icons/limit-14.1.png b/web/www/routino/icons/limit-14.1.png new file mode 100644 index 0000000..7495eb2 Binary files /dev/null and b/web/www/routino/icons/limit-14.1.png differ diff --git a/web/www/routino/icons/limit-14.2.png b/web/www/routino/icons/limit-14.2.png new file mode 100644 index 0000000..3dfb2ff Binary files /dev/null and b/web/www/routino/icons/limit-14.2.png differ diff --git a/web/www/routino/icons/limit-14.3.png b/web/www/routino/icons/limit-14.3.png new file mode 100644 index 0000000..8c9986f Binary files /dev/null and b/web/www/routino/icons/limit-14.3.png differ diff --git a/web/www/routino/icons/limit-14.4.png b/web/www/routino/icons/limit-14.4.png new file mode 100644 index 0000000..f148833 Binary files /dev/null and b/web/www/routino/icons/limit-14.4.png differ diff --git a/web/www/routino/icons/limit-14.5.png b/web/www/routino/icons/limit-14.5.png new file mode 100644 index 0000000..c605734 Binary files /dev/null and b/web/www/routino/icons/limit-14.5.png differ diff --git a/web/www/routino/icons/limit-14.6.png b/web/www/routino/icons/limit-14.6.png new file mode 100644 index 0000000..01b5295 Binary files /dev/null and b/web/www/routino/icons/limit-14.6.png differ diff --git a/web/www/routino/icons/limit-14.7.png b/web/www/routino/icons/limit-14.7.png new file mode 100644 index 0000000..f422d23 Binary files /dev/null and b/web/www/routino/icons/limit-14.7.png differ diff --git a/web/www/routino/icons/limit-14.8.png b/web/www/routino/icons/limit-14.8.png new file mode 100644 index 0000000..934de9a Binary files /dev/null and b/web/www/routino/icons/limit-14.8.png differ diff --git a/web/www/routino/icons/limit-14.9.png b/web/www/routino/icons/limit-14.9.png new file mode 100644 index 0000000..d95a0c2 Binary files /dev/null and b/web/www/routino/icons/limit-14.9.png differ diff --git a/web/www/routino/icons/limit-14.png b/web/www/routino/icons/limit-14.png new file mode 100644 index 0000000..1c88286 Binary files /dev/null and b/web/www/routino/icons/limit-14.png differ diff --git a/web/www/routino/icons/limit-140.png b/web/www/routino/icons/limit-140.png new file mode 100644 index 0000000..9bce99b Binary files /dev/null and b/web/www/routino/icons/limit-140.png differ diff --git a/web/www/routino/icons/limit-141.png b/web/www/routino/icons/limit-141.png new file mode 100644 index 0000000..64a0ba6 Binary files /dev/null and b/web/www/routino/icons/limit-141.png differ diff --git a/web/www/routino/icons/limit-142.png b/web/www/routino/icons/limit-142.png new file mode 100644 index 0000000..b1b6249 Binary files /dev/null and b/web/www/routino/icons/limit-142.png differ diff --git a/web/www/routino/icons/limit-143.png b/web/www/routino/icons/limit-143.png new file mode 100644 index 0000000..5b4a58c Binary files /dev/null and b/web/www/routino/icons/limit-143.png differ diff --git a/web/www/routino/icons/limit-144.png b/web/www/routino/icons/limit-144.png new file mode 100644 index 0000000..d86d6c5 Binary files /dev/null and b/web/www/routino/icons/limit-144.png differ diff --git a/web/www/routino/icons/limit-145.png b/web/www/routino/icons/limit-145.png new file mode 100644 index 0000000..165c92a Binary files /dev/null and b/web/www/routino/icons/limit-145.png differ diff --git a/web/www/routino/icons/limit-146.png b/web/www/routino/icons/limit-146.png new file mode 100644 index 0000000..70217c0 Binary files /dev/null and b/web/www/routino/icons/limit-146.png differ diff --git a/web/www/routino/icons/limit-147.png b/web/www/routino/icons/limit-147.png new file mode 100644 index 0000000..170edf8 Binary files /dev/null and b/web/www/routino/icons/limit-147.png differ diff --git a/web/www/routino/icons/limit-148.png b/web/www/routino/icons/limit-148.png new file mode 100644 index 0000000..864ce76 Binary files /dev/null and b/web/www/routino/icons/limit-148.png differ diff --git a/web/www/routino/icons/limit-149.png b/web/www/routino/icons/limit-149.png new file mode 100644 index 0000000..8f7df2d Binary files /dev/null and b/web/www/routino/icons/limit-149.png differ diff --git a/web/www/routino/icons/limit-15.0.png b/web/www/routino/icons/limit-15.0.png new file mode 100644 index 0000000..a243a96 Binary files /dev/null and b/web/www/routino/icons/limit-15.0.png differ diff --git a/web/www/routino/icons/limit-15.1.png b/web/www/routino/icons/limit-15.1.png new file mode 100644 index 0000000..f358757 Binary files /dev/null and b/web/www/routino/icons/limit-15.1.png differ diff --git a/web/www/routino/icons/limit-15.2.png b/web/www/routino/icons/limit-15.2.png new file mode 100644 index 0000000..9011df6 Binary files /dev/null and b/web/www/routino/icons/limit-15.2.png differ diff --git a/web/www/routino/icons/limit-15.3.png b/web/www/routino/icons/limit-15.3.png new file mode 100644 index 0000000..6844ec9 Binary files /dev/null and b/web/www/routino/icons/limit-15.3.png differ diff --git a/web/www/routino/icons/limit-15.4.png b/web/www/routino/icons/limit-15.4.png new file mode 100644 index 0000000..24b88aa Binary files /dev/null and b/web/www/routino/icons/limit-15.4.png differ diff --git a/web/www/routino/icons/limit-15.5.png b/web/www/routino/icons/limit-15.5.png new file mode 100644 index 0000000..95edb73 Binary files /dev/null and b/web/www/routino/icons/limit-15.5.png differ diff --git a/web/www/routino/icons/limit-15.6.png b/web/www/routino/icons/limit-15.6.png new file mode 100644 index 0000000..d358365 Binary files /dev/null and b/web/www/routino/icons/limit-15.6.png differ diff --git a/web/www/routino/icons/limit-15.7.png b/web/www/routino/icons/limit-15.7.png new file mode 100644 index 0000000..0f37478 Binary files /dev/null and b/web/www/routino/icons/limit-15.7.png differ diff --git a/web/www/routino/icons/limit-15.8.png b/web/www/routino/icons/limit-15.8.png new file mode 100644 index 0000000..09f5330 Binary files /dev/null and b/web/www/routino/icons/limit-15.8.png differ diff --git a/web/www/routino/icons/limit-15.9.png b/web/www/routino/icons/limit-15.9.png new file mode 100644 index 0000000..a8cbf6f Binary files /dev/null and b/web/www/routino/icons/limit-15.9.png differ diff --git a/web/www/routino/icons/limit-15.png b/web/www/routino/icons/limit-15.png new file mode 100644 index 0000000..3c4446c Binary files /dev/null and b/web/www/routino/icons/limit-15.png differ diff --git a/web/www/routino/icons/limit-150.png b/web/www/routino/icons/limit-150.png new file mode 100644 index 0000000..9cc5942 Binary files /dev/null and b/web/www/routino/icons/limit-150.png differ diff --git a/web/www/routino/icons/limit-151.png b/web/www/routino/icons/limit-151.png new file mode 100644 index 0000000..5221559 Binary files /dev/null and b/web/www/routino/icons/limit-151.png differ diff --git a/web/www/routino/icons/limit-152.png b/web/www/routino/icons/limit-152.png new file mode 100644 index 0000000..7a553a0 Binary files /dev/null and b/web/www/routino/icons/limit-152.png differ diff --git a/web/www/routino/icons/limit-153.png b/web/www/routino/icons/limit-153.png new file mode 100644 index 0000000..b23a3b2 Binary files /dev/null and b/web/www/routino/icons/limit-153.png differ diff --git a/web/www/routino/icons/limit-154.png b/web/www/routino/icons/limit-154.png new file mode 100644 index 0000000..1650af3 Binary files /dev/null and b/web/www/routino/icons/limit-154.png differ diff --git a/web/www/routino/icons/limit-155.png b/web/www/routino/icons/limit-155.png new file mode 100644 index 0000000..a62c3dc Binary files /dev/null and b/web/www/routino/icons/limit-155.png differ diff --git a/web/www/routino/icons/limit-156.png b/web/www/routino/icons/limit-156.png new file mode 100644 index 0000000..f39fddc Binary files /dev/null and b/web/www/routino/icons/limit-156.png differ diff --git a/web/www/routino/icons/limit-157.png b/web/www/routino/icons/limit-157.png new file mode 100644 index 0000000..14168dd Binary files /dev/null and b/web/www/routino/icons/limit-157.png differ diff --git a/web/www/routino/icons/limit-158.png b/web/www/routino/icons/limit-158.png new file mode 100644 index 0000000..854f737 Binary files /dev/null and b/web/www/routino/icons/limit-158.png differ diff --git a/web/www/routino/icons/limit-159.png b/web/www/routino/icons/limit-159.png new file mode 100644 index 0000000..513314a Binary files /dev/null and b/web/www/routino/icons/limit-159.png differ diff --git a/web/www/routino/icons/limit-16.0.png b/web/www/routino/icons/limit-16.0.png new file mode 100644 index 0000000..9f1244c Binary files /dev/null and b/web/www/routino/icons/limit-16.0.png differ diff --git a/web/www/routino/icons/limit-16.1.png b/web/www/routino/icons/limit-16.1.png new file mode 100644 index 0000000..db59558 Binary files /dev/null and b/web/www/routino/icons/limit-16.1.png differ diff --git a/web/www/routino/icons/limit-16.2.png b/web/www/routino/icons/limit-16.2.png new file mode 100644 index 0000000..b3edeed Binary files /dev/null and b/web/www/routino/icons/limit-16.2.png differ diff --git a/web/www/routino/icons/limit-16.3.png b/web/www/routino/icons/limit-16.3.png new file mode 100644 index 0000000..0d80cd4 Binary files /dev/null and b/web/www/routino/icons/limit-16.3.png differ diff --git a/web/www/routino/icons/limit-16.4.png b/web/www/routino/icons/limit-16.4.png new file mode 100644 index 0000000..c6c0038 Binary files /dev/null and b/web/www/routino/icons/limit-16.4.png differ diff --git a/web/www/routino/icons/limit-16.5.png b/web/www/routino/icons/limit-16.5.png new file mode 100644 index 0000000..b384f77 Binary files /dev/null and b/web/www/routino/icons/limit-16.5.png differ diff --git a/web/www/routino/icons/limit-16.6.png b/web/www/routino/icons/limit-16.6.png new file mode 100644 index 0000000..47a435f Binary files /dev/null and b/web/www/routino/icons/limit-16.6.png differ diff --git a/web/www/routino/icons/limit-16.7.png b/web/www/routino/icons/limit-16.7.png new file mode 100644 index 0000000..f84dc90 Binary files /dev/null and b/web/www/routino/icons/limit-16.7.png differ diff --git a/web/www/routino/icons/limit-16.8.png b/web/www/routino/icons/limit-16.8.png new file mode 100644 index 0000000..93b0e11 Binary files /dev/null and b/web/www/routino/icons/limit-16.8.png differ diff --git a/web/www/routino/icons/limit-16.9.png b/web/www/routino/icons/limit-16.9.png new file mode 100644 index 0000000..ab44581 Binary files /dev/null and b/web/www/routino/icons/limit-16.9.png differ diff --git a/web/www/routino/icons/limit-16.png b/web/www/routino/icons/limit-16.png new file mode 100644 index 0000000..e0b8fe4 Binary files /dev/null and b/web/www/routino/icons/limit-16.png differ diff --git a/web/www/routino/icons/limit-160.png b/web/www/routino/icons/limit-160.png new file mode 100644 index 0000000..6cc29c8 Binary files /dev/null and b/web/www/routino/icons/limit-160.png differ diff --git a/web/www/routino/icons/limit-17.0.png b/web/www/routino/icons/limit-17.0.png new file mode 100644 index 0000000..40f9c66 Binary files /dev/null and b/web/www/routino/icons/limit-17.0.png differ diff --git a/web/www/routino/icons/limit-17.1.png b/web/www/routino/icons/limit-17.1.png new file mode 100644 index 0000000..9df040e Binary files /dev/null and b/web/www/routino/icons/limit-17.1.png differ diff --git a/web/www/routino/icons/limit-17.2.png b/web/www/routino/icons/limit-17.2.png new file mode 100644 index 0000000..d005743 Binary files /dev/null and b/web/www/routino/icons/limit-17.2.png differ diff --git a/web/www/routino/icons/limit-17.3.png b/web/www/routino/icons/limit-17.3.png new file mode 100644 index 0000000..9d3e0d5 Binary files /dev/null and b/web/www/routino/icons/limit-17.3.png differ diff --git a/web/www/routino/icons/limit-17.4.png b/web/www/routino/icons/limit-17.4.png new file mode 100644 index 0000000..c21f8fb Binary files /dev/null and b/web/www/routino/icons/limit-17.4.png differ diff --git a/web/www/routino/icons/limit-17.5.png b/web/www/routino/icons/limit-17.5.png new file mode 100644 index 0000000..d832cc9 Binary files /dev/null and b/web/www/routino/icons/limit-17.5.png differ diff --git a/web/www/routino/icons/limit-17.6.png b/web/www/routino/icons/limit-17.6.png new file mode 100644 index 0000000..44aa02c Binary files /dev/null and b/web/www/routino/icons/limit-17.6.png differ diff --git a/web/www/routino/icons/limit-17.7.png b/web/www/routino/icons/limit-17.7.png new file mode 100644 index 0000000..59add22 Binary files /dev/null and b/web/www/routino/icons/limit-17.7.png differ diff --git a/web/www/routino/icons/limit-17.8.png b/web/www/routino/icons/limit-17.8.png new file mode 100644 index 0000000..dcb0c80 Binary files /dev/null and b/web/www/routino/icons/limit-17.8.png differ diff --git a/web/www/routino/icons/limit-17.9.png b/web/www/routino/icons/limit-17.9.png new file mode 100644 index 0000000..b9e4b3b Binary files /dev/null and b/web/www/routino/icons/limit-17.9.png differ diff --git a/web/www/routino/icons/limit-17.png b/web/www/routino/icons/limit-17.png new file mode 100644 index 0000000..7c46a9f Binary files /dev/null and b/web/www/routino/icons/limit-17.png differ diff --git a/web/www/routino/icons/limit-18.0.png b/web/www/routino/icons/limit-18.0.png new file mode 100644 index 0000000..e98a93c Binary files /dev/null and b/web/www/routino/icons/limit-18.0.png differ diff --git a/web/www/routino/icons/limit-18.1.png b/web/www/routino/icons/limit-18.1.png new file mode 100644 index 0000000..4fd9f47 Binary files /dev/null and b/web/www/routino/icons/limit-18.1.png differ diff --git a/web/www/routino/icons/limit-18.2.png b/web/www/routino/icons/limit-18.2.png new file mode 100644 index 0000000..00f898d Binary files /dev/null and b/web/www/routino/icons/limit-18.2.png differ diff --git a/web/www/routino/icons/limit-18.3.png b/web/www/routino/icons/limit-18.3.png new file mode 100644 index 0000000..0cfd866 Binary files /dev/null and b/web/www/routino/icons/limit-18.3.png differ diff --git a/web/www/routino/icons/limit-18.4.png b/web/www/routino/icons/limit-18.4.png new file mode 100644 index 0000000..7cc57c9 Binary files /dev/null and b/web/www/routino/icons/limit-18.4.png differ diff --git a/web/www/routino/icons/limit-18.5.png b/web/www/routino/icons/limit-18.5.png new file mode 100644 index 0000000..fad46e3 Binary files /dev/null and b/web/www/routino/icons/limit-18.5.png differ diff --git a/web/www/routino/icons/limit-18.6.png b/web/www/routino/icons/limit-18.6.png new file mode 100644 index 0000000..5e31c9f Binary files /dev/null and b/web/www/routino/icons/limit-18.6.png differ diff --git a/web/www/routino/icons/limit-18.7.png b/web/www/routino/icons/limit-18.7.png new file mode 100644 index 0000000..0667779 Binary files /dev/null and b/web/www/routino/icons/limit-18.7.png differ diff --git a/web/www/routino/icons/limit-18.8.png b/web/www/routino/icons/limit-18.8.png new file mode 100644 index 0000000..f1bbcdd Binary files /dev/null and b/web/www/routino/icons/limit-18.8.png differ diff --git a/web/www/routino/icons/limit-18.9.png b/web/www/routino/icons/limit-18.9.png new file mode 100644 index 0000000..18daefc Binary files /dev/null and b/web/www/routino/icons/limit-18.9.png differ diff --git a/web/www/routino/icons/limit-18.png b/web/www/routino/icons/limit-18.png new file mode 100644 index 0000000..26caae6 Binary files /dev/null and b/web/www/routino/icons/limit-18.png differ diff --git a/web/www/routino/icons/limit-19.0.png b/web/www/routino/icons/limit-19.0.png new file mode 100644 index 0000000..59c9f41 Binary files /dev/null and b/web/www/routino/icons/limit-19.0.png differ diff --git a/web/www/routino/icons/limit-19.1.png b/web/www/routino/icons/limit-19.1.png new file mode 100644 index 0000000..5b1f015 Binary files /dev/null and b/web/www/routino/icons/limit-19.1.png differ diff --git a/web/www/routino/icons/limit-19.2.png b/web/www/routino/icons/limit-19.2.png new file mode 100644 index 0000000..4b43319 Binary files /dev/null and b/web/www/routino/icons/limit-19.2.png differ diff --git a/web/www/routino/icons/limit-19.3.png b/web/www/routino/icons/limit-19.3.png new file mode 100644 index 0000000..6db46b0 Binary files /dev/null and b/web/www/routino/icons/limit-19.3.png differ diff --git a/web/www/routino/icons/limit-19.4.png b/web/www/routino/icons/limit-19.4.png new file mode 100644 index 0000000..d950112 Binary files /dev/null and b/web/www/routino/icons/limit-19.4.png differ diff --git a/web/www/routino/icons/limit-19.5.png b/web/www/routino/icons/limit-19.5.png new file mode 100644 index 0000000..f661c94 Binary files /dev/null and b/web/www/routino/icons/limit-19.5.png differ diff --git a/web/www/routino/icons/limit-19.6.png b/web/www/routino/icons/limit-19.6.png new file mode 100644 index 0000000..5d18cef Binary files /dev/null and b/web/www/routino/icons/limit-19.6.png differ diff --git a/web/www/routino/icons/limit-19.7.png b/web/www/routino/icons/limit-19.7.png new file mode 100644 index 0000000..2e4d2d4 Binary files /dev/null and b/web/www/routino/icons/limit-19.7.png differ diff --git a/web/www/routino/icons/limit-19.8.png b/web/www/routino/icons/limit-19.8.png new file mode 100644 index 0000000..720213e Binary files /dev/null and b/web/www/routino/icons/limit-19.8.png differ diff --git a/web/www/routino/icons/limit-19.9.png b/web/www/routino/icons/limit-19.9.png new file mode 100644 index 0000000..1bb4406 Binary files /dev/null and b/web/www/routino/icons/limit-19.9.png differ diff --git a/web/www/routino/icons/limit-19.png b/web/www/routino/icons/limit-19.png new file mode 100644 index 0000000..01aa718 Binary files /dev/null and b/web/www/routino/icons/limit-19.png differ diff --git a/web/www/routino/icons/limit-2.0.png b/web/www/routino/icons/limit-2.0.png new file mode 100644 index 0000000..475e604 Binary files /dev/null and b/web/www/routino/icons/limit-2.0.png differ diff --git a/web/www/routino/icons/limit-2.1.png b/web/www/routino/icons/limit-2.1.png new file mode 100644 index 0000000..0a544a1 Binary files /dev/null and b/web/www/routino/icons/limit-2.1.png differ diff --git a/web/www/routino/icons/limit-2.2.png b/web/www/routino/icons/limit-2.2.png new file mode 100644 index 0000000..deed784 Binary files /dev/null and b/web/www/routino/icons/limit-2.2.png differ diff --git a/web/www/routino/icons/limit-2.3.png b/web/www/routino/icons/limit-2.3.png new file mode 100644 index 0000000..6087a9b Binary files /dev/null and b/web/www/routino/icons/limit-2.3.png differ diff --git a/web/www/routino/icons/limit-2.4.png b/web/www/routino/icons/limit-2.4.png new file mode 100644 index 0000000..94ff741 Binary files /dev/null and b/web/www/routino/icons/limit-2.4.png differ diff --git a/web/www/routino/icons/limit-2.5.png b/web/www/routino/icons/limit-2.5.png new file mode 100644 index 0000000..a1bb205 Binary files /dev/null and b/web/www/routino/icons/limit-2.5.png differ diff --git a/web/www/routino/icons/limit-2.6.png b/web/www/routino/icons/limit-2.6.png new file mode 100644 index 0000000..ca434ef Binary files /dev/null and b/web/www/routino/icons/limit-2.6.png differ diff --git a/web/www/routino/icons/limit-2.7.png b/web/www/routino/icons/limit-2.7.png new file mode 100644 index 0000000..17ae517 Binary files /dev/null and b/web/www/routino/icons/limit-2.7.png differ diff --git a/web/www/routino/icons/limit-2.8.png b/web/www/routino/icons/limit-2.8.png new file mode 100644 index 0000000..d879af5 Binary files /dev/null and b/web/www/routino/icons/limit-2.8.png differ diff --git a/web/www/routino/icons/limit-2.9.png b/web/www/routino/icons/limit-2.9.png new file mode 100644 index 0000000..9ecb9d8 Binary files /dev/null and b/web/www/routino/icons/limit-2.9.png differ diff --git a/web/www/routino/icons/limit-2.png b/web/www/routino/icons/limit-2.png new file mode 100644 index 0000000..b734451 Binary files /dev/null and b/web/www/routino/icons/limit-2.png differ diff --git a/web/www/routino/icons/limit-20.0.png b/web/www/routino/icons/limit-20.0.png new file mode 100644 index 0000000..9ed3ed1 Binary files /dev/null and b/web/www/routino/icons/limit-20.0.png differ diff --git a/web/www/routino/icons/limit-20.png b/web/www/routino/icons/limit-20.png new file mode 100644 index 0000000..675ab62 Binary files /dev/null and b/web/www/routino/icons/limit-20.png differ diff --git a/web/www/routino/icons/limit-21.png b/web/www/routino/icons/limit-21.png new file mode 100644 index 0000000..a373fa7 Binary files /dev/null and b/web/www/routino/icons/limit-21.png differ diff --git a/web/www/routino/icons/limit-22.png b/web/www/routino/icons/limit-22.png new file mode 100644 index 0000000..c94c15d Binary files /dev/null and b/web/www/routino/icons/limit-22.png differ diff --git a/web/www/routino/icons/limit-23.png b/web/www/routino/icons/limit-23.png new file mode 100644 index 0000000..5f17e29 Binary files /dev/null and b/web/www/routino/icons/limit-23.png differ diff --git a/web/www/routino/icons/limit-24.png b/web/www/routino/icons/limit-24.png new file mode 100644 index 0000000..82e88dc Binary files /dev/null and b/web/www/routino/icons/limit-24.png differ diff --git a/web/www/routino/icons/limit-25.png b/web/www/routino/icons/limit-25.png new file mode 100644 index 0000000..2c2c46b Binary files /dev/null and b/web/www/routino/icons/limit-25.png differ diff --git a/web/www/routino/icons/limit-26.png b/web/www/routino/icons/limit-26.png new file mode 100644 index 0000000..80b54de Binary files /dev/null and b/web/www/routino/icons/limit-26.png differ diff --git a/web/www/routino/icons/limit-27.png b/web/www/routino/icons/limit-27.png new file mode 100644 index 0000000..25bbc40 Binary files /dev/null and b/web/www/routino/icons/limit-27.png differ diff --git a/web/www/routino/icons/limit-28.png b/web/www/routino/icons/limit-28.png new file mode 100644 index 0000000..3c3b4fe Binary files /dev/null and b/web/www/routino/icons/limit-28.png differ diff --git a/web/www/routino/icons/limit-29.png b/web/www/routino/icons/limit-29.png new file mode 100644 index 0000000..a910f6f Binary files /dev/null and b/web/www/routino/icons/limit-29.png differ diff --git a/web/www/routino/icons/limit-3.0.png b/web/www/routino/icons/limit-3.0.png new file mode 100644 index 0000000..56022f4 Binary files /dev/null and b/web/www/routino/icons/limit-3.0.png differ diff --git a/web/www/routino/icons/limit-3.1.png b/web/www/routino/icons/limit-3.1.png new file mode 100644 index 0000000..78338dc Binary files /dev/null and b/web/www/routino/icons/limit-3.1.png differ diff --git a/web/www/routino/icons/limit-3.2.png b/web/www/routino/icons/limit-3.2.png new file mode 100644 index 0000000..500cc94 Binary files /dev/null and b/web/www/routino/icons/limit-3.2.png differ diff --git a/web/www/routino/icons/limit-3.3.png b/web/www/routino/icons/limit-3.3.png new file mode 100644 index 0000000..9dc15ee Binary files /dev/null and b/web/www/routino/icons/limit-3.3.png differ diff --git a/web/www/routino/icons/limit-3.4.png b/web/www/routino/icons/limit-3.4.png new file mode 100644 index 0000000..cf5583d Binary files /dev/null and b/web/www/routino/icons/limit-3.4.png differ diff --git a/web/www/routino/icons/limit-3.5.png b/web/www/routino/icons/limit-3.5.png new file mode 100644 index 0000000..d42e247 Binary files /dev/null and b/web/www/routino/icons/limit-3.5.png differ diff --git a/web/www/routino/icons/limit-3.6.png b/web/www/routino/icons/limit-3.6.png new file mode 100644 index 0000000..af8f5be Binary files /dev/null and b/web/www/routino/icons/limit-3.6.png differ diff --git a/web/www/routino/icons/limit-3.7.png b/web/www/routino/icons/limit-3.7.png new file mode 100644 index 0000000..8956978 Binary files /dev/null and b/web/www/routino/icons/limit-3.7.png differ diff --git a/web/www/routino/icons/limit-3.8.png b/web/www/routino/icons/limit-3.8.png new file mode 100644 index 0000000..22e26fe Binary files /dev/null and b/web/www/routino/icons/limit-3.8.png differ diff --git a/web/www/routino/icons/limit-3.9.png b/web/www/routino/icons/limit-3.9.png new file mode 100644 index 0000000..6d8f22f Binary files /dev/null and b/web/www/routino/icons/limit-3.9.png differ diff --git a/web/www/routino/icons/limit-3.png b/web/www/routino/icons/limit-3.png new file mode 100644 index 0000000..8426d15 Binary files /dev/null and b/web/www/routino/icons/limit-3.png differ diff --git a/web/www/routino/icons/limit-30.png b/web/www/routino/icons/limit-30.png new file mode 100644 index 0000000..78ddb4c Binary files /dev/null and b/web/www/routino/icons/limit-30.png differ diff --git a/web/www/routino/icons/limit-31.png b/web/www/routino/icons/limit-31.png new file mode 100644 index 0000000..868746e Binary files /dev/null and b/web/www/routino/icons/limit-31.png differ diff --git a/web/www/routino/icons/limit-32.png b/web/www/routino/icons/limit-32.png new file mode 100644 index 0000000..1019b1a Binary files /dev/null and b/web/www/routino/icons/limit-32.png differ diff --git a/web/www/routino/icons/limit-33.png b/web/www/routino/icons/limit-33.png new file mode 100644 index 0000000..3fbed36 Binary files /dev/null and b/web/www/routino/icons/limit-33.png differ diff --git a/web/www/routino/icons/limit-34.png b/web/www/routino/icons/limit-34.png new file mode 100644 index 0000000..b0e1805 Binary files /dev/null and b/web/www/routino/icons/limit-34.png differ diff --git a/web/www/routino/icons/limit-35.png b/web/www/routino/icons/limit-35.png new file mode 100644 index 0000000..9e1b38a Binary files /dev/null and b/web/www/routino/icons/limit-35.png differ diff --git a/web/www/routino/icons/limit-36.png b/web/www/routino/icons/limit-36.png new file mode 100644 index 0000000..281595e Binary files /dev/null and b/web/www/routino/icons/limit-36.png differ diff --git a/web/www/routino/icons/limit-37.png b/web/www/routino/icons/limit-37.png new file mode 100644 index 0000000..f4528e4 Binary files /dev/null and b/web/www/routino/icons/limit-37.png differ diff --git a/web/www/routino/icons/limit-38.png b/web/www/routino/icons/limit-38.png new file mode 100644 index 0000000..6369559 Binary files /dev/null and b/web/www/routino/icons/limit-38.png differ diff --git a/web/www/routino/icons/limit-39.png b/web/www/routino/icons/limit-39.png new file mode 100644 index 0000000..84dd891 Binary files /dev/null and b/web/www/routino/icons/limit-39.png differ diff --git a/web/www/routino/icons/limit-4.0.png b/web/www/routino/icons/limit-4.0.png new file mode 100644 index 0000000..39a2c19 Binary files /dev/null and b/web/www/routino/icons/limit-4.0.png differ diff --git a/web/www/routino/icons/limit-4.1.png b/web/www/routino/icons/limit-4.1.png new file mode 100644 index 0000000..4e8d005 Binary files /dev/null and b/web/www/routino/icons/limit-4.1.png differ diff --git a/web/www/routino/icons/limit-4.2.png b/web/www/routino/icons/limit-4.2.png new file mode 100644 index 0000000..d90c7e3 Binary files /dev/null and b/web/www/routino/icons/limit-4.2.png differ diff --git a/web/www/routino/icons/limit-4.3.png b/web/www/routino/icons/limit-4.3.png new file mode 100644 index 0000000..73f0ba5 Binary files /dev/null and b/web/www/routino/icons/limit-4.3.png differ diff --git a/web/www/routino/icons/limit-4.4.png b/web/www/routino/icons/limit-4.4.png new file mode 100644 index 0000000..d024035 Binary files /dev/null and b/web/www/routino/icons/limit-4.4.png differ diff --git a/web/www/routino/icons/limit-4.5.png b/web/www/routino/icons/limit-4.5.png new file mode 100644 index 0000000..bbbc15e Binary files /dev/null and b/web/www/routino/icons/limit-4.5.png differ diff --git a/web/www/routino/icons/limit-4.6.png b/web/www/routino/icons/limit-4.6.png new file mode 100644 index 0000000..be0f1d0 Binary files /dev/null and b/web/www/routino/icons/limit-4.6.png differ diff --git a/web/www/routino/icons/limit-4.7.png b/web/www/routino/icons/limit-4.7.png new file mode 100644 index 0000000..2e0ad01 Binary files /dev/null and b/web/www/routino/icons/limit-4.7.png differ diff --git a/web/www/routino/icons/limit-4.8.png b/web/www/routino/icons/limit-4.8.png new file mode 100644 index 0000000..6fdb029 Binary files /dev/null and b/web/www/routino/icons/limit-4.8.png differ diff --git a/web/www/routino/icons/limit-4.9.png b/web/www/routino/icons/limit-4.9.png new file mode 100644 index 0000000..d60a7c8 Binary files /dev/null and b/web/www/routino/icons/limit-4.9.png differ diff --git a/web/www/routino/icons/limit-4.png b/web/www/routino/icons/limit-4.png new file mode 100644 index 0000000..d435712 Binary files /dev/null and b/web/www/routino/icons/limit-4.png differ diff --git a/web/www/routino/icons/limit-40.png b/web/www/routino/icons/limit-40.png new file mode 100644 index 0000000..b774934 Binary files /dev/null and b/web/www/routino/icons/limit-40.png differ diff --git a/web/www/routino/icons/limit-41.png b/web/www/routino/icons/limit-41.png new file mode 100644 index 0000000..d8f9d7a Binary files /dev/null and b/web/www/routino/icons/limit-41.png differ diff --git a/web/www/routino/icons/limit-42.png b/web/www/routino/icons/limit-42.png new file mode 100644 index 0000000..5ecb683 Binary files /dev/null and b/web/www/routino/icons/limit-42.png differ diff --git a/web/www/routino/icons/limit-43.png b/web/www/routino/icons/limit-43.png new file mode 100644 index 0000000..c7b9e27 Binary files /dev/null and b/web/www/routino/icons/limit-43.png differ diff --git a/web/www/routino/icons/limit-44.png b/web/www/routino/icons/limit-44.png new file mode 100644 index 0000000..4e716ac Binary files /dev/null and b/web/www/routino/icons/limit-44.png differ diff --git a/web/www/routino/icons/limit-45.png b/web/www/routino/icons/limit-45.png new file mode 100644 index 0000000..a307a9c Binary files /dev/null and b/web/www/routino/icons/limit-45.png differ diff --git a/web/www/routino/icons/limit-46.png b/web/www/routino/icons/limit-46.png new file mode 100644 index 0000000..07dbc1c Binary files /dev/null and b/web/www/routino/icons/limit-46.png differ diff --git a/web/www/routino/icons/limit-47.png b/web/www/routino/icons/limit-47.png new file mode 100644 index 0000000..90cd65f Binary files /dev/null and b/web/www/routino/icons/limit-47.png differ diff --git a/web/www/routino/icons/limit-48.png b/web/www/routino/icons/limit-48.png new file mode 100644 index 0000000..8c60143 Binary files /dev/null and b/web/www/routino/icons/limit-48.png differ diff --git a/web/www/routino/icons/limit-49.png b/web/www/routino/icons/limit-49.png new file mode 100644 index 0000000..24d779c Binary files /dev/null and b/web/www/routino/icons/limit-49.png differ diff --git a/web/www/routino/icons/limit-5.0.png b/web/www/routino/icons/limit-5.0.png new file mode 100644 index 0000000..a135d28 Binary files /dev/null and b/web/www/routino/icons/limit-5.0.png differ diff --git a/web/www/routino/icons/limit-5.1.png b/web/www/routino/icons/limit-5.1.png new file mode 100644 index 0000000..94a49a0 Binary files /dev/null and b/web/www/routino/icons/limit-5.1.png differ diff --git a/web/www/routino/icons/limit-5.2.png b/web/www/routino/icons/limit-5.2.png new file mode 100644 index 0000000..f693572 Binary files /dev/null and b/web/www/routino/icons/limit-5.2.png differ diff --git a/web/www/routino/icons/limit-5.3.png b/web/www/routino/icons/limit-5.3.png new file mode 100644 index 0000000..9b7e403 Binary files /dev/null and b/web/www/routino/icons/limit-5.3.png differ diff --git a/web/www/routino/icons/limit-5.4.png b/web/www/routino/icons/limit-5.4.png new file mode 100644 index 0000000..7d84188 Binary files /dev/null and b/web/www/routino/icons/limit-5.4.png differ diff --git a/web/www/routino/icons/limit-5.5.png b/web/www/routino/icons/limit-5.5.png new file mode 100644 index 0000000..fa228be Binary files /dev/null and b/web/www/routino/icons/limit-5.5.png differ diff --git a/web/www/routino/icons/limit-5.6.png b/web/www/routino/icons/limit-5.6.png new file mode 100644 index 0000000..dd217dc Binary files /dev/null and b/web/www/routino/icons/limit-5.6.png differ diff --git a/web/www/routino/icons/limit-5.7.png b/web/www/routino/icons/limit-5.7.png new file mode 100644 index 0000000..db7a31b Binary files /dev/null and b/web/www/routino/icons/limit-5.7.png differ diff --git a/web/www/routino/icons/limit-5.8.png b/web/www/routino/icons/limit-5.8.png new file mode 100644 index 0000000..3bdba37 Binary files /dev/null and b/web/www/routino/icons/limit-5.8.png differ diff --git a/web/www/routino/icons/limit-5.9.png b/web/www/routino/icons/limit-5.9.png new file mode 100644 index 0000000..753de97 Binary files /dev/null and b/web/www/routino/icons/limit-5.9.png differ diff --git a/web/www/routino/icons/limit-5.png b/web/www/routino/icons/limit-5.png new file mode 100644 index 0000000..024d141 Binary files /dev/null and b/web/www/routino/icons/limit-5.png differ diff --git a/web/www/routino/icons/limit-50.png b/web/www/routino/icons/limit-50.png new file mode 100644 index 0000000..47f94a9 Binary files /dev/null and b/web/www/routino/icons/limit-50.png differ diff --git a/web/www/routino/icons/limit-51.png b/web/www/routino/icons/limit-51.png new file mode 100644 index 0000000..1e5d55c Binary files /dev/null and b/web/www/routino/icons/limit-51.png differ diff --git a/web/www/routino/icons/limit-52.png b/web/www/routino/icons/limit-52.png new file mode 100644 index 0000000..57e9b46 Binary files /dev/null and b/web/www/routino/icons/limit-52.png differ diff --git a/web/www/routino/icons/limit-53.png b/web/www/routino/icons/limit-53.png new file mode 100644 index 0000000..cd54063 Binary files /dev/null and b/web/www/routino/icons/limit-53.png differ diff --git a/web/www/routino/icons/limit-54.png b/web/www/routino/icons/limit-54.png new file mode 100644 index 0000000..63d1d85 Binary files /dev/null and b/web/www/routino/icons/limit-54.png differ diff --git a/web/www/routino/icons/limit-55.png b/web/www/routino/icons/limit-55.png new file mode 100644 index 0000000..a6f3787 Binary files /dev/null and b/web/www/routino/icons/limit-55.png differ diff --git a/web/www/routino/icons/limit-56.png b/web/www/routino/icons/limit-56.png new file mode 100644 index 0000000..4253793 Binary files /dev/null and b/web/www/routino/icons/limit-56.png differ diff --git a/web/www/routino/icons/limit-57.png b/web/www/routino/icons/limit-57.png new file mode 100644 index 0000000..97f09e6 Binary files /dev/null and b/web/www/routino/icons/limit-57.png differ diff --git a/web/www/routino/icons/limit-58.png b/web/www/routino/icons/limit-58.png new file mode 100644 index 0000000..b0f127d Binary files /dev/null and b/web/www/routino/icons/limit-58.png differ diff --git a/web/www/routino/icons/limit-59.png b/web/www/routino/icons/limit-59.png new file mode 100644 index 0000000..91c4a95 Binary files /dev/null and b/web/www/routino/icons/limit-59.png differ diff --git a/web/www/routino/icons/limit-6.0.png b/web/www/routino/icons/limit-6.0.png new file mode 100644 index 0000000..60971c3 Binary files /dev/null and b/web/www/routino/icons/limit-6.0.png differ diff --git a/web/www/routino/icons/limit-6.1.png b/web/www/routino/icons/limit-6.1.png new file mode 100644 index 0000000..188eb62 Binary files /dev/null and b/web/www/routino/icons/limit-6.1.png differ diff --git a/web/www/routino/icons/limit-6.2.png b/web/www/routino/icons/limit-6.2.png new file mode 100644 index 0000000..b492ee8 Binary files /dev/null and b/web/www/routino/icons/limit-6.2.png differ diff --git a/web/www/routino/icons/limit-6.3.png b/web/www/routino/icons/limit-6.3.png new file mode 100644 index 0000000..a76d7ef Binary files /dev/null and b/web/www/routino/icons/limit-6.3.png differ diff --git a/web/www/routino/icons/limit-6.4.png b/web/www/routino/icons/limit-6.4.png new file mode 100644 index 0000000..73937e6 Binary files /dev/null and b/web/www/routino/icons/limit-6.4.png differ diff --git a/web/www/routino/icons/limit-6.5.png b/web/www/routino/icons/limit-6.5.png new file mode 100644 index 0000000..43c2feb Binary files /dev/null and b/web/www/routino/icons/limit-6.5.png differ diff --git a/web/www/routino/icons/limit-6.6.png b/web/www/routino/icons/limit-6.6.png new file mode 100644 index 0000000..3bea790 Binary files /dev/null and b/web/www/routino/icons/limit-6.6.png differ diff --git a/web/www/routino/icons/limit-6.7.png b/web/www/routino/icons/limit-6.7.png new file mode 100644 index 0000000..7c9d7f8 Binary files /dev/null and b/web/www/routino/icons/limit-6.7.png differ diff --git a/web/www/routino/icons/limit-6.8.png b/web/www/routino/icons/limit-6.8.png new file mode 100644 index 0000000..f20656c Binary files /dev/null and b/web/www/routino/icons/limit-6.8.png differ diff --git a/web/www/routino/icons/limit-6.9.png b/web/www/routino/icons/limit-6.9.png new file mode 100644 index 0000000..c401e26 Binary files /dev/null and b/web/www/routino/icons/limit-6.9.png differ diff --git a/web/www/routino/icons/limit-6.png b/web/www/routino/icons/limit-6.png new file mode 100644 index 0000000..a7e7008 Binary files /dev/null and b/web/www/routino/icons/limit-6.png differ diff --git a/web/www/routino/icons/limit-60.png b/web/www/routino/icons/limit-60.png new file mode 100644 index 0000000..f7cba69 Binary files /dev/null and b/web/www/routino/icons/limit-60.png differ diff --git a/web/www/routino/icons/limit-61.png b/web/www/routino/icons/limit-61.png new file mode 100644 index 0000000..610ca73 Binary files /dev/null and b/web/www/routino/icons/limit-61.png differ diff --git a/web/www/routino/icons/limit-62.png b/web/www/routino/icons/limit-62.png new file mode 100644 index 0000000..90bba38 Binary files /dev/null and b/web/www/routino/icons/limit-62.png differ diff --git a/web/www/routino/icons/limit-63.png b/web/www/routino/icons/limit-63.png new file mode 100644 index 0000000..697557e Binary files /dev/null and b/web/www/routino/icons/limit-63.png differ diff --git a/web/www/routino/icons/limit-64.png b/web/www/routino/icons/limit-64.png new file mode 100644 index 0000000..f20791c Binary files /dev/null and b/web/www/routino/icons/limit-64.png differ diff --git a/web/www/routino/icons/limit-65.png b/web/www/routino/icons/limit-65.png new file mode 100644 index 0000000..61ec74c Binary files /dev/null and b/web/www/routino/icons/limit-65.png differ diff --git a/web/www/routino/icons/limit-66.png b/web/www/routino/icons/limit-66.png new file mode 100644 index 0000000..30c6f05 Binary files /dev/null and b/web/www/routino/icons/limit-66.png differ diff --git a/web/www/routino/icons/limit-67.png b/web/www/routino/icons/limit-67.png new file mode 100644 index 0000000..fdd4cb8 Binary files /dev/null and b/web/www/routino/icons/limit-67.png differ diff --git a/web/www/routino/icons/limit-68.png b/web/www/routino/icons/limit-68.png new file mode 100644 index 0000000..2c46581 Binary files /dev/null and b/web/www/routino/icons/limit-68.png differ diff --git a/web/www/routino/icons/limit-69.png b/web/www/routino/icons/limit-69.png new file mode 100644 index 0000000..8fff32c Binary files /dev/null and b/web/www/routino/icons/limit-69.png differ diff --git a/web/www/routino/icons/limit-7.0.png b/web/www/routino/icons/limit-7.0.png new file mode 100644 index 0000000..3e0feb2 Binary files /dev/null and b/web/www/routino/icons/limit-7.0.png differ diff --git a/web/www/routino/icons/limit-7.1.png b/web/www/routino/icons/limit-7.1.png new file mode 100644 index 0000000..72039ce Binary files /dev/null and b/web/www/routino/icons/limit-7.1.png differ diff --git a/web/www/routino/icons/limit-7.2.png b/web/www/routino/icons/limit-7.2.png new file mode 100644 index 0000000..8449943 Binary files /dev/null and b/web/www/routino/icons/limit-7.2.png differ diff --git a/web/www/routino/icons/limit-7.3.png b/web/www/routino/icons/limit-7.3.png new file mode 100644 index 0000000..60103fc Binary files /dev/null and b/web/www/routino/icons/limit-7.3.png differ diff --git a/web/www/routino/icons/limit-7.4.png b/web/www/routino/icons/limit-7.4.png new file mode 100644 index 0000000..ebe4d43 Binary files /dev/null and b/web/www/routino/icons/limit-7.4.png differ diff --git a/web/www/routino/icons/limit-7.5.png b/web/www/routino/icons/limit-7.5.png new file mode 100644 index 0000000..a771332 Binary files /dev/null and b/web/www/routino/icons/limit-7.5.png differ diff --git a/web/www/routino/icons/limit-7.6.png b/web/www/routino/icons/limit-7.6.png new file mode 100644 index 0000000..60ad68f Binary files /dev/null and b/web/www/routino/icons/limit-7.6.png differ diff --git a/web/www/routino/icons/limit-7.7.png b/web/www/routino/icons/limit-7.7.png new file mode 100644 index 0000000..d4eda2f Binary files /dev/null and b/web/www/routino/icons/limit-7.7.png differ diff --git a/web/www/routino/icons/limit-7.8.png b/web/www/routino/icons/limit-7.8.png new file mode 100644 index 0000000..c8d78ec Binary files /dev/null and b/web/www/routino/icons/limit-7.8.png differ diff --git a/web/www/routino/icons/limit-7.9.png b/web/www/routino/icons/limit-7.9.png new file mode 100644 index 0000000..2116759 Binary files /dev/null and b/web/www/routino/icons/limit-7.9.png differ diff --git a/web/www/routino/icons/limit-7.png b/web/www/routino/icons/limit-7.png new file mode 100644 index 0000000..08d7295 Binary files /dev/null and b/web/www/routino/icons/limit-7.png differ diff --git a/web/www/routino/icons/limit-70.png b/web/www/routino/icons/limit-70.png new file mode 100644 index 0000000..2856aa9 Binary files /dev/null and b/web/www/routino/icons/limit-70.png differ diff --git a/web/www/routino/icons/limit-71.png b/web/www/routino/icons/limit-71.png new file mode 100644 index 0000000..2649962 Binary files /dev/null and b/web/www/routino/icons/limit-71.png differ diff --git a/web/www/routino/icons/limit-72.png b/web/www/routino/icons/limit-72.png new file mode 100644 index 0000000..4bc83bf Binary files /dev/null and b/web/www/routino/icons/limit-72.png differ diff --git a/web/www/routino/icons/limit-73.png b/web/www/routino/icons/limit-73.png new file mode 100644 index 0000000..24ba4e4 Binary files /dev/null and b/web/www/routino/icons/limit-73.png differ diff --git a/web/www/routino/icons/limit-74.png b/web/www/routino/icons/limit-74.png new file mode 100644 index 0000000..f500d8b Binary files /dev/null and b/web/www/routino/icons/limit-74.png differ diff --git a/web/www/routino/icons/limit-75.png b/web/www/routino/icons/limit-75.png new file mode 100644 index 0000000..1639536 Binary files /dev/null and b/web/www/routino/icons/limit-75.png differ diff --git a/web/www/routino/icons/limit-76.png b/web/www/routino/icons/limit-76.png new file mode 100644 index 0000000..81d97ad Binary files /dev/null and b/web/www/routino/icons/limit-76.png differ diff --git a/web/www/routino/icons/limit-77.png b/web/www/routino/icons/limit-77.png new file mode 100644 index 0000000..c89d522 Binary files /dev/null and b/web/www/routino/icons/limit-77.png differ diff --git a/web/www/routino/icons/limit-78.png b/web/www/routino/icons/limit-78.png new file mode 100644 index 0000000..d4cc2e5 Binary files /dev/null and b/web/www/routino/icons/limit-78.png differ diff --git a/web/www/routino/icons/limit-79.png b/web/www/routino/icons/limit-79.png new file mode 100644 index 0000000..4ef7479 Binary files /dev/null and b/web/www/routino/icons/limit-79.png differ diff --git a/web/www/routino/icons/limit-8.0.png b/web/www/routino/icons/limit-8.0.png new file mode 100644 index 0000000..06a4f84 Binary files /dev/null and b/web/www/routino/icons/limit-8.0.png differ diff --git a/web/www/routino/icons/limit-8.1.png b/web/www/routino/icons/limit-8.1.png new file mode 100644 index 0000000..c30756e Binary files /dev/null and b/web/www/routino/icons/limit-8.1.png differ diff --git a/web/www/routino/icons/limit-8.2.png b/web/www/routino/icons/limit-8.2.png new file mode 100644 index 0000000..f0cd413 Binary files /dev/null and b/web/www/routino/icons/limit-8.2.png differ diff --git a/web/www/routino/icons/limit-8.3.png b/web/www/routino/icons/limit-8.3.png new file mode 100644 index 0000000..01a6b36 Binary files /dev/null and b/web/www/routino/icons/limit-8.3.png differ diff --git a/web/www/routino/icons/limit-8.4.png b/web/www/routino/icons/limit-8.4.png new file mode 100644 index 0000000..1ec999b Binary files /dev/null and b/web/www/routino/icons/limit-8.4.png differ diff --git a/web/www/routino/icons/limit-8.5.png b/web/www/routino/icons/limit-8.5.png new file mode 100644 index 0000000..2ff9460 Binary files /dev/null and b/web/www/routino/icons/limit-8.5.png differ diff --git a/web/www/routino/icons/limit-8.6.png b/web/www/routino/icons/limit-8.6.png new file mode 100644 index 0000000..3397564 Binary files /dev/null and b/web/www/routino/icons/limit-8.6.png differ diff --git a/web/www/routino/icons/limit-8.7.png b/web/www/routino/icons/limit-8.7.png new file mode 100644 index 0000000..71de255 Binary files /dev/null and b/web/www/routino/icons/limit-8.7.png differ diff --git a/web/www/routino/icons/limit-8.8.png b/web/www/routino/icons/limit-8.8.png new file mode 100644 index 0000000..2e449a7 Binary files /dev/null and b/web/www/routino/icons/limit-8.8.png differ diff --git a/web/www/routino/icons/limit-8.9.png b/web/www/routino/icons/limit-8.9.png new file mode 100644 index 0000000..8597ea2 Binary files /dev/null and b/web/www/routino/icons/limit-8.9.png differ diff --git a/web/www/routino/icons/limit-8.png b/web/www/routino/icons/limit-8.png new file mode 100644 index 0000000..1a85ad2 Binary files /dev/null and b/web/www/routino/icons/limit-8.png differ diff --git a/web/www/routino/icons/limit-80.png b/web/www/routino/icons/limit-80.png new file mode 100644 index 0000000..c445928 Binary files /dev/null and b/web/www/routino/icons/limit-80.png differ diff --git a/web/www/routino/icons/limit-81.png b/web/www/routino/icons/limit-81.png new file mode 100644 index 0000000..a13e364 Binary files /dev/null and b/web/www/routino/icons/limit-81.png differ diff --git a/web/www/routino/icons/limit-82.png b/web/www/routino/icons/limit-82.png new file mode 100644 index 0000000..88a0b21 Binary files /dev/null and b/web/www/routino/icons/limit-82.png differ diff --git a/web/www/routino/icons/limit-83.png b/web/www/routino/icons/limit-83.png new file mode 100644 index 0000000..3fc8401 Binary files /dev/null and b/web/www/routino/icons/limit-83.png differ diff --git a/web/www/routino/icons/limit-84.png b/web/www/routino/icons/limit-84.png new file mode 100644 index 0000000..89c4eaa Binary files /dev/null and b/web/www/routino/icons/limit-84.png differ diff --git a/web/www/routino/icons/limit-85.png b/web/www/routino/icons/limit-85.png new file mode 100644 index 0000000..1fd523e Binary files /dev/null and b/web/www/routino/icons/limit-85.png differ diff --git a/web/www/routino/icons/limit-86.png b/web/www/routino/icons/limit-86.png new file mode 100644 index 0000000..7b367dd Binary files /dev/null and b/web/www/routino/icons/limit-86.png differ diff --git a/web/www/routino/icons/limit-87.png b/web/www/routino/icons/limit-87.png new file mode 100644 index 0000000..24c576e Binary files /dev/null and b/web/www/routino/icons/limit-87.png differ diff --git a/web/www/routino/icons/limit-88.png b/web/www/routino/icons/limit-88.png new file mode 100644 index 0000000..f45d4b1 Binary files /dev/null and b/web/www/routino/icons/limit-88.png differ diff --git a/web/www/routino/icons/limit-89.png b/web/www/routino/icons/limit-89.png new file mode 100644 index 0000000..8190d03 Binary files /dev/null and b/web/www/routino/icons/limit-89.png differ diff --git a/web/www/routino/icons/limit-9.0.png b/web/www/routino/icons/limit-9.0.png new file mode 100644 index 0000000..0e4e1ca Binary files /dev/null and b/web/www/routino/icons/limit-9.0.png differ diff --git a/web/www/routino/icons/limit-9.1.png b/web/www/routino/icons/limit-9.1.png new file mode 100644 index 0000000..1e72a3d Binary files /dev/null and b/web/www/routino/icons/limit-9.1.png differ diff --git a/web/www/routino/icons/limit-9.2.png b/web/www/routino/icons/limit-9.2.png new file mode 100644 index 0000000..c874cc0 Binary files /dev/null and b/web/www/routino/icons/limit-9.2.png differ diff --git a/web/www/routino/icons/limit-9.3.png b/web/www/routino/icons/limit-9.3.png new file mode 100644 index 0000000..d203ff6 Binary files /dev/null and b/web/www/routino/icons/limit-9.3.png differ diff --git a/web/www/routino/icons/limit-9.4.png b/web/www/routino/icons/limit-9.4.png new file mode 100644 index 0000000..50e4b93 Binary files /dev/null and b/web/www/routino/icons/limit-9.4.png differ diff --git a/web/www/routino/icons/limit-9.5.png b/web/www/routino/icons/limit-9.5.png new file mode 100644 index 0000000..3175f28 Binary files /dev/null and b/web/www/routino/icons/limit-9.5.png differ diff --git a/web/www/routino/icons/limit-9.6.png b/web/www/routino/icons/limit-9.6.png new file mode 100644 index 0000000..a91d27f Binary files /dev/null and b/web/www/routino/icons/limit-9.6.png differ diff --git a/web/www/routino/icons/limit-9.7.png b/web/www/routino/icons/limit-9.7.png new file mode 100644 index 0000000..b3904c9 Binary files /dev/null and b/web/www/routino/icons/limit-9.7.png differ diff --git a/web/www/routino/icons/limit-9.8.png b/web/www/routino/icons/limit-9.8.png new file mode 100644 index 0000000..abc116b Binary files /dev/null and b/web/www/routino/icons/limit-9.8.png differ diff --git a/web/www/routino/icons/limit-9.9.png b/web/www/routino/icons/limit-9.9.png new file mode 100644 index 0000000..10be98c Binary files /dev/null and b/web/www/routino/icons/limit-9.9.png differ diff --git a/web/www/routino/icons/limit-9.png b/web/www/routino/icons/limit-9.png new file mode 100644 index 0000000..5053dc9 Binary files /dev/null and b/web/www/routino/icons/limit-9.png differ diff --git a/web/www/routino/icons/limit-90.png b/web/www/routino/icons/limit-90.png new file mode 100644 index 0000000..c86c1bc Binary files /dev/null and b/web/www/routino/icons/limit-90.png differ diff --git a/web/www/routino/icons/limit-91.png b/web/www/routino/icons/limit-91.png new file mode 100644 index 0000000..d235463 Binary files /dev/null and b/web/www/routino/icons/limit-91.png differ diff --git a/web/www/routino/icons/limit-92.png b/web/www/routino/icons/limit-92.png new file mode 100644 index 0000000..7200fbd Binary files /dev/null and b/web/www/routino/icons/limit-92.png differ diff --git a/web/www/routino/icons/limit-93.png b/web/www/routino/icons/limit-93.png new file mode 100644 index 0000000..d500ab9 Binary files /dev/null and b/web/www/routino/icons/limit-93.png differ diff --git a/web/www/routino/icons/limit-94.png b/web/www/routino/icons/limit-94.png new file mode 100644 index 0000000..975386b Binary files /dev/null and b/web/www/routino/icons/limit-94.png differ diff --git a/web/www/routino/icons/limit-95.png b/web/www/routino/icons/limit-95.png new file mode 100644 index 0000000..de7f9ff Binary files /dev/null and b/web/www/routino/icons/limit-95.png differ diff --git a/web/www/routino/icons/limit-96.png b/web/www/routino/icons/limit-96.png new file mode 100644 index 0000000..8898cae Binary files /dev/null and b/web/www/routino/icons/limit-96.png differ diff --git a/web/www/routino/icons/limit-97.png b/web/www/routino/icons/limit-97.png new file mode 100644 index 0000000..f63678c Binary files /dev/null and b/web/www/routino/icons/limit-97.png differ diff --git a/web/www/routino/icons/limit-98.png b/web/www/routino/icons/limit-98.png new file mode 100644 index 0000000..b6aa054 Binary files /dev/null and b/web/www/routino/icons/limit-98.png differ diff --git a/web/www/routino/icons/limit-99.png b/web/www/routino/icons/limit-99.png new file mode 100644 index 0000000..b8b6b1f Binary files /dev/null and b/web/www/routino/icons/limit-99.png differ diff --git a/web/www/routino/icons/limit-no.png b/web/www/routino/icons/limit-no.png new file mode 100644 index 0000000..cbcf311 Binary files /dev/null and b/web/www/routino/icons/limit-no.png differ diff --git a/web/www/routino/icons/marker-0-grey.png b/web/www/routino/icons/marker-0-grey.png new file mode 100644 index 0000000..29bb4c3 Binary files /dev/null and b/web/www/routino/icons/marker-0-grey.png differ diff --git a/web/www/routino/icons/marker-0-red.png b/web/www/routino/icons/marker-0-red.png new file mode 100644 index 0000000..9a46127 Binary files /dev/null and b/web/www/routino/icons/marker-0-red.png differ diff --git a/web/www/routino/icons/marker-1-grey.png b/web/www/routino/icons/marker-1-grey.png new file mode 100644 index 0000000..ecf8623 Binary files /dev/null and b/web/www/routino/icons/marker-1-grey.png differ diff --git a/web/www/routino/icons/marker-1-red.png b/web/www/routino/icons/marker-1-red.png new file mode 100644 index 0000000..dd50628 Binary files /dev/null and b/web/www/routino/icons/marker-1-red.png differ diff --git a/web/www/routino/icons/marker-2-grey.png b/web/www/routino/icons/marker-2-grey.png new file mode 100644 index 0000000..64a954a Binary files /dev/null and b/web/www/routino/icons/marker-2-grey.png differ diff --git a/web/www/routino/icons/marker-2-red.png b/web/www/routino/icons/marker-2-red.png new file mode 100644 index 0000000..87765ad Binary files /dev/null and b/web/www/routino/icons/marker-2-red.png differ diff --git a/web/www/routino/icons/marker-3-grey.png b/web/www/routino/icons/marker-3-grey.png new file mode 100644 index 0000000..63ecf74 Binary files /dev/null and b/web/www/routino/icons/marker-3-grey.png differ diff --git a/web/www/routino/icons/marker-3-red.png b/web/www/routino/icons/marker-3-red.png new file mode 100644 index 0000000..7cf0f85 Binary files /dev/null and b/web/www/routino/icons/marker-3-red.png differ diff --git a/web/www/routino/icons/marker-4-grey.png b/web/www/routino/icons/marker-4-grey.png new file mode 100644 index 0000000..bc310ee Binary files /dev/null and b/web/www/routino/icons/marker-4-grey.png differ diff --git a/web/www/routino/icons/marker-4-red.png b/web/www/routino/icons/marker-4-red.png new file mode 100644 index 0000000..da4548e Binary files /dev/null and b/web/www/routino/icons/marker-4-red.png differ diff --git a/web/www/routino/icons/marker-5-grey.png b/web/www/routino/icons/marker-5-grey.png new file mode 100644 index 0000000..0d805e5 Binary files /dev/null and b/web/www/routino/icons/marker-5-grey.png differ diff --git a/web/www/routino/icons/marker-5-red.png b/web/www/routino/icons/marker-5-red.png new file mode 100644 index 0000000..e6eeb93 Binary files /dev/null and b/web/www/routino/icons/marker-5-red.png differ diff --git a/web/www/routino/icons/marker-6-grey.png b/web/www/routino/icons/marker-6-grey.png new file mode 100644 index 0000000..c93fe1b Binary files /dev/null and b/web/www/routino/icons/marker-6-grey.png differ diff --git a/web/www/routino/icons/marker-6-red.png b/web/www/routino/icons/marker-6-red.png new file mode 100644 index 0000000..87d2048 Binary files /dev/null and b/web/www/routino/icons/marker-6-red.png differ diff --git a/web/www/routino/icons/marker-7-grey.png b/web/www/routino/icons/marker-7-grey.png new file mode 100644 index 0000000..1bfeed2 Binary files /dev/null and b/web/www/routino/icons/marker-7-grey.png differ diff --git a/web/www/routino/icons/marker-7-red.png b/web/www/routino/icons/marker-7-red.png new file mode 100644 index 0000000..cbe9f41 Binary files /dev/null and b/web/www/routino/icons/marker-7-red.png differ diff --git a/web/www/routino/icons/marker-8-grey.png b/web/www/routino/icons/marker-8-grey.png new file mode 100644 index 0000000..fca1545 Binary files /dev/null and b/web/www/routino/icons/marker-8-grey.png differ diff --git a/web/www/routino/icons/marker-8-red.png b/web/www/routino/icons/marker-8-red.png new file mode 100644 index 0000000..2ae4d0d Binary files /dev/null and b/web/www/routino/icons/marker-8-red.png differ diff --git a/web/www/routino/icons/marker-9-grey.png b/web/www/routino/icons/marker-9-grey.png new file mode 100644 index 0000000..4e7db79 Binary files /dev/null and b/web/www/routino/icons/marker-9-grey.png differ diff --git a/web/www/routino/icons/marker-9-red.png b/web/www/routino/icons/marker-9-red.png new file mode 100644 index 0000000..310b43e Binary files /dev/null and b/web/www/routino/icons/marker-9-red.png differ diff --git a/web/www/routino/icons/marker-home-grey.png b/web/www/routino/icons/marker-home-grey.png new file mode 100644 index 0000000..a894854 Binary files /dev/null and b/web/www/routino/icons/marker-home-grey.png differ diff --git a/web/www/routino/icons/marker-home-red.png b/web/www/routino/icons/marker-home-red.png new file mode 100644 index 0000000..beb7269 Binary files /dev/null and b/web/www/routino/icons/marker-home-red.png differ diff --git a/web/www/routino/icons/waypoint-add.png b/web/www/routino/icons/waypoint-add.png new file mode 100644 index 0000000..c11fb26 Binary files /dev/null and b/web/www/routino/icons/waypoint-add.png differ diff --git a/web/www/routino/icons/waypoint-centre.png b/web/www/routino/icons/waypoint-centre.png new file mode 100644 index 0000000..e464631 Binary files /dev/null and b/web/www/routino/icons/waypoint-centre.png differ diff --git a/web/www/routino/icons/waypoint-down.png b/web/www/routino/icons/waypoint-down.png new file mode 100644 index 0000000..1082bfd Binary files /dev/null and b/web/www/routino/icons/waypoint-down.png differ diff --git a/web/www/routino/icons/waypoint-home.png b/web/www/routino/icons/waypoint-home.png new file mode 100644 index 0000000..caf6019 Binary files /dev/null and b/web/www/routino/icons/waypoint-home.png differ diff --git a/web/www/routino/icons/waypoint-remove.png b/web/www/routino/icons/waypoint-remove.png new file mode 100644 index 0000000..2fcb77f Binary files /dev/null and b/web/www/routino/icons/waypoint-remove.png differ diff --git a/web/www/routino/icons/waypoint-up.png b/web/www/routino/icons/waypoint-up.png new file mode 100644 index 0000000..6b1b5c0 Binary files /dev/null and b/web/www/routino/icons/waypoint-up.png differ diff --git a/web/www/routino/index.html b/web/www/routino/index.html new file mode 100644 index 0000000..831ef02 --- /dev/null +++ b/web/www/routino/index.html @@ -0,0 +1,70 @@ + + + + + + +Routino : Route Planner for OpenStreetMap Data + + + + + + + + + +

+ +

Routino : Route Planner for OpenStreetMap Data

+ +
+
+ + + + + +
+ +

Page Moved

+ +
+ + + + + + + + + + + + diff --git a/web/www/routino/maplayout-ie6-bugfixes.css b/web/www/routino/maplayout-ie6-bugfixes.css new file mode 100644 index 0000000..0760507 --- /dev/null +++ b/web/www/routino/maplayout-ie6-bugfixes.css @@ -0,0 +1,83 @@ +/* +// Routino Internet Explorer 6 map layout web page style sheet. +// +// Part of the Routino routing software. +// +// This file Copyright 2010 Andrew M. Bishop +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +*/ + + +/*----------------------------------*/ +/* Body HTML formatting */ +/*----------------------------------*/ + +/* + Internet Explorer 6 doesn't understand 'postion: fixed' styles. The best that + can be done is the following to make it the equivalent of absolute positioning. + This is "well-known" problem, you can find details on the internet. +*/ + +* HTML +{ + overflow-x: auto; +} + +* HTML BODY +{ + height: 100%; + width: 100%; + overflow: auto; +} + + +/*-------------*/ +/* Right panel */ +/*-------------*/ + + +/* + Internet Explorer 6 ignores the fact that the map and attribution divs are + within the right_panel and positions them all over everything (probably due + to the previous hacks). The fix for this is to make the left edges of these + divs line up with where the edge of the right_panel is. +*/ + +DIV.map +{ + left: 23.5em !important; +} + +DIV.attribution +{ + left: 23.5em !important; +} + + +/* + In addition to the poor positioning we need to set a height and width of the + map so we guess what fits in the user's window. +*/ + +DIV.map +{ + width: 65%; + height: 90%; +} + +DIV.attribution +{ + width: 65%; +} diff --git a/web/www/routino/maplayout-ie7-bugfixes.css b/web/www/routino/maplayout-ie7-bugfixes.css new file mode 100644 index 0000000..705056e --- /dev/null +++ b/web/www/routino/maplayout-ie7-bugfixes.css @@ -0,0 +1,64 @@ +/* +// Routino Internet Explorer 7 map layout web page style sheet. +// +// Part of the Routino routing software. +// +// This file Copyright 2010 Andrew M. Bishop +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +*/ + + + +/*-------------*/ +/* Right panel */ +/*-------------*/ + +/* + What seems to happen is that the map div in the right panel picks up the size + of the right_panel div itself but won't fill the area unless a width and + height are given. Using 100% width and height is then the whole size of the + right_panel and the border makes it bigger still. + + This fix makes the right_panel smaller all round, the map div has its edges + moved out to allow the border to be visible all round and has 100% size. The + attribution needs to be given a position outside of the right_panel to make + sure that is isn't covered by the map. +*/ + +DIV.right_panel +{ + top: 3px !important; + bottom: 1.7em !important; + right: 3px !important; + left: 23.7em !important; +} + +DIV.map +{ + top: -3px !important; + bottom: -3px !important; + right: -3px !important; + left: -3px !important; + + width: 100% !important; + height: 100% !important; +} + +DIV.attribution +{ + bottom: -1.7em !important; + + width: 100% !important; +} diff --git a/web/www/routino/maplayout.css b/web/www/routino/maplayout.css new file mode 100644 index 0000000..bf83bb8 --- /dev/null +++ b/web/www/routino/maplayout.css @@ -0,0 +1,101 @@ +/* +// Routino map layout web page style sheet. +// +// Part of the Routino routing software. +// +// This file Copyright 2008-2010 Andrew M. Bishop +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +*/ + + +/*----------------------------------*/ +/* Body HTML formatting */ +/*----------------------------------*/ + +BODY +{ + /* fonts and text styles */ + + font-family: sans-serif; + font-size: medium; + + /* colours */ + + background-color: white; + color: black; +} + + +/*------------*/ +/* Left panel */ +/*------------*/ + +DIV.left_panel +{ + width: 23em; + + position: absolute; + top: 0; + bottom: 0; + right: auto; + left: 0; + + padding: 3px; +} + + +/*-------------*/ +/* Right panel */ +/*-------------*/ + +DIV.right_panel +{ + position: fixed; + top: 0; + bottom: 0; + right: 0; + left: 23.5em; +} + +DIV.map +{ + position: absolute; + top: 0; + bottom: 1.5em; + right: 0; + left: 0; + + border: 3px solid; + + text-align: center; +} + +DIV.attribution +{ + position: absolute; + top: auto; + bottom: 0; + right: 0; + left: 0; + + margin: 0px; + border: 0px; + padding: 0px; + + text-align: center; + + white-space: nowrap; + overflow: hidden; +} diff --git a/web/www/routino/noscript.cgi b/web/www/routino/noscript.cgi new file mode 100755 index 0000000..a460c81 --- /dev/null +++ b/web/www/routino/noscript.cgi @@ -0,0 +1,196 @@ +#!/usr/bin/perl +# +# Routino non-Javascript router CGI +# +# Part of the Routino routing software. +# +# This file Copyright 2008-2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Use the generic router script +require "router.pl"; + +# Use the perl CGI module +use CGI ':cgi'; + +# Create the query and get the parameters + +$query=new CGI; + +@rawparams=$query->param; + +# Legal CGI parameters with regexp validity check + +%legalparams=( + "lon[1-9]" => "[-0-9.]+", + "lat[1-9]" => "[-0-9.]+", + "transport" => "[a-z]+", + "highway-[a-z]+" => "[0-9.]+", + "speed-[a-z]+" => "[0-9.]+", + "property-[a-z]+" => "[0-9.]+", + "oneway" => "(1|0|true|false|on|off)", + "weight" => "[0-9.]+", + "height" => "[0-9.]+", + "width" => "[0-9.]+", + "length" => "[0-9.]+", + "length" => "[0-9.]+", + + "language" => "[-a-zA-Z]+" + "submit" => "(shortest|quickest|link)", + "format" => "(html|gpx-route|gpx-track|text|text-all|form)" + ); + +# Validate the CGI parameters, ignore invalid ones + +foreach $key (@rawparams) + { + foreach $test (keys (%legalparams)) + { + if($key =~ m%^$test$%) + { + $value=$query->param($key); + + if($value =~ m%^$legalparams{$test}$%) + { + $cgiparams{$key}=$value; + last; + } + } + } + } + +# Get the important parameters + +$submit=$cgiparams{submit}; +delete $cgiparams{submit}; + +$format=$cgiparams{format}; +delete $cgiparams{format}; + +$format="form" if(!$format || ($submit ne "shortest" && $submit ne "quickest")); + +# Generate a custom URL + +$customurl=""; + +if($submit) + { + $customurl="noscript.cgi?"; + + foreach $key (sort (keys %cgiparams)) + { + $customurl.="$key=$cgiparams{$key};"; + } + + $customurl.="submit=custom"; + } + +# Fill in the default parameters + +%fullparams=FillInDefaults(%cgiparams); + +# Open template file before running the router (including changing directory) + +open(TEMPLATE,") + { + if (m%%) + { + $key=$1; + + m%type="([a-z]+)"%; + $type=$1; + + m%value="([a-z]+)"%; + $value=$1; + + if ($type eq "radio") + { + $checked=""; + $checked="checked" if($fullparams{$key} eq $value); + + s%>% $checked>%; + } + elsif ($type eq "checkbox") + { + $checked=""; + $checked="checked" if($fullparams{$key}); + + s%>% $checked>%; + } + elsif ($type eq "text") + { + s%>% value="$fullparams{$key}">%; + } + + print; + } + elsif (m%%) + { + s%%$customurl%; + + print if($submit); + } + elsif (m%%) + { + $results_section=1; + } + elsif (m%%) + { + $results_section=0; + } + elsif ($results_section) + { + s%%$router_Type%; + s%%$router_type%; + s%%$router_uuid%; + s%%$router_time%; + s%%$router_result%; + s%%$router_message%; + + print if($router_uuid); + } + else + { + print; + } + } + +close(TEMPLATE); diff --git a/web/www/routino/noscript.html b/web/www/routino/noscript.html new file mode 100644 index 0000000..79344e2 --- /dev/null +++ b/web/www/routino/noscript.html @@ -0,0 +1,70 @@ + + + + + + +Routino : Route Planner for OpenStreetMap Data (non-JavaScript) + + + + + + + + + +
+ +

Routino : Route Planner for OpenStreetMap Data (non-JavaScript)

+ +
+
+ + + + + +
+ +

Page Moved

+ +
+ + + + + + + + + + + + diff --git a/web/www/routino/noscript.template.html b/web/www/routino/noscript.template.html new file mode 100644 index 0000000..40eebb6 --- /dev/null +++ b/web/www/routino/noscript.template.html @@ -0,0 +1,420 @@ + + + + + + +Routino : Route Planner for OpenStreetMap Data (non-JavaScript) + + + + + + + + + +
+ +

Routino : Route Planner for OpenStreetMap Data (non-JavaScript)

+ +
+
+ + + + + +
+ +

Non Javascript Route Finder

+ +
+ +

Locations

+ + When a route is calculated it will visit (as close as possible + for the selected transport type) each of the locations that have + been specified in the order given. + +

+ + + + + + + + + + + +
Waypoint 1: + E + N +
Waypoint 2: + E + N +
Waypoint 3: + E + N +
Waypoint 4: + E + N +
Waypoint 5: + E + N +
Waypoint 6: + E + N +
Waypoint 7: + E + N +
Waypoint 8: + E + N +
Waypoint 9: + E + N +
+ +

+ +

Transport Type

+ + Selecting a transport type will restrict the chosen route to + those on which it is allowed. Selecting one of the links here + will set default values for the other parameters. + +

+ + + + + + + + + + + + +
Foot + +
Horse + +
Wheelchair + +
Bicycle + +
Moped + +
Motorbike + +
Motorcar + +
Goods + +
HGV + +
PSV + +
+ +

+ +

Highway Preferences

+ + The highway preference is selected as a percentage and routes are chosen that + try to follow the preferred highways. + For example if a "Primary" road is given a "110%" preference and a "Secondary" + road is given a "100%" preference then it means that a route on a Primary road + can be up to 10% longer than on a secondary road and still be selected. + +

Speed Limits

+ + The speed limits chosen here for the different types of highway apply if the + highway has no other speed limit marked or it is higher than the chosen one. + +

+ + + + + + + + + + + + + + + +
+ Preference + Speed Limit +
Motorway: + + % + + km/hr +
Trunk: + + % + + km/hr +
Primary: + + % + + km/hr +
Secondary: + + % + + km/hr +
Tertiary: + + % + + km/hr +
Unclassified: + + % + + km/hr +
Residential: + + % + + km/hr +
Service: + + % + + km/hr +
Track: + + % + + km/hr +
Cycleway: + + % + + km/hr +
Path: + + % + + km/hr +
Steps: + + % + + km/hr +
+ +

+ +

Property Preferences

+ + The property preference is selected as a percentage and routes are chosen that + try to follow highways with the preferred property. + For example if a "Paved" highway is given a "75%" preference then it means that + an unpaved highway is automatically given a "25%" preference so that a route on + a paved highway can be 3 times the length of an unpaved one and still be + selected. + +

+ + + + + + + +
+ Preference
+
Paved: + + % +
Multiple Lanes: + + % +
Bridge: + + % +
Tunnel: + + % +
+ +

+ +

Other Restrictions

+ + These allow a route to be found that avoids marked limits on + weight, height, width or length. It is also possible to ignore + one-way restrictions (e.g. if walking). + +

+ + + + + + + +
Obey oneway: + + +
Weight: + + tonnes +
Height: + + metres +
Width: + + metres +
Length: + + metres +
+ +

+ +

Output Format

+ + This allows for selection of the language of the generated output. + +

+ + + + +
English (en) + +
German (de) + +
+ +

+ + This allows for selection of the format of the generated output. + +

+ + + + + + + + +
This HTML format +
HTML route instructions +
GPX track file +
GPX route file +
Text file +
Full text file +
+ +

+ +

Calculate Route

+ + + + +

+ + + +


+ +

+ + + + + + + + + + + +
Result +
+
+
HTML file: + Open +
GPX track file: + Open +
GPX route file: + Open +
Text file: + Open +
Full text file: + Open +
+
+ +

+ + + +


+ +

+ +

Create Link

+ + + Bookmarkable link with customised parameters + +
+ +
+ + + + + + + + + + + + diff --git a/web/www/routino/page-elements.css b/web/www/routino/page-elements.css new file mode 100644 index 0000000..722997d --- /dev/null +++ b/web/www/routino/page-elements.css @@ -0,0 +1,143 @@ +/* +// Style sheet for page elements. +// +// Part of the Routino routing software. +// +// This file Copyright 2008-2010 Andrew M. Bishop +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +*/ + + +/*-------------*/ +/* Tabbed DIVs */ +/*-------------*/ + + +DIV.tab_box +{ + padding: 3px; + margin-top: 3px; + + width: 100%; +} + +DIV.tab_box SPAN.tab_selected +{ + border-top: 2px solid; + border-left: 2px solid; + border-right: 2px solid; + border-bottom: 1px solid white; + + z-index: 5; + + padding: 3px; + + font-weight: bold; + font-variant: small-caps; + + background: #FFF; +} + +DIV.tab_box SPAN.tab_unselected +{ + border-top: 1px solid; + border-left: 1px solid; + border-right: 1px solid; + + padding: 3px; + + cursor: pointer; + + font-variant: small-caps; + + background: #CCC; +} + +DIV.tab_box SPAN.tab_unselected:hover +{ + background: #DDD; +} + +DIV.tab_content +{ + width: auto; + + padding: 3px; + border: thin solid; +} + + +/*----------------*/ +/* Show/Hide DIVs */ +/*----------------*/ + + +DIV.hideshow_box +{ + min-height: 1em; + + border-top: 2px solid; + border-color: #AAA; + + padding-bottom: 2px; + + overflow: hidden; +} + +DIV.hideshow_box:first-child +{ + border-top: none; +} + +DIV.hideshow_box SPAN.hideshow_show +{ + float: right; + display: block; + + font-style: italic; + font-variant: small-caps; + + padding-right: 2px; + padding-left: 1px; + padding-top: 1px; + padding-bottom: 1px; + + cursor: pointer; + + background: #CCC; +} + +DIV.hideshow_box SPAN.hideshow_show:hover +{ + background: #DDD; +} + +DIV.hideshow_box SPAN.hideshow_hide +{ + display: none; +} + +SPAN.hideshow_title +{ + display: block; + + font-weight: bold; + text-decoration: underline; + + padding-top: 1px; + padding-bottom: 1px; + + background: #EEE; +} diff --git a/web/www/routino/page-elements.js b/web/www/routino/page-elements.js new file mode 100644 index 0000000..f751897 --- /dev/null +++ b/web/www/routino/page-elements.js @@ -0,0 +1,91 @@ +// +// Javascript for page elements. +// +// Part of the Routino routing software. +// +// This file Copyright 2008,2009 Andrew M. Bishop +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// + + +// +// Display one of the tabs and associated DIV and hide the others +// + +function tab_select(name) +{ + var tab=document.getElementById("tab_" + name); + + if(tab.className=="tab_selected") + {return;} + + // Hide the deslected tabs and DIVs + + var parent=tab.parentNode; + var child=parent.firstChild; + + do + { + if(String(child.id).substr(0,4)=="tab_") + { + var div=document.getElementById(child.id + "_div"); + + child.className="tab_unselected"; + div.style.display="none"; + } + + child=child.nextSibling; + } + while(child!=null); + + // Display the newly selected tab and DIV + + var div=document.getElementById(tab.id + "_div"); + + tab.className="tab_selected"; + div.style.display=""; +} + + +// +// Show the associated DIV +// + +function hideshow_show(name) +{ + var span1=document.getElementById("hideshow_" + name + "_show"); + var span2=document.getElementById("hideshow_" + name + "_hide"); + var div=document.getElementById("hideshow_" + name + "_div"); + + div.style.display=""; + span1.className="hideshow_hide"; + span2.className="hideshow_show"; +} + + +// +// Hide the associated DIV +// + +function hideshow_hide(name) +{ + var span1=document.getElementById("hideshow_" + name + "_show"); + var span2=document.getElementById("hideshow_" + name + "_hide"); + var div=document.getElementById("hideshow_" + name + "_div"); + + div.style.display="none"; + span2.className="hideshow_hide"; + span1.className="hideshow_show"; +} diff --git a/web/www/routino/paths.pl b/web/www/routino/paths.pl new file mode 100644 index 0000000..a896ec3 --- /dev/null +++ b/web/www/routino/paths.pl @@ -0,0 +1,32 @@ +# +# Routino CGI paths Perl script +# +# Part of the Routino routing software. +# +# This file Copyright 2008-2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Directory path parameters + +# EDIT THIS to set the root directory for the non-web data files. +$root_dir="../.."; + +# EDIT THIS if you want to change the location of the individual directories. +$bin_dir="$root_dir/bin"; +$data_dir="$root_dir/data"; +$results_dir="$root_dir/results"; + +1; diff --git a/web/www/routino/results.cgi b/web/www/routino/results.cgi new file mode 100755 index 0000000..5236363 --- /dev/null +++ b/web/www/routino/results.cgi @@ -0,0 +1,74 @@ +#!/usr/bin/perl +# +# Routino router results retrieval CGI +# +# Part of the Routino routing software. +# +# This file Copyright 2008-2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Use the directory paths script +require "paths.pl"; + +# Use the generic router script +require "router.pl"; + +# Use the perl CGI module +use CGI ':cgi'; + +# Create the query and get the parameters + +$query=new CGI; + +@rawparams=$query->param; + +# Legal CGI parameters with regexp validity check + +%legalparams=( + "type" => "(shortest|quickest)", + "format" => "(html|gpx-route|gpx-track|text|text-all)", + + "uuid" => "[0-9a-f]{32}" + ); + +# Validate the CGI parameters, ignore invalid ones + +foreach $key (@rawparams) + { + foreach $test (keys (%legalparams)) + { + if($key =~ m%^$test$%) + { + $value=$query->param($key); + + if($value =~ m%^$legalparams{$test}$%) + { + $cgiparams{$key}=$value; + last; + } + } + } + } + +# Parse the parameters + +$uuid =$cgiparams{"uuid"}; +$type =$cgiparams{"type"}; +$format=$cgiparams{"format"}; + +# Return the file + +ReturnOutput($uuid,$type,$format); diff --git a/web/www/routino/router.cgi b/web/www/routino/router.cgi new file mode 100755 index 0000000..41a6212 --- /dev/null +++ b/web/www/routino/router.cgi @@ -0,0 +1,105 @@ +#!/usr/bin/perl +# +# Routino interactive router CGI +# +# Part of the Routino routing software. +# +# This file Copyright 2008-2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Use the generic router script +require "router.pl"; + +# Use the perl CGI module +use CGI ':cgi'; + +# Create the query and get the parameters + +$query=new CGI; + +@rawparams=$query->param; + +# Legal CGI parameters with regexp validity check + +%legalparams=( + "lon[1-9]" => "[-0-9.]+", + "lat[1-9]" => "[-0-9.]+", + "transport" => "[a-z]+", + "highway-[a-z]+" => "[0-9.]+", + "speed-[a-z]+" => "[0-9.]+", + "property-[a-z]+" => "[0-9.]+", + "oneway" => "(1|0|true|false|on|off)", + "weight" => "[0-9.]+", + "height" => "[0-9.]+", + "width" => "[0-9.]+", + "length" => "[0-9.]+", + "length" => "[0-9.]+", + + "language" => "[-a-zA-Z]+", + "type" => "(shortest|quickest)", + "format" => "(html|gpx-route|gpx-track|text|text-all)" + ); + +# Validate the CGI parameters, ignore invalid ones + +foreach $key (@rawparams) + { + foreach $test (keys (%legalparams)) + { + if($key =~ m%^$test$%) + { + $value=$query->param($key); + + if($value =~ m%^$legalparams{$test}$%) + { + $cgiparams{$key}=$value; + last; + } + } + } + } + +# Get the important parameters + +$type=$cgiparams{type}; +delete $cgiparams{type}; + +$format=$cgiparams{format}; +delete $cgiparams{format}; + +# Fill in the default parameters + +%fullparams=FillInDefaults(%cgiparams); + +# Run the router + +($router_uuid,$router_time,$router_result,$router_message)=RunRouter($type,%fullparams); + +# Return the output + +if($format) + { + ReturnOutput($router_uuid,$type,$format); + } +else + { + print header('text/plain'); + + print "$router_uuid\n"; + print "$router_time\n"; + print "$router_result\n"; + print "$router_message\n"; + } diff --git a/web/www/routino/router.css b/web/www/routino/router.css new file mode 100644 index 0000000..9bb90c0 --- /dev/null +++ b/web/www/routino/router.css @@ -0,0 +1,171 @@ +/* +// Routino router web page style sheet. +// +// Part of the Routino routing software. +// +// This file Copyright 2008-2010 Andrew M. Bishop +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +*/ + + +/*--------------------------------*/ +/* Left panel - override defaults */ +/*--------------------------------*/ + +DIV.hideshow_box +{ + overflow-x: auto; +} + + +/*------------------------------*/ +/* Left panel - generic options */ +/*------------------------------*/ + +DIV.scrollable +{ + overflow: auto; + + height: 20em; +} + + +/*-----------------------------------*/ +/* Left panel - specific tab options */ +/*-----------------------------------*/ + +DIV#tab_options_div IMG +{ + cursor: pointer; + vertical-align: bottom; +} + +DIV#tab_options_div IMG:hover +{ + background: #F0F000; +} + +DIV#tab_options_div TABLE +{ + padding: 0; + border: 0 hidden; + margin: 0; +} + +DIV#tab_options_div TABLE TD +{ + padding: 0; + border: 0; + margin: 0; +} + +DIV#tab_options_div INPUT +{ + padding: 0; + border: 1px solid; + margin: 0; + + text-align: right; +} + +DIV#tab_options_div INPUT:hover +{ + background: #F0F0C0; +} + +DIV#tab_options_div INPUT#shortest +{ + margin: 3px; + border: 3px solid; + + border-color: #00FF00; + + background: #C0F0C0; + + text-align: center; +} + +DIV#tab_options_div INPUT#quickest +{ + margin: 3px; + border: 3px solid; + + border-color: #0000FF; + + background: #C0C0F0; + + text-align: center; +} + +DIV#tab_results_div TABLE +{ + border-collapse: collapse; + border: hidden; +} + +DIV#tab_results_div TD.distance +{ + text-align: left; +} + +DIV#tab_results_div TD.highway +{ + text-align: left; + padding-left: 10px; +} + +DIV#tab_results_div DIV#shortest_links A:hover +{ + background: #C0F0C0; +} + +DIV#tab_results_div DIV#shortest_route TR:hover +{ + cursor: pointer; + + background: #C0F0C0; +} + +DIV#tab_results_div DIV#quickest_links A:hover +{ + background: #C0C0F0; +} + +DIV#tab_results_div DIV#quickest_route TR:hover +{ + cursor: pointer; + + background: #C0C0F0; +} + + +/*-------------------------------------------------*/ +/* Popup - using the styles defined in HTML output */ +/*-------------------------------------------------*/ + +DIV.popup table {table-layout: fixed; border: none; border-collapse: collapse;} +DIV.popup tr {border: 0px;} +DIV.popup tr.c {display: none;} /* coords */ +DIV.popup tr.n {} /* node */ +DIV.popup tr.s {} /* segment */ +DIV.popup tr.t {font-weight: bold;} /* total */ +DIV.popup td.l {font-weight: bold;} +DIV.popup td.r {} +DIV.popup span.w {font-weight: bold;} /* waypoint */ +DIV.popup span.h {text-decoration: underline;} /* highway */ +DIV.popup span.d {} /* segment distance */ +DIV.popup span.j {font-style: italic;} /* total journey distance */ +DIV.popup span.t {font-variant: small-caps;} /* turn */ +DIV.popup span.b {font-variant: small-caps;} /* bearing */ diff --git a/web/www/routino/router.html b/web/www/routino/router.html new file mode 120000 index 0000000..9f14bc5 --- /dev/null +++ b/web/www/routino/router.html @@ -0,0 +1 @@ +router.html.en \ No newline at end of file diff --git a/web/www/routino/router.html.en b/web/www/routino/router.html.en new file mode 100644 index 0000000..ec1020e --- /dev/null +++ b/web/www/routino/router.html.en @@ -0,0 +1,550 @@ + + + + + + +Routino : Route Planner for OpenStreetMap Data + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ Options + Results + Data +
+ +
+ +
+
+ Routino OpenStreetMap Router + This web page allows routing within the data collected by OpenStreetMap. + Select start and end points (click on the marker icons below), select routing preferences then find a route. + +
+ +
+ Show + Hide + Language + + + + +
+ +
+ Show + Hide + Waypoints +
+ + + + + + + + + + + +
+ Waypoint 1  + + E  + + N  + + o + ^ + +
+ ~ + v + - +
+ Waypoint 2  + + E  + + N  + + o + ^ + +
+ ~ + v + - +
+ Waypoint 3  + + E  + + N  + + o + ^ + +
+ ~ + v + - +
+ Waypoint 4  + + E  + + N  + + o + ^ + +
+ ~ + v + - +
+ Waypoint 5  + + E  + + N  + + o + ^ + +
+ ~ + v + - +
+ Waypoint 6  + + E  + + N  + + o + ^ + +
+ ~ + v + - +
+ Waypoint 7  + + E  + + N  + + o + ^ + +
+ ~ + v + - +
+ Waypoint 8  + + E  + + N  + + o + ^ + +
+ ~ + v + - +
+ Waypoint 9  + + E  + + N  + + o + ^ + +
+ ~ + v + - + +
+
+
+
+ +
+ Show + Hide + Transport Type +
+ +
Foot +
Horse +
Wheelchair +
Bicycle +
Moped +
Motorbike +
Motorcar +
Goods +
HGV +
PSV +
+
+
+ +
+ Show + Hide + Highway Preferences + +
+ +
+ Show + Hide + Speed Limits + +
+ +
+ Show + Hide + Property Preferences + +
+ +
+ Show + Hide + Other Restrictions + +
+ +
+ Find + + +
+ + + +
+ Show + Hide + Help +
+
+

+ Quick Start +
+ Click on marker icons (above) to place them on the map (right). Then + drag them to the correct position. Zooming the map before placing the + markers is probably easiest. Alternatively type the latitude and + longitude into the boxes above. +

+ Select the transport type, allowed highway types, speed limits, highway + properties and other restrictions from the options above. + Select "Shortest" or "Quickest" to calculate the route and display it + on the map. +

+ Waypoints +
+ Clicking on the marker icons will toggle the display of them on the map. + When a route is calculated it will visit (as close as possible + for the selected transport type) each of the waypoints that have + markers on the map in the order given. +

+ Transport Type +
+ Selecting a transport type will restrict the chosen route to + those on which it is allowed and set default values for the + other parameters. +

+ Highway Preferences +
+ The highway preference is selected as a percentage and routes are chosen that + try to follow the preferred highways. + For example if a "Primary" road is given a "110%" preference and a "Secondary" + road is given a "100%" preference then it means that a route on a Primary road + can be up to 10% longer than on a secondary road and still be selected. +

+ Speed Limits +
+ The speed limits chosen here for the different types of highway apply if the + highway has no other speed limit marked or it is higher than the chosen one. +

+ Property Preferences +
+ The property preference is selected as a percentage and routes are chosen that + try to follow highways with the preferred property. + For example if a "Paved" highway is given a "75%" preference then it means that + an unpaved highway is automatically given a "25%" preference so that a route on + a paved highway can be 3 times the length of an unpaved one and still be + selected. +

+ Other Restrictions +
+ These allow a route to be found that avoids marked limits on + weight, height, width or length. It is also possible to ignore + one-way restrictions (e.g. if walking). +

+
+
+
+
+ + + + + + + +
+ + + +
+
+ +
+ +
+ + + diff --git a/web/www/routino/router.js b/web/www/routino/router.js new file mode 100644 index 0000000..efb421f --- /dev/null +++ b/web/www/routino/router.js @@ -0,0 +1,1503 @@ +// +// Routino router web page Javascript +// +// Part of the Routino routing software. +// +// This file Copyright 2008-2010 Andrew M. Bishop +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// + +//////////////////////////////////////////////////////////////////////////////// +/////////////////////////// Routino default profile //////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +var routino={ // contains all default Routino options (generated using "--help-profile-js"). + + // Default transport type + transport: 'motorcar', + + // Transport types + transports: {foot: 1, horse: 2, wheelchair: 3, bicycle: 4, moped: 5, motorbike: 6, motorcar: 7, goods: 8, hgv: 9, psv: 10}, + + // Highway types + highways: {motorway: 1, trunk: 2, primary: 3, secondary: 4, tertiary: 5, unclassified: 6, residential: 7, service: 8, track: 9, cycleway: 10, path: 11, steps: 12}, + + // Property types + properties: {paved: 1, multilane: 2, bridge: 3, tunnel: 4}, + + // Restriction types + restrictions: {oneway: 1, weight: 2, height: 3, width: 4, length: 5}, + + // Allowed highways + profile_highway: { + motorway: {foot: 0, horse: 0, wheelchair: 0, bicycle: 0, moped: 0, motorbike: 100, motorcar: 100, goods: 100, hgv: 100, psv: 100}, + trunk: {foot: 40, horse: 25, wheelchair: 40, bicycle: 30, moped: 90, motorbike: 100, motorcar: 100, goods: 100, hgv: 100, psv: 100}, + primary: {foot: 50, horse: 50, wheelchair: 50, bicycle: 70, moped: 100, motorbike: 90, motorcar: 90, goods: 90, hgv: 90, psv: 90}, + secondary: {foot: 60, horse: 50, wheelchair: 60, bicycle: 80, moped: 90, motorbike: 80, motorcar: 80, goods: 80, hgv: 80, psv: 80}, + tertiary: {foot: 70, horse: 75, wheelchair: 70, bicycle: 90, moped: 80, motorbike: 70, motorcar: 70, goods: 70, hgv: 70, psv: 70}, + unclassified: {foot: 80, horse: 75, wheelchair: 80, bicycle: 90, moped: 70, motorbike: 60, motorcar: 60, goods: 60, hgv: 60, psv: 60}, + residential: {foot: 90, horse: 75, wheelchair: 90, bicycle: 90, moped: 60, motorbike: 50, motorcar: 50, goods: 50, hgv: 50, psv: 50}, + service: {foot: 90, horse: 75, wheelchair: 90, bicycle: 90, moped: 80, motorbike: 80, motorcar: 80, goods: 80, hgv: 80, psv: 80}, + track: {foot: 95, horse: 100, wheelchair: 95, bicycle: 90, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0}, + cycleway: {foot: 95, horse: 90, wheelchair: 95, bicycle: 100, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0}, + path: {foot: 100, horse: 100, wheelchair: 100, bicycle: 90, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0}, + steps: {foot: 80, horse: 0, wheelchair: 0, bicycle: 0, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0} + }, + + // Speed limits + profile_speed: { + motorway: {foot: 0, horse: 0, wheelchair: 0, bicycle: 0, moped: 48, motorbike: 112, motorcar: 112, goods: 96, hgv: 89, psv: 89}, + trunk: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 96, motorcar: 96, goods: 96, hgv: 80, psv: 80}, + primary: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 96, motorcar: 96, goods: 96, hgv: 80, psv: 80}, + secondary: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 88, motorcar: 88, goods: 88, hgv: 80, psv: 80}, + tertiary: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 80, motorcar: 80, goods: 80, hgv: 80, psv: 80}, + unclassified: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 64, motorcar: 64, goods: 64, hgv: 64, psv: 64}, + residential: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 48, motorbike: 48, motorcar: 48, goods: 48, hgv: 48, psv: 48}, + service: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 32, motorbike: 32, motorcar: 32, goods: 32, hgv: 32, psv: 32}, + track: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 16, motorbike: 16, motorcar: 16, goods: 16, hgv: 16, psv: 16}, + cycleway: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0}, + path: {foot: 4, horse: 8, wheelchair: 4, bicycle: 20, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0}, + steps: {foot: 4, horse: 0, wheelchair: 4, bicycle: 0, moped: 0, motorbike: 0, motorcar: 0, goods: 0, hgv: 0, psv: 0} + }, + + // Highway properties + profile_property: { + paved: {foot: 50, horse: 20, wheelchair: 90, bicycle: 50, moped: 100, motorbike: 100, motorcar: 100, goods: 100, hgv: 100, psv: 100}, + multilane: {foot: 25, horse: 25, wheelchair: 25, bicycle: 25, moped: 25, motorbike: 75, motorcar: 75, goods: 75, hgv: 75, psv: 75}, + bridge: {foot: 50, horse: 50, wheelchair: 50, bicycle: 50, moped: 50, motorbike: 50, motorcar: 50, goods: 50, hgv: 50, psv: 50}, + tunnel: {foot: 50, horse: 50, wheelchair: 50, bicycle: 50, moped: 50, motorbike: 50, motorcar: 50, goods: 50, hgv: 50, psv: 50} + }, + + // Restrictions + profile_restrictions: { + oneway: {foot: 0, horse: 1, wheelchair: 0, bicycle: 1, moped: 1, motorbike: 1, motorcar: 1, goods: 1, hgv: 1, psv: 1}, + weight: {foot: 0.0, horse: 0.0, wheelchair: 0.0, bicycle: 0.0, moped: 0.0, motorbike: 0.0, motorcar: 0.0, goods: 5.0, hgv: 10.0, psv: 15.0}, + height: {foot: 0.0, horse: 0.0, wheelchair: 0.0, bicycle: 0.0, moped: 0.0, motorbike: 0.0, motorcar: 0.0, goods: 2.5, hgv: 3.0, psv: 3.0}, + width: {foot: 0.0, horse: 0.0, wheelchair: 0.0, bicycle: 0.0, moped: 0.0, motorbike: 0.0, motorcar: 0.0, goods: 2.0, hgv: 2.5, psv: 2.5}, + length: {foot: 0.0, horse: 0.0, wheelchair: 0.0, bicycle: 0.0, moped: 0.0, motorbike: 0.0, motorcar: 0.0, goods: 5.0, hgv: 6.0, psv: 6.0} + } + +}; // end of routino variable + +// Make a deep copy of the routino profile. + +var routino_default={}; +for(var l1 in routino) + if(typeof(routino[l1])!='object') + routino_default[l1]=routino[l1]; + else + { + routino_default[l1]={}; + for(var l2 in routino[l1]) + if(typeof(routino[l1][l2])!='object') + routino_default[l1][l2]=Number(routino[l1][l2]); + else + { + routino_default[l1][l2]={}; + for(var l3 in routino[l1][l2]) + routino_default[l1][l2][l3]=Number(routino[l1][l2][l3]); + } + } + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////// Form handling ///////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// +// Form initialisation - fill in the uninitialised parts +// + +function form_init() +{ + // Update the routino variable with the URL settings (from the HTML). + + for(var lang=0;lang< document.forms["form"].elements["language"].length;lang++) + if(document.forms["form"].elements["language"][lang].checked) + formSetLanguage(document.forms["form"].elements["language"][lang].value); + + var transport=null; + + for(var key in routino.transports) + if(document.forms["form"].elements["transport"][routino.transports[key]-1].checked) + transport=key; + + if(transport==null) + formSetTransport(routino.transport); + else + { + routino.transport=transport; + + for(var key in routino.profile_highway) + { + if(document.forms["form"].elements["highway-" + key].value=="") + document.forms["form"].elements["highway-" + key].value=routino.profile_highway[key][routino.transport]; + else + formSetHighway(key); + } + + for(var key in routino.profile_speed) + { + if(document.forms["form"].elements["speed-" + key].value=="") + document.forms["form"].elements["speed-" + key].value=routino.profile_speed[key][routino.transport]; + else + formSetSpeed(key); + } + + for(var key in routino.profile_property) + { + if(document.forms["form"].elements["property-" + key].value=="") + document.forms["form"].elements["property-" + key].value=routino.profile_property[key][routino.transport]; + else + formSetProperty(key); + } + + for(var key in routino.restrictions) + { + if(key=="oneway") + formSetRestriction(key); + else + { + if(document.forms["form"].elements["restrict-" + key].value=="") + document.forms["form"].elements["restrict-" + key].value=routino.profile_restrictions[key][routino.transport]; + else + formSetRestriction(key); + } + } + } + + // Delete the extra empty waypoints + + var filled=0; + + for(var marker=nmarkers;marker>=1;marker--) + { + var lon=document.forms["form"].elements["lon" + marker].value; + var lat=document.forms["form"].elements["lat" + marker].value; + + if(lon != "" && lat != "") + { + filled++; + markerAddMap(marker); + } + else if(filled==0) + markerRemove(marker); + } + + // Get the home location cookie and compare to each waypoint + + var cookies=document.cookie.split('; '); + + for(var cookie=0;cookie=1;marker--) + { + var lon=document.forms["form"].elements["lon" + marker].value; + var lat=document.forms["form"].elements["lat" + marker].value; + + if(lon==homelon && lat==homelat) + updateIcon(marker); + } + + // If the first location is empty and the cookie is set then fill it. + + if(document.forms["form"].elements["lon1"].value=="" && document.forms["form"].elements["lat1"].value=="") + { + document.forms["form"].elements["lon1"].value=homelon; + document.forms["form"].elements["lat1"].value=homelat; + + markerAddMap(1); + } + } + + updateCustomURL(); +} + + +// +// Change of language in the form +// + +function formSetLanguage(type) +{ + routino.language=type; + + updateCustomURL(); +} + + +// +// Change of transport in the form +// + +function formSetTransport(type) +{ + routino.transport=type; + + for(var key in routino.transports) + document.forms["form"].elements["transport"][routino.transports[key]-1].checked=(key==routino.transport); + + for(var key in routino.profile_highway) + document.forms["form"].elements["highway-" + key].value=routino.profile_highway[key][routino.transport]; + + for(var key in routino.profile_speed) + document.forms["form"].elements["speed-" + key].value=routino.profile_speed[key][routino.transport]; + + for(var key in routino.profile_property) + document.forms["form"].elements["property-" + key].value=routino.profile_property[key][routino.transport]; + + for(var key in routino.restrictions) + { + if(key=="oneway") + document.forms["form"].elements["restrict-" + key].checked=routino.profile_restrictions[key][routino.transport]; + else + document.forms["form"].elements["restrict-" + key].value=routino.profile_restrictions[key][routino.transport]; + } + + paramschanged=true; + + updateCustomURL(); +} + + +// +// Change of highway in the form +// + +function formSetHighway(type) +{ + routino.profile_highway[type][routino.transport]=document.forms["form"].elements["highway-" + type].value; + + paramschanged=true; + + updateCustomURL(); +} + + +// +// Change of Speed in the form +// + +function formSetSpeed(type) +{ + routino.profile_speed[type][routino.transport]=document.forms["form"].elements["speed-" + type].value; + + paramschanged=true; + + updateCustomURL(); +} + + +// +// Change of Property in the form +// + +function formSetProperty(type) +{ + routino.profile_property[type][routino.transport]=document.forms["form"].elements["property-" + type].value; + + paramschanged=true; + + updateCustomURL(); +} + + +// +// Change of oneway rule in the form +// + +function formSetRestriction(type) +{ + if(type=="oneway") + routino.profile_restrictions[type][routino.transport]=document.forms["form"].elements["restrict-" + type].checked; + else + routino.profile_restrictions[type][routino.transport]=document.forms["form"].elements["restrict-" + type].value; + + paramschanged=true; + + updateCustomURL(); +} + + +// +// Set the feature coordinates from the form when the form changes. +// + +function formSetCoords(marker) +{ + var lonlat=map.getCenter().clone(); + + lonlat.transform(map.getProjectionObject(),epsg4326); + + var lon=document.forms["form"].elements["lon" + marker].value; + var lat=document.forms["form"].elements["lat" + marker].value; + + if(lon!="") + { + if(lon<-180) lon=-180; + if(lon>+180) lon=+180; + lonlat.lon=lon; + } + + if(lat!="") + { + if(lat<-90 ) lat=-90 ; + if(lat>+90 ) lat=+90 ; + lonlat.lat=lat; + } + + var point = lonlat.clone(); + + point.transform(epsg4326,map.getProjectionObject()); + + markers[marker].move(point); + + markersmoved=true; + + coordsSetForm(marker); +} + + +// +// Set the feature coordinates in the form. +// + +function coordsSetForm(marker) +{ + var lonlat = new OpenLayers.LonLat(markers[marker].geometry.x, markers[marker].geometry.y); + lonlat.transform(map.getProjectionObject(),epsg4326); + + var lon=format5f(lonlat.lon); + var lat=format5f(lonlat.lat); + + document.forms["form"].elements["lon" + marker].value=lon; + document.forms["form"].elements["lat" + marker].value=lat; + + updateIcon(marker); + + updateCustomURL(); +} + + +// +// Format a number in printf("%.5f") format. +// + +function format5f(number) +{ + var newnumber=Math.floor(number*100000+0.5); + var delta=0; + + if(newnumber>=0 && newnumber<100000) delta= 100000; + if(newnumber<0 && newnumber>-100000) delta=-100000; + + var string=String(newnumber+delta); + + var intpart =string.substring(0,string.length-5); + var fracpart=string.substring(string.length-5,string.length); + + if(delta>0) intpart="0"; + if(delta<0) intpart="-0"; + + return(intpart + "." + fracpart); +} + + +// +// Build a set of URL arguments +// + +function buildURLArguments(all) +{ + var url="?"; + + url=url + "transport=" + routino.transport; + + for(var marker=1;marker<=vismarkers;marker++) + if(markers[marker].style.display == "" || all) + { + url=url + ";lon" + marker + "=" + document.forms["form"].elements["lon" + marker].value; + url=url + ";lat" + marker + "=" + document.forms["form"].elements["lat" + marker].value; + } + + for(var key in routino.profile_highway) + if(routino.profile_highway[key][routino.transport]!=routino_default.profile_highway[key][routino.transport]) + url=url + ";highway-" + key + "=" + routino.profile_highway[key][routino.transport]; + + for(var key in routino.profile_speed) + if(routino.profile_speed[key][routino.transport]!=routino_default.profile_speed[key][routino.transport]) + url=url + ";speed-" + key + "=" + routino.profile_speed[key][routino.transport]; + + for(var key in routino.profile_property) + if(routino.profile_property[key][routino.transport]!=routino_default.profile_property[key][routino.transport]) + url=url + ";property-" + key + "=" + routino.profile_property[key][routino.transport]; + + for(var key in routino.restrictions) + if(routino.profile_restrictions[key][routino.transport]!=routino_default.profile_restrictions[key][routino.transport]) + url=url + ";" + key + "=" + routino.profile_restrictions[key][routino.transport]; + + if(routino.language) + url=url + ";language=" + routino.language; + + return(url); +} + + +// +// Update custom URL +// + +function updateCustomURL() +{ + var visualiser_url=document.getElementById("visualiser_url"); + var link_url =document.getElementById("link_url"); + var edit_url =document.getElementById("edit_url"); + + visualiser_url.href="customvisualiser.cgi?" + map_args; + link_url.href="customrouter.cgi" + buildURLArguments(1) + ";" + map_args; + edit_url.href="http://www.openstreetmap.org/edit?" + map_args; +} + + +// +// Block the use of the return key to submit the form +// + +function block_return_key() +{ + var form=document.getElementById("form"); + + if(form.addEventListener) + form.addEventListener('keyup', discardReturnKey, false); + else if(form.attachEvent) + form.attachEvent('keyup', discardReturnKey); // Internet Explorer +} + +// +// Function to discard the return key if pressed +// + +function discardReturnKey(ev) +{ + if(ev.keyCode==13) + return(false); + + return(true); +} + + +//////////////////////////////////////////////////////////////////////////////// +///////////////////////////////// Map handling ///////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +var map; +var layerMapOSM, layerVectors, layerGPX; +var epsg4326, epsg900913; +var map_args; + +// +// Initialise the 'map' object +// + +function map_init(lat,lon,zoom) +{ + // Default configuration: + // UK coordinate range + // West -11.0, South 49.5, East 2.0, North 61.0 + // Zoom level 4 to 15 + + // EDIT THIS below to change the visible map limits + + var westedge = -11.0; // Minimum longitude (degrees) + var eastedge = 2.0; // Maximum longitude (degrees) + var southedge = 49.5; // Minimum latitude (degrees) + var northedge = 61.0; // Maximum latitude (degrees) + var zoomout = 4; // Minimum zoom + var zoomin = 15; // Maximum zoom + + // EDIT THIS above to change the visible map limits + + // + // Create the map + // + + epsg4326=new OpenLayers.Projection("EPSG:4326"); + epsg900913=new OpenLayers.Projection("EPSG:900913"); + + map = new OpenLayers.Map ("map", + { + controls:[ + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.PanZoomBar(), + new OpenLayers.Control.ScaleLine(), + new OpenLayers.Control.LayerSwitcher() + ], + + projection: epsg900913, + displayProjection: epsg4326, + + minZoomLevel: zoomout, + numZoomLevels: zoomin-zoomout+1, + maxResolution: 156543.0339 / Math.pow(2,zoomout), + + maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34), + restrictedExtent: new OpenLayers.Bounds(westedge,southedge,eastedge,northedge).transform(epsg4326,epsg900913), + + units: "m" + }); + + map.events.register("moveend", map, mapMoved); + + // Add a map tile layer (OpenStreetMap tiles, direct access) + + layerMapOSM = new OpenLayers.Layer.TMS("Original OSM map", + "http://tile.openstreetmap.org/", + { + emptyUrl: "http://openstreetmap.org/openlayers/img/404.png", + type: 'png', + getURL: limitedUrl, + displayOutsideMaxExtent: true, + buffer: 1 + }); + map.addLayer(layerMapOSM); + + // Get a URL for the tile; limited to map restricted extent. + + function limitedUrl(bounds) + { + var z = map.getZoom() + map.minZoomLevel; + + if (z>=7 && (bounds.right < map.restrictedExtent.left || + bounds.left > map.restrictedExtent.right || + bounds.top < map.restrictedExtent.bottom || + bounds.bottom > map.restrictedExtent.top)) + return this.emptyUrl; + + var res = map.getResolution(); + var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h)); + var limit = Math.pow(2, z); + + if (y < 0 || y >= limit) + return this.emptyUrl; + + var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w)); + + x = ((x % limit) + limit) % limit; + return this.url + z + "/" + x + "/" + y + "." + this.type; + } + + // Define a GPX layer but don't add it yet + + layerGPX={shortest: null, quickest: null}; + + gpx_style={shortest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#00FF00"}), + quickest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#0000FF"})}; + + // Add a vectors layer + + layerVectors = new OpenLayers.Layer.Vector("Markers"); + map.addLayer(layerVectors); + + // A set of markers + + nmarkers=99; + vismarkers=0; + markers={}; + markersmoved=false; + paramschanged=false; + + for(var marker=1;marker<=nmarkers;marker++) + { + if(document.forms["form"].elements["lon" + marker] != undefined) + { + markers[marker] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{}, + new OpenLayers.Style({},{externalGraphic: 'icons/marker-' + marker + '-red.png', + fillColor: "white", + graphicYOffset: -25, + graphicWidth: 21, + graphicHeight: 25, + display: "none"})); + + layerVectors.addFeatures([markers[marker]]); + } + else + { + nmarkers=marker-1; + vismarkers=marker-1; + break; + } + } + + // A function to drag the markers + + var drag = new OpenLayers.Control.DragFeature(layerVectors, + {onDrag: dragMove, + onComplete: dragComplete }); + map.addControl(drag); + drag.activate(); + + // Markers to highlight a selected point + + for(var highlight in highlights) + { + highlights[highlight] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{}, + new OpenLayers.Style({},{strokeColor: route_dark_colours[highlight], + fillColor: "white", + pointRadius: 10, + strokeWidth: 4, + fillOpacity: 0, + display: "none"})); + + layerVectors.addFeatures([highlights[highlight]]); + } + + // A popup for routing results + + for(var popup in popups) + popups[popup] = createPopup(popup); + + // Set the map centre to the limited range specified + + map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,true)); + map.maxResolution = map.getResolution(); + + // Move the map + + if(lon != 'lon' && lat != 'lat' && zoom != 'zoom') + { + var lonlat = new OpenLayers.LonLat(lon,lat).transform(epsg4326,map.getProjectionObject()); + + map.moveTo(lonlat,zoom-map.minZoomLevel); + } +} + + +// +// Map has moved +// + +function mapMoved() +{ + var centre = map.getCenter().clone(); + + var lonlat = centre.transform(map.getProjectionObject(),epsg4326); + + var zoom = this.getZoom() + map.minZoomLevel; + + map_args="lat=" + lonlat.lat + ";lon=" + lonlat.lon + ";zoom=" + zoom; + + updateCustomURL(); +} + + +// +// OpenLayers.Control.DragFeature callback for a drag occuring. +// + +function dragMove(feature,pixel) +{ + for(var marker in markers) + if(feature==markers[marker]) + { + markersmoved=true; + + coordsSetForm(marker); + } +} + + +// +// OpenLayers.Control.DragFeature callback for completing a drag. +// + +function dragComplete(feature,pixel) +{ + for(var marker in markers) + if(feature==markers[marker]) + { + markersmoved=true; + + coordsSetForm(marker); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////// Marker handling //////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +var nmarkers, vismarkers, markers, markersmoved, paramschanged; +var homelat=null, homelon=null; + + +// +// Toggle a marker on the map. +// + +function markerToggleMap(marker) +{ + if(markers[marker].style.display == "") + markerRemoveMap(marker); + else + markerAddMap(marker); +} + + +// +// Show a marker on the map. +// + +function markerAddMap(marker) +{ + markers[marker].style.display = ""; + + formSetCoords(marker); + + updateIcon(marker); + + markersmoved=true; +} + + +// +// Remove a marker from the map. +// + +function markerRemoveMap(marker) +{ + markers[marker].style.display = "none"; + + updateIcon(marker); + + markersmoved=true; +} + + +// +// Centre the marker on the map +// + +function markerCentre(marker) +{ + document.forms["form"].elements["lon" + marker].value=""; + document.forms["form"].elements["lat" + marker].value=""; + + formSetCoords(marker); + + markersmoved=true; +} + + +// +// Clear the current marker. +// + +function markerRemove(marker) +{ + for(var marker2=marker;marker2marker;marker2--) + { + document.forms["form"].elements["lon" + marker2].value=document.forms["form"].elements["lon" + (marker2-1)].value; + document.forms["form"].elements["lat" + marker2].value=document.forms["form"].elements["lat" + (marker2-1)].value; + + if(markers[marker2-1].style.display=="") + markerAddMap(marker2); + else + markerRemoveMap(marker2); + } + + document.forms["form"].elements["lon" + marker].value=""; + document.forms["form"].elements["lat" + marker].value=""; + markers[marker].style.display="none"; + + markerRemoveMap(marker); + + updateCustomURL(); +} + + +// +// Add a marker after the current one. +// + +function markerAddAfter(marker) +{ + if(vismarkers==nmarkers) + return false; + + vismarkers++; + + var marker_tr=document.getElementById("point" + vismarkers); + + marker_tr.style.display=""; + + for(var marker2=vismarkers;marker2>(marker+1);marker2--) + { + document.forms["form"].elements["lon" + marker2].value=document.forms["form"].elements["lon" + (marker2-1)].value; + document.forms["form"].elements["lat" + marker2].value=document.forms["form"].elements["lat" + (marker2-1)].value; + + if(markers[marker2-1].style.display=="") + markerAddMap(marker2); + else + markerRemoveMap(marker2); + } + + document.forms["form"].elements["lon" + (marker+1)].value=""; + document.forms["form"].elements["lat" + (marker+1)].value=""; + markers[marker+1].style.display="none"; + + markerRemoveMap(marker+1); + + updateCustomURL(); +} + + +// +// Set this marker as the home location. +// + +function markerHome(marker) +{ + if(markerHomeCookie(marker)) + for(marker=1;marker<=nmarkers;marker++) + updateIcon(marker); +} + + +// +// Update an icon to set colours and home or normal marker. +// + +function updateIcon(marker) +{ + var lon=document.forms["form"].elements["lon" + marker].value; + var lat=document.forms["form"].elements["lat" + marker].value; + + if(lon==homelon && lat==homelat) + { + if(markers[marker].style.display=="") + document.images["waypoint" + marker].src="icons/marker-home-red.png"; + else + document.images["waypoint" + marker].src="icons/marker-home-grey.png"; + + markers[marker].style.externalGraphic="icons/marker-home-red.png"; + } + else + { + if(markers[marker].style.display=="") + document.images["waypoint" + marker].src="icons/marker-" + marker + "-red.png"; + else + document.images["waypoint" + marker].src="icons/marker-" + marker + "-grey.png"; + + markers[marker].style.externalGraphic="icons/marker-" + marker + "-red.png"; + } + + layerVectors.drawFeature(markers[marker]); +} + + +// +// Set or clear the home marker icon +// + +function markerHomeCookie(marker) +{ + var lon=document.forms["form"].elements["lon" + marker].value; + var lat=document.forms["form"].elements["lat" + marker].value; + + if(lon=="" || lat=="") + return(false); + + var cookie; + var date = new Date(); + + if((homelat==null && homelon==null) || + (homelat!=lat && homelon!=lon)) + { + cookie="Routino-home=lon:" + lon + ":lat:" + lat; + + date.setUTCFullYear(date.getUTCFullYear()+5); + + homelat=lat; + homelon=lon; + } + else + { + cookie="Routino-home=unset"; + + date.setUTCFullYear(date.getUTCFullYear()-1); + + homelat=null; + homelon=null; + } + + document.cookie=cookie + ";expires=" + date.toGMTString(); + + return(true); +} + + +// +// Move this marker up. +// + +function markerMoveUp(marker) +{ + if(marker==1) + return false; + + markerSwap(marker,marker-1); +} + + +// +// Move this marker down. +// + +function markerMoveDown(marker) +{ + if(marker==vismarkers) + return false; + + markerSwap(marker,marker+1); +} + + +// +// Swap a pair of markers. +// + +function markerSwap(marker1,marker2) +{ + var lon=document.forms["form"].elements["lon" + marker1].value; + var lat=document.forms["form"].elements["lat" + marker1].value; + var display=markers[marker1].style.display; + + document.forms["form"].elements["lon" + marker1].value=document.forms["form"].elements["lon" + marker2].value; + document.forms["form"].elements["lat" + marker1].value=document.forms["form"].elements["lat" + marker2].value; + if(markers[marker2].style.display=="") + markerAddMap(marker1); + else + markerRemoveMap(marker1); + + document.forms["form"].elements["lon" + marker2].value=lon; + document.forms["form"].elements["lat" + marker2].value=lat; + if(display=="") + markerAddMap(marker2); + else + markerRemoveMap(marker2); + + updateCustomURL(); +} + + +// +// Reverse the markers. +// + +function markersReverse() +{ + for(var marker=1;marker<=vismarkers/2;marker++) + markerSwap(marker,vismarkers+1-marker); + + updateCustomURL(); +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Route results handling //////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +var route_light_colours={shortest: "#60C060", quickest: "#6060C0"}; +var route_dark_colours ={shortest: "#408040", quickest: "#404080"}; + +var highlights={shortest: null, quickest: null}; +var popups={shortest: null, quickest: null}; +var routepoints={shortest: {}, quickest: {}}; +var gpx_style={shortest: null, quickest: null}; + +// +// Zoom to a specific item in the route +// + +function zoomTo(type,line) +{ + var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat).transform(epsg4326,map.getProjectionObject()); + + map.moveTo(lonlat,map.numZoomLevels-2); +} + + +// +// Highlight a specific item in the route +// + +function highlight(type,line) +{ + if(line==-1) + { + highlights[type].style.display = "none"; + + drawPopup(popups[type],null); + } + else + { + // Marker + + var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat).transform(epsg4326,map.getProjectionObject()); + + highlights[type].move(lonlat); + + if(highlights[type].style.display = "none") + highlights[type].style.display = ""; + + // Popup + + drawPopup(popups[type],"" + routepoints[type][line].html + "
"); + } + + layerVectors.drawFeature(highlights[type]); +} + + +// +// Create a popup - not using OpenLayers because want it fixed on screen not fixed on map. +// + +function createPopup(type) +{ + var popup=document.createElement('div'); + + popup.className = "popup"; + + popup.innerHTML = ""; + + popup.style.display = "none"; + + popup.style.position = "fixed"; + popup.style.top = "-4000px"; + popup.style.left = "-4000px"; + popup.style.zIndex = "100"; + + popup.style.padding = "5px"; + + popup.style.opacity=0.85; + popup.style.backgroundColor=route_light_colours[type]; + popup.style.border="4px solid " + route_dark_colours[type]; + + document.body.appendChild(popup); + + return(popup); +} + + +// +// Draw a popup - not using OpenLayers because want it fixed on screen not fixed on map. +// + +function drawPopup(popup,html) +{ + if(html==null) + { + popup.style.display="none"; + return; + } + + if(popup.style.display=="none") + { + var map_div=document.getElementById("map"); + + popup.style.left =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px"; + popup.style.top = map_div.offsetTop +30 + "px"; + popup.style.width =map_div.clientWidth-100 + "px"; + + popup.style.display=""; + } + + popup.innerHTML=html; +} + + +// +// Remove a GPX trace +// + +function removeGPXTrace(type) +{ + map.removeLayer(layerGPX[type]); + layerGPX[type].destroy(); + layerGPX[type]=null; + + displayStatus(type,"no_info"); + + var div_links=document.getElementById(type + "_links"); + div_links.style.display = "none"; + + var div_route=document.getElementById(type + "_route"); + div_route.innerHTML = ""; + + hideshow_hide(type); +} + + +//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////// Server handling //////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// +// Display data statistics +// + +function displayStatistics() +{ + // Use AJAX to get the statistics + + OpenLayers.loadURL("statistics.cgi",null,null,runStatisticsSuccess); +} + + +// +// Success in running data statistics generation. +// + +function runStatisticsSuccess(response) +{ + var statistics_data=document.getElementById("statistics_data"); + var statistics_link=document.getElementById("statistics_link"); + + statistics_data.innerHTML="
" + response.responseText + "
"; + + statistics_link.style.display="none"; +} + + +// +// Submit form - perform the routing +// + +function findRoute(type) +{ + tab_select("results"); + + hideshow_hide('help_options'); + hideshow_hide('shortest'); + hideshow_hide('quickest'); + + displayStatus("result","running"); + + var url="router.cgi" + buildURLArguments(0) + ";type=" + type; + + // Destroy the existing layer(s) + + if(markersmoved || paramschanged) + { + if(layerGPX.shortest!=null) + removeGPXTrace("shortest"); + if(layerGPX.quickest!=null) + removeGPXTrace("quickest"); + markersmoved=false; + paramschanged=false; + } + else if(layerGPX[type]!=null) + removeGPXTrace(type); + + // Use AJAX to run the router + + routing_type=type; + + OpenLayers.loadURL(url,null,null,runRouterSuccess,runRouterFailure); +} + + +// +// Success in running router. +// + +function runRouterSuccess(response) +{ + var lines=response.responseText.split('\n'); + + var uuid=lines[0]; + var cpuinfo=lines[1]; + var distinfo=lines[2]; + var message=lines[3]; + + // Update the status message + + if(message!="") + { + displayStatus("result","error"); + hideshow_show('help_route'); + return; + } + else + { + displayStatus("result","complete"); + hideshow_hide('help_route'); + } + + // Update the routing result message + + displayStatus(routing_type,"info",distinfo.bold()); + + var link; + + link=document.getElementById(routing_type + "_html"); + link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html"; + link=document.getElementById(routing_type + "_gpx_track"); + link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track"; + link=document.getElementById(routing_type + "_gpx_route"); + link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-route"; + link=document.getElementById(routing_type + "_text_all"); + link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text-all"; + link=document.getElementById(routing_type + "_text"); + link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text"; + + var div_links=document.getElementById(routing_type + "_links"); + div_links.style.display = ""; + + // Add a GPX layer + + var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track"; + + layerGPX[routing_type] = new OpenLayers.Layer.GML("GPX (" + routing_type + ")", url, + { + format: OpenLayers.Format.GPX, + style: gpx_style[routing_type], + projection: map.displayProjection + }); + + map.addLayer(layerGPX[routing_type]); + + hideshow_show(routing_type); + + displayResult(routing_type,uuid); +} + + +// +// Failure in running router. +// + +function runRouterFailure(response) +{ + displayStatus("result","failed"); +} + + +// +// Display the status +// + +function displayStatus(type,subtype,content) +{ + var div_status=document.getElementById(type + "_status"); + + var child=div_status.firstChild; + + do + { + if(child.id != undefined) + child.style.display="none"; + + child=child.nextSibling; + } + while(child != undefined); + + var span_status=document.getElementById(type + "_status_" + subtype); + + span_status.style.display=""; + + if(content != null) + span_status.innerHTML=content; +} + + +// +// Display the route +// + +function displayResult(type,uuid) +{ + routing_type = type; + + // Add the route + + var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html"; + + // Use AJAX to get the route + + OpenLayers.loadURL(url,null,null,getRouteSuccess,getRouteFailure); +} + + +// +// Success in getting route. +// + +function getRouteSuccess(response) +{ + var lines=response.responseText.split('\n'); + var div_route=document.getElementById(routing_type + "_route"); + + routepoints[routing_type]=[]; + + var points=routepoints[routing_type]; + + var table=0; + var point=0; + var total_table,total_word; + + for(var line=0;line')) + table=1; + else + continue; + } + + if(thisline.match('')) + break; + + if(thisline.match('')) + { + var rowtype=RegExp.$1; + + if(rowtype=='c') + { + thisline.match(' *([-0-9.]+) *([-0-9.]+)'); + points[point]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), html: "", highway: "", distance: "", total: ""}; + + point++; + } + else if(rowtype=='n') + { + points[point-1].html += thisline; + } + else if(rowtype=='s') + { + thisline.match('([^<]+)'); + points[point-1].highway = RegExp.$1; + + thisline.match('([^<]+)'); + points[point-1].distance = RegExp.$1; + + thisline.match('([^<]+)'); + points[point-1].total = RegExp.$1; + + thisline.match('^(.*).'); + + points[point-1].html += RegExp.$1; + } + else if(rowtype=='t') + { + points[point-1].html += thisline; + + thisline.match('^(.*)'); + total_table = RegExp.$1; + + thisline.match('([^<]+)<'); + total_word = RegExp.$1; + + thisline.match('([^<]+)'); + points[point-1].total = RegExp.$1; + } + } + } + + var result=""; + + for(var p=0;p" + + "" + + "
#" + (p+1) + + "" + points[p].highway; + } + + result=result + "
" + total_word + " " + points[p].total; + + result=result + "
"; + + div_route.innerHTML=result; +} + + +// +// Failure in getting route. +// + +function getRouteFailure(response) +{ + var div_route=document.getElementById(routing_type + "_route"); + div_route.innerHTML = ""; +} diff --git a/web/www/routino/router.pl b/web/www/routino/router.pl new file mode 100644 index 0000000..7f5dbd0 --- /dev/null +++ b/web/www/routino/router.pl @@ -0,0 +1,249 @@ +# +# Routino generic router Perl script +# +# Part of the Routino routing software. +# +# This file Copyright 2008-2010 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Use the directory paths script +require "paths.pl"; + +# Use the perl Time::HiRes module +use Time::HiRes qw(gettimeofday tv_interval); + +$t0 = [gettimeofday]; + +# Filename prefix + +$data_prefix=""; + +$routino={ # contains all default Routino options (generated using "--help-profile-pl"). + + # Default transport type + transport => 'motorcar', + + # Transport types + transports => {foot => 1, horse => 2, wheelchair => 3, bicycle => 4, moped => 5, motorbike => 6, motorcar => 7, goods => 8, hgv => 9, psv => 10}, + + # Highway types + highways => {motorway => 1, trunk => 2, primary => 3, secondary => 4, tertiary => 5, unclassified => 6, residential => 7, service => 8, track => 9, cycleway => 10, path => 11, steps => 12}, + + # Property types + properties => {paved => 1, multilane => 2, bridge => 3, tunnel => 4}, + + # Restriction types + restrictions => {oneway => 1, weight => 2, height => 3, width => 4, length => 5}, + + # Allowed highways + profile_highway => { + motorway => { foot => 0, horse => 0, wheelchair => 0, bicycle => 0, moped => 0, motorbike => 100, motorcar => 100, goods => 100, hgv => 100, psv => 100}, + trunk => { foot => 40, horse => 25, wheelchair => 40, bicycle => 30, moped => 90, motorbike => 100, motorcar => 100, goods => 100, hgv => 100, psv => 100}, + primary => { foot => 50, horse => 50, wheelchair => 50, bicycle => 70, moped => 100, motorbike => 90, motorcar => 90, goods => 90, hgv => 90, psv => 90}, + secondary => { foot => 60, horse => 50, wheelchair => 60, bicycle => 80, moped => 90, motorbike => 80, motorcar => 80, goods => 80, hgv => 80, psv => 80}, + tertiary => { foot => 70, horse => 75, wheelchair => 70, bicycle => 90, moped => 80, motorbike => 70, motorcar => 70, goods => 70, hgv => 70, psv => 70}, + unclassified => { foot => 80, horse => 75, wheelchair => 80, bicycle => 90, moped => 70, motorbike => 60, motorcar => 60, goods => 60, hgv => 60, psv => 60}, + residential => { foot => 90, horse => 75, wheelchair => 90, bicycle => 90, moped => 60, motorbike => 50, motorcar => 50, goods => 50, hgv => 50, psv => 50}, + service => { foot => 90, horse => 75, wheelchair => 90, bicycle => 90, moped => 80, motorbike => 80, motorcar => 80, goods => 80, hgv => 80, psv => 80}, + track => { foot => 95, horse => 100, wheelchair => 95, bicycle => 90, moped => 0, motorbike => 0, motorcar => 0, goods => 0, hgv => 0, psv => 0}, + cycleway => { foot => 95, horse => 90, wheelchair => 95, bicycle => 100, moped => 0, motorbike => 0, motorcar => 0, goods => 0, hgv => 0, psv => 0}, + path => { foot => 100, horse => 100, wheelchair => 100, bicycle => 90, moped => 0, motorbike => 0, motorcar => 0, goods => 0, hgv => 0, psv => 0}, + steps => { foot => 80, horse => 0, wheelchair => 0, bicycle => 0, moped => 0, motorbike => 0, motorcar => 0, goods => 0, hgv => 0, psv => 0} + }, + + # Speed limits + profile_speed => { + motorway => { foot => 0, horse => 0, wheelchair => 0, bicycle => 0, moped => 48, motorbike => 112, motorcar => 112, goods => 96, hgv => 89, psv => 89}, + trunk => { foot => 4, horse => 8, wheelchair => 4, bicycle => 20, moped => 48, motorbike => 96, motorcar => 96, goods => 96, hgv => 80, psv => 80}, + primary => { foot => 4, horse => 8, wheelchair => 4, bicycle => 20, moped => 48, motorbike => 96, motorcar => 96, goods => 96, hgv => 80, psv => 80}, + secondary => { foot => 4, horse => 8, wheelchair => 4, bicycle => 20, moped => 48, motorbike => 88, motorcar => 88, goods => 88, hgv => 80, psv => 80}, + tertiary => { foot => 4, horse => 8, wheelchair => 4, bicycle => 20, moped => 48, motorbike => 80, motorcar => 80, goods => 80, hgv => 80, psv => 80}, + unclassified => { foot => 4, horse => 8, wheelchair => 4, bicycle => 20, moped => 48, motorbike => 64, motorcar => 64, goods => 64, hgv => 64, psv => 64}, + residential => { foot => 4, horse => 8, wheelchair => 4, bicycle => 20, moped => 48, motorbike => 48, motorcar => 48, goods => 48, hgv => 48, psv => 48}, + service => { foot => 4, horse => 8, wheelchair => 4, bicycle => 20, moped => 32, motorbike => 32, motorcar => 32, goods => 32, hgv => 32, psv => 32}, + track => { foot => 4, horse => 8, wheelchair => 4, bicycle => 20, moped => 16, motorbike => 16, motorcar => 16, goods => 16, hgv => 16, psv => 16}, + cycleway => { foot => 4, horse => 8, wheelchair => 4, bicycle => 20, moped => 0, motorbike => 0, motorcar => 0, goods => 0, hgv => 0, psv => 0}, + path => { foot => 4, horse => 8, wheelchair => 4, bicycle => 20, moped => 0, motorbike => 0, motorcar => 0, goods => 0, hgv => 0, psv => 0}, + steps => { foot => 4, horse => 0, wheelchair => 4, bicycle => 0, moped => 0, motorbike => 0, motorcar => 0, goods => 0, hgv => 0, psv => 0} + }, + + # Highway properties + profile_property => { + paved => { foot => 50, horse => 20, wheelchair => 90, bicycle => 50, moped => 100, motorbike => 100, motorcar => 100, goods => 100, hgv => 100, psv => 100}, + multilane => { foot => 25, horse => 25, wheelchair => 25, bicycle => 25, moped => 25, motorbike => 75, motorcar => 75, goods => 75, hgv => 75, psv => 75}, + bridge => { foot => 50, horse => 50, wheelchair => 50, bicycle => 50, moped => 50, motorbike => 50, motorcar => 50, goods => 50, hgv => 50, psv => 50}, + tunnel => { foot => 50, horse => 50, wheelchair => 50, bicycle => 50, moped => 50, motorbike => 50, motorcar => 50, goods => 50, hgv => 50, psv => 50} + }, + + # Restrictions + profile_restrictions => { + oneway => { foot => 0, horse => 1, wheelchair => 0, bicycle => 1, moped => 1, motorbike => 1, motorcar => 1, goods => 1, hgv => 1, psv => 1}, + weight => { foot => 0.0, horse => 0.0, wheelchair => 0.0, bicycle => 0.0, moped => 0.0, motorbike => 0.0, motorcar => 0.0, goods => 5.0, hgv => 10.0, psv => 15.0}, + height => { foot => 0.0, horse => 0.0, wheelchair => 0.0, bicycle => 0.0, moped => 0.0, motorbike => 0.0, motorcar => 0.0, goods => 2.5, hgv => 3.0, psv => 3.0}, + width => { foot => 0.0, horse => 0.0, wheelchair => 0.0, bicycle => 0.0, moped => 0.0, motorbike => 0.0, motorcar => 0.0, goods => 2.0, hgv => 2.5, psv => 2.5}, + length => { foot => 0.0, horse => 0.0, wheelchair => 0.0, bicycle => 0.0, moped => 0.0, motorbike => 0.0, motorcar => 0.0, goods => 5.0, hgv => 6.0, psv => 6.0} + }, + +}; # end of routino variable + + +# +# Fill in the default parameters using the ones above (don't use executable compiled in defaults) +# + +sub FillInDefaults + { + my(%params)=@_; + + $params{transport}=$routino->{transport} if(!defined $params{transport}); + + my($transport)=$params{transport}; + + foreach $highway (keys %{$routino->{highways}}) + { + $key="highway-$highway"; + $value=$routino->{profile_highway}->{$highway}->{$transport}; + $params{$key}=$value if(!defined $params{$key}); + + $key="speed-$highway"; + $value=$routino->{profile_speed}->{$highway}->{$transport}; + $params{$key}=$value if(!defined $params{$key}); + } + + foreach $property (keys %{$routino->{properties}}) + { + $key="property-$property"; + $value=$routino->{profile_property}->{$property}->{$transport}; + $params{$key}=$value if(!defined $params{$key}); + } + + $params{oneway} =~ s/(true|on)/1/; + $params{oneway} =~ s/(false|off)/0/; + + foreach $restriction (keys %{$routino->{restrictions}}) + { + $key="$restriction"; + $value=$routino->{profile_restrictions}->{$restriction}->{$transport}; + $params{$key}=$value if(!defined $params{$key}); + } + + return %params; + } + + +# +# Run the router +# + +sub RunRouter + { + my($optimise,%params)=@_; + + # Combine all of the parameters together + + my($params)="--$optimise"; + + foreach $key (keys %params) + { + $params.=" --$key=$params{$key}"; + } + + # Change directory + + mkdir $results_dir,0755 if(! -d $results_dir); + chdir $results_dir; + + # Create a unique output directory + + chomp($uuid=`echo '$params' $$ | md5sum | cut -f1 '-d '`); + + mkdir $uuid; + chmod 0775, $uuid; + chdir $uuid; + + # Run the router + + $params.=" --dir=$data_dir" if($data_dir); + $params.=" --prefix=$data_prefix" if($data_prefix); + $params.=" --quiet"; + + $message=`$bin_dir/router $params 2>&1`; + + (undef,undef,$cuser,$csystem) = times; + $time=sprintf "time: %.3f CPU / %.3f elapsed",$cuser+$csystem,tv_interval($t0); + + if(-f "$optimise.txt") + { + $result=`tail -1 $optimise.txt`; + @result=split(/\t/,$result); + $result = $result[4]." , ".$result[5]; + } + + # Return the results + + return($uuid,$time,$result,$message); + } + + +# +# Return the output file +# + +# Possible file formats + +%suffixes=( + "html" => ".html", + "gpx-route" => "-route.gpx", + "gpx-track" => "-track.gpx", + "text" => ".txt", + "text-all" => "-all.txt" + ); + +# Possible MIME types + +%mimetypes=( + "html" => "text/html", + "gpx-route" => "text/xml", + "gpx-track" => "text/xml", + "text" => "text/plain", + "text-all" => "text/plain" + ); + +sub ReturnOutput + { + my($uuid,$type,$format)=@_; + + $suffix=$suffixes{$format}; + $mime =$mimetypes{$format}; + + $file="$results_dir/$uuid/$type$suffix"; + + # Return the output + + if(!$type || !$uuid || !$format || ! -f $file) + { + print header('text/plain','404 Not found'); + print "Not Found!\n"; + } + else + { + print header($mime); + + system "cat $file"; + } + } + +1; diff --git a/web/www/routino/statistics.cgi b/web/www/routino/statistics.cgi new file mode 100755 index 0000000..501097a --- /dev/null +++ b/web/www/routino/statistics.cgi @@ -0,0 +1,39 @@ +#!/usr/bin/perl +# +# Routino data statistics +# +# Part of the Routino routing software. +# +# This file Copyright 2008,2009 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Use the directory paths script +require "paths.pl"; + +# Use the perl CGI module +use CGI ':cgi'; + +# Print the output + +print header('text/plain'); + +# Run the filedumper + +$params.=" --dir=$data_dir" if($data_dir); +$params.=" --prefix=$data_prefix" if($data_prefix); +$params.=" --statistics"; + +system "$bin_dir/filedumper $params 2>&1"; diff --git a/web/www/routino/visualiser.cgi b/web/www/routino/visualiser.cgi new file mode 100755 index 0000000..d3b8f38 --- /dev/null +++ b/web/www/routino/visualiser.cgi @@ -0,0 +1,110 @@ +#!/usr/bin/perl +# +# Routino data visualiser CGI +# +# Part of the Routino routing software. +# +# This file Copyright 2008,2009 Andrew M. Bishop +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +# Use the directory paths script +require "paths.pl"; + +# Use the perl CGI module +use CGI ':cgi'; + +# Create the query and get the parameters + +$query=new CGI; + +@rawparams=$query->param; + +# Legal CGI parameters with regexp validity check + +%legalparams=( + "latmin" => "[-0-9.]+", + "latmax" => "[-0-9.]+", + "lonmin" => "[-0-9.]+", + "lonmax" => "[-0-9.]+", + "data" => "(junctions|super|oneway|speed|weight|height|width|length)" + ); + +# Validate the CGI parameters, ignore invalid ones + +foreach $key (@rawparams) + { + foreach $test (keys (%legalparams)) + { + if($key =~ m%^$test$%) + { + $value=$query->param($key); + + if($value =~ m%^$legalparams{$test}$%) + { + $cgiparams{$key}=$value; + last; + } + } + } + } + +# Parameters to limit range selected + +%limits=( + "junctions" => 0.1, + "speed" => 0.2, + "super" => 0.2, + "oneway" => 0.2, + "weight" => 0.3, + "height" => 0.3, + "width" => 0.3, + "length" => 0.3 + ); + +# Check the parameters + +$latmin=$cgiparams{"latmin"}; +$latmax=$cgiparams{"latmax"}; +$lonmin=$cgiparams{"lonmin"}; +$lonmax=$cgiparams{"lonmax"}; +$data =$cgiparams{"data"}; + +if($latmin eq "" || $latmax eq "" || $lonmin eq "" || $lonmax eq "" || $data eq "") + { + print header(-status => '500 Invalid CGI parameters'); + exit; + } + +if(($latmax-$latmin)>$limits{$data} || ($lonmax-$lonmin)>$limits{$data}) + { + print header(-status => '500 Selected area too large'); + exit; + } + +# Print the output + +print header('text/plain'); + +print "$latmin $lonmin $latmax $lonmax\n"; + +# Run the filedumper + +$params.=" --dir=$data_dir" if($data_dir); +$params.=" --prefix=$data_prefix" if($data_prefix); +$params.=" --visualiser --data=$data"; +$params.=" --latmin=$latmin --latmax=$latmax --lonmin=$lonmin --lonmax=$lonmax"; + +system "$bin_dir/filedumper $params 2>&1"; diff --git a/web/www/routino/visualiser.css b/web/www/routino/visualiser.css new file mode 100644 index 0000000..561544e --- /dev/null +++ b/web/www/routino/visualiser.css @@ -0,0 +1,49 @@ +/* +// Routino visualiser web page style sheet. +// +// Part of the Routino routing software. +// +// This file Copyright 2008-2010 Andrew M. Bishop +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +*/ + + +/*--------------------------------*/ +/* Left panel - override defaults */ +/*--------------------------------*/ + +DIV.hideshow_box +{ + overflow-x: auto; +} + + +/*-----------------------------------*/ +/* Left panel - specific tab options */ +/*-----------------------------------*/ + +DIV#tab_visualiser_div INPUT +{ + padding: 0; + border: 1px solid; + margin: 0; + + text-align: center; +} + +DIV#tab_visualiser_div INPUT:hover +{ + background: #F0F0C0; +} diff --git a/web/www/routino/visualiser.html b/web/www/routino/visualiser.html new file mode 100644 index 0000000..c79bea9 --- /dev/null +++ b/web/www/routino/visualiser.html @@ -0,0 +1,258 @@ + + + + + + +Routino : Data Visualiser for Routino OpenStreetMap Data + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ Visualiser + Router + Data +
+ +
+ +
+ Routino Data Visualiser + This web page allows visualisation of the data that Routino uses for routing. + Only data relevant for routing is displayed and some will therefore be excluded + (e.g. private roads). + +
+ +
+ Instructions + Zoom in and then use the buttons below to download the data. The + server will only return data if the selected area is small enough. +
+ +
+ Status +
+ No data displayed +
+
+ +
+ Show + Hide + + +
+ +
+ Show + Hide + + +
+ +
+ Show + Hide + + +
+ +
+ Show + Hide + + +
+ +
+ Show + Hide + + +
+ +
+ Show + Hide + + +
+ +
+ Show + Hide + + +
+ +
+ Show + Hide + + +
+ +
+ +
+ + +
+ + + + + +
+ + + +
+
+ +
+ +
+ + + diff --git a/web/www/routino/visualiser.js b/web/www/routino/visualiser.js new file mode 100644 index 0000000..1444c89 --- /dev/null +++ b/web/www/routino/visualiser.js @@ -0,0 +1,618 @@ +// +// Routino data visualiser web page Javascript +// +// Part of the Routino routing software. +// +// This file Copyright 2008-2010 Andrew M. Bishop +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// + + +// +// Data types +// + +var data_types=[ + "junctions", + "super", + "oneway", + "speed", + "weight", + "height", + "width", + "length" + ]; + + +// +// Junction styles +// + +var junction_colours={ + 0: "#FFFFFF", + 1: "#FF0000", + 2: "#FFFF00", + 3: "#00FF00", + 4: "#8B4513", + 5: "#00BFFF", + 6: "#FF69B4", + 7: "#000000", + 8: "#000000", + 9: "#000000" + }; + +var junction_styles={}; + + +// +// Super styles +// + +var super_node_style,super_segment_style; + + +// +// Oneway styles +// + +var hex={0: "00", 1: "11", 2: "22", 3: "33", 4: "44", 5: "55", 6: "66", 7: "77", + 8: "88", 9: "99", 10: "AA", 11: "BB", 12: "CC", 13: "DD", 14: "EE", 15: "FF"}; + + +//////////////////////////////////////////////////////////////////////////////// +///////////////////////////////// Map handling ///////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +var map; +var layerMapOSM, layerVectors, layerBoxes; +var epsg4326, epsg900913; +var map_args; + +var box; + +// +// Initialise the 'map' object +// + +function map_init(lat,lon,zoom) +{ + // Default configuration: + // UK coordinate range + // West -11.0, South 49.5, East 2.0, North 61.0 + // Zoom level 4 to 15 + + // EDIT THIS below to change the visible map limits + + var westedge = -11.0; // Minimum longitude (degrees) + var eastedge = 2.0; // Maximum longitude (degrees) + var southedge = 49.5; // Minimum latitude (degrees) + var northedge = 61.0; // Maximum latitude (degrees) + var zoomout = 4; // Minimum zoom + var zoomin = 15; // Maximum zoom + + // EDIT THIS above to change the visible map limits + + // + // Create the map + // + + epsg4326=new OpenLayers.Projection("EPSG:4326"); + epsg900913=new OpenLayers.Projection("EPSG:900913"); + + map = new OpenLayers.Map ("map", + { + controls:[ + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.PanZoomBar(), + new OpenLayers.Control.ScaleLine(), + new OpenLayers.Control.LayerSwitcher() + ], + + projection: epsg900913, + displayProjection: epsg4326, + + minZoomLevel: zoomout, + numZoomLevels: zoomin-zoomout+1, + maxResolution: 156543.0339 / Math.pow(2,zoomout), + + maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34), + restrictedExtent: new OpenLayers.Bounds(westedge,southedge,eastedge,northedge).transform(epsg4326,epsg900913), + + units: "m" + }); + + map.events.register("moveend", map, mapMoved); + + // Add a map tile layer (OpenStreetMap tiles, direct access) + + layerMapOSM = new OpenLayers.Layer.TMS("Original OSM map", + "http://tile.openstreetmap.org/", + { + emptyUrl: "http://openstreetmap.org/openlayers/img/404.png", + type: 'png', + getURL: limitedUrl, + displayOutsideMaxExtent: true, + buffer: 1 + }); + map.addLayer(layerMapOSM); + + // Get a URL for the tile; limited to map restricted extent. + + function limitedUrl(bounds) + { + var z = map.getZoom() + map.minZoomLevel; + + if (z>=7 && (bounds.right < map.restrictedExtent.left || + bounds.left > map.restrictedExtent.right || + bounds.top < map.restrictedExtent.bottom || + bounds.bottom > map.restrictedExtent.top)) + return this.emptyUrl; + + var res = map.getResolution(); + var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h)); + var limit = Math.pow(2, z); + + if (y < 0 || y >= limit) + return this.emptyUrl; + + var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w)); + + x = ((x % limit) + limit) % limit; + return this.url + z + "/" + x + "/" + y + "." + this.type; + } + + // Add a vectors layer + + layerVectors = new OpenLayers.Layer.Vector("Markers"); + map.addLayer(layerVectors); + + for(var colour in junction_colours) + junction_styles[colour]=new OpenLayers.Style({},{stroke: false, pointRadius: 2,fillColor: junction_colours[colour]}); + + super_node_style =new OpenLayers.Style({},{stroke: false, pointRadius: 3,fillColor : "#FF0000"}); + super_segment_style=new OpenLayers.Style({},{fill: false , strokeWidth: 2,strokeColor: "#FF0000"}); + + // Add a boxes layer + + layerBoxes = new OpenLayers.Layer.Boxes("Boundary"); + map.addLayer(layerBoxes); + + box=null; + + // Set the map centre to the limited range specified + + map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,true)); + map.maxResolution = map.getResolution(); + + // Move the map + + if(lon != 'lon' && lat != 'lat' && zoom != 'zoom') + { + var lonlat = new OpenLayers.LonLat(lon,lat).transform(epsg4326,map.getProjectionObject()); + + map.moveTo(lonlat,zoom-map.minZoomLevel); + } +} + + +// +// Map has moved +// + +function mapMoved() +{ + var centre = map.getCenter().clone(); + + var lonlat = centre.transform(map.getProjectionObject(),epsg4326); + + var zoom = this.getZoom() + map.minZoomLevel; + + map_args="lat=" + lonlat.lat + ";lon=" + lonlat.lon + ";zoom=" + zoom; + + updateCustomURL(); +} + + +// +// Update custom URL +// + +function updateCustomURL() +{ + var router_url=document.getElementById("router_url"); + var link_url =document.getElementById("link_url"); + var edit_url =document.getElementById("edit_url"); + + router_url.href="customrouter.cgi?" + map_args; + link_url.href="customvisualiser.cgi?" + map_args; + edit_url.href="http://www.openstreetmap.org/edit?" + map_args; +} + + +//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////// Server handling //////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// +// Display data statistics +// + +function displayStatistics() +{ + // Use AJAX to get the statistics + + OpenLayers.loadURL("statistics.cgi",null,null,runStatisticsSuccess); +} + + +// +// Success in running data statistics generation. +// + +function runStatisticsSuccess(response) +{ + var statistics_data=document.getElementById("statistics_data"); + var statistics_link=document.getElementById("statistics_link"); + + statistics_data.innerHTML="
" + response.responseText + "
"; + + statistics_link.style.display="none"; +} + + +// +// Get the requested data +// + +function displayData(datatype) +{ + for(var data in data_types) + hideshow_hide(data_types[data]); + + if(datatype != "") + hideshow_show(datatype); + + // Delete the old data + + layerVectors.destroyFeatures(); + + if(box != null) + layerBoxes.removeMarker(box); + box=null; + + // Print the status + + var div_status=document.getElementById("result_status"); + div_status.innerHTML = "No data displayed"; + + // Return if just here to clear the data + + if(datatype == "") + return; + + // Get the new data + + var mapbounds=map.getExtent().clone(); + mapbounds.transform(epsg900913,epsg4326); + + var url="visualiser.cgi"; + + url=url + "?lonmin=" + mapbounds.left; + url=url + ";latmin=" + mapbounds.bottom; + url=url + ";lonmax=" + mapbounds.right; + url=url + ";latmax=" + mapbounds.top; + url=url + ";data=" + datatype; + + // Print the status + + div_status.innerHTML = "Fetching " + datatype + " data ..."; + + // Use AJAX to get the data + + switch(datatype) + { + case 'junctions': + OpenLayers.loadURL(url,null,null,runJunctionsSuccess,runFailure); + break; + case 'super': + OpenLayers.loadURL(url,null,null,runSuperSuccess,runFailure); + break; + case 'oneway': + OpenLayers.loadURL(url,null,null,runOnewaySuccess,runFailure); + break; + case 'speed': + case 'weight': + case 'height': + case 'width': + case 'length': + OpenLayers.loadURL(url,null,null,runLimitSuccess,runFailure); + break; + } +} + + +// +// Success in getting the junctions. +// + +function runJunctionsSuccess(response) +{ + var lines=response.responseText.split('\n'); + +// This won't update the browser window +// var div_status=document.getElementById("result_status"); +// div_status.innerHTML = "Processing " + (lines.length-2) + " junctions ..."; + + var features=[]; + + for(var line=0;line. +# + +WEBDIR=../web/data + +FILES=profiles.xml \ + translations.xml \ + tagging.xml + +######## + +all : + -@[ -d $(WEBDIR) ] && \ + for file in $(FILES); do \ + if [ ! -f $(WEBDIR)/$$file ] || [ routino-$$file -nt $(WEBDIR)/$$file ]; then \ + echo cp routino-$$file $(WEBDIR)/$$file ;\ + cp -f routino-$$file $(WEBDIR)/$$file ;\ + fi ;\ + done + +######## + +clean: + rm -f *~ + +######## + +distclean: clean + rm -f $(WEBDIR)/*.xml diff --git a/xml/osm.xsd b/xml/osm.xsd new file mode 100644 index 0000000..1b657a9 --- /dev/null +++ b/xml/osm.xsd @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/routino-osm.xsd b/xml/routino-osm.xsd new file mode 100644 index 0000000..092990a --- /dev/null +++ b/xml/routino-osm.xsd @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/routino-profiles.xml b/xml/routino-profiles.xml new file mode 100644 index 0000000..ba3fa51 --- /dev/null +++ b/xml/routino-profiles.xml @@ -0,0 +1,461 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/routino-profiles.xsd b/xml/routino-profiles.xsd new file mode 100644 index 0000000..7c13e94 --- /dev/null +++ b/xml/routino-profiles.xsd @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/routino-tagging-nomodify.xml b/xml/routino-tagging-nomodify.xml new file mode 100644 index 0000000..0674870 --- /dev/null +++ b/xml/routino-tagging-nomodify.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/routino-tagging.xml b/xml/routino-tagging.xml new file mode 100644 index 0000000..0bec4dc --- /dev/null +++ b/xml/routino-tagging.xml @@ -0,0 +1,435 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/routino-tagging.xsd b/xml/routino-tagging.xsd new file mode 100644 index 0000000..7df6dae --- /dev/null +++ b/xml/routino-tagging.xsd @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/routino-translations.xml b/xml/routino-translations.xml new file mode 100644 index 0000000..470563d --- /dev/null +++ b/xml/routino-translations.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <!-- %s = [shortest|quickest] --> + + <start string="Start" text="At %s, head %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] --> + <node string="At" text="%s, go %s heading %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] --> + <segment string="Follow" text="%s for %.3f km, %.1f min" /> <!-- 1st %s = street name --> + <stop string="Stop" text="At %s" /> <!-- 1st %s = [waypoint|junction] --> + <total string="Total" text="%.1f km, %.0f minutes" /> + </output-html> + + <!-- GPX output --> + <output-gpx> + <waypoint type="start" string="START" /> <!-- For the first route waypoint --> + <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints --> + <waypoint type="trip" string="TRIP" /> <!-- For the other route points --> + <waypoint type="finish" string="FINISH"/> <!-- For the last route waypoint --> + + <desc text="%s route between 'start' and 'finish' waypoints" /> <!-- %s = [shortest|quickest] --> + <name text="%s route" /> <!-- %s = [shortest|quickest] --> + <step text="%s on '%s' for %.3f km, %.1f min" /> <!-- 1st %s = [turn], 2nd %s = street name --> + <final text="Total Journey %.1f km, %.0f minutes" /> + </output-gpx> + + </language> + + <language lang="de"> + + <!-- Copyright of the data being routed, not of this file --> + <copyright> + <creator string="Creator" text="Routino - http://www.routino.org/" /> + <source string="Source" text="Basierend auf OpenStreetMap-Daten, erhältlich via http://www.openstreetmap.org/" /> + <license string="License" text="http://creativecommons.org/licenses/by-sa/2.0/" /> + </copyright> + + <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right --> + <turn direction="-4" string="Spitzkehre nach links" /> + <turn direction="-3" string="Scharf links" /> + <turn direction="-2" string="Links" /> + <turn direction="-1" string="Halb links" /> + <turn direction="0" string="Geradeaus" /> + <turn direction="1" string="Halb rechts" /> + <turn direction="2" string="Rechts" /> + <turn direction="3" string="Scharf rechts" /> + <turn direction="4" string="Spitzkehre nach rechts" /> + + <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East --> + <heading direction="-4" string="Süd" /> + <heading direction="-3" string="Süd-West" /> + <heading direction="-2" string="West" /> + <heading direction="-1" string="Nord-West" /> + <heading direction="0" string="Nord" /> + <heading direction="1" string="Nord-Ost" /> + <heading direction="2" string="Ost" /> + <heading direction="3" string="Süd-Ost" /> + <heading direction="4" string="Süd" /> + + <!-- Highway names --> + <highway type="motorway" string="Autobahn" /> + <highway type="trunk" string="Schnellstraße" /> + <highway type="primary" string="Bundesstraße" /> + <highway type="secondary" string="Landstraße" /> + <highway type="tertiary" string="Kreisstraße" /> + <highway type="unclassified" string="Nebenstraße" /> + <highway type="residential" string="Wohngebietsstraße" /> + <highway type="service" string="Erschließungsweg" /> + <highway type="track" string="Wirtschaftsweg" /> + <highway type="cycleway" string="Radweg" /> + <highway type="path" string="Weg" /> + <highway type="steps" string="Treppe" /> + + <!-- The type of route --> + <route type="shortest" string="Kürzeste" /> <!-- For the description and route name --> + <route type="quickest" string="Schnellste" /> <!-- For the description and route name --> + + <!-- HTML output --> + <output-html> + <waypoint type="waypoint" string="Wegpunkt" /> <!-- For the chosen waypoints --> + <waypoint type="junction" string="Anschlussstelle" /> <!-- For the interesting junctions --> + + <title text="%s Route" /> <!-- %s = [shortest|quickest] --> + + <start string="Start" text="Bei %s halten Sie sich Richtung %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] --> + <node string="Bei" text="Bei %s wenden Sie sich nach %s Richtung %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] --> + <segment string="Folgen" text="Folgen Sie der %s für %.3f km bzw. %.1f min" /> <!-- 1st %s = street name --> + <stop string="Stop" text="Sie sind bei %s angekommen" /> <!-- 1st %s = [waypoint|junction] --> + <total string="Gesamt" text="%.1f km, %.0f minuten" /> + </output-html> + + <!-- GPX output --> + <output-gpx> + <waypoint type="start" string="START" /> <!-- For the first route waypoint --> + <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints --> + <waypoint type="trip" string="TRIP" /> <!-- For the other route points --> + <waypoint type="finish" string="FINISH"/> <!-- For the last route waypoint --> + + <desc text="%s Strecke zwischen 'Start' und 'Ziel'" /> <!-- %s = [shortest|quickest] --> + <name text="%s Strecke" /> <!-- %s = [shortest|quickest] --> + <step text="%s auf '%s' für %.3f km, %.1f min" /> <!-- 1st %s = [turn], 2nd %s = street name --> + <final text="Gesamtstrecke %.1f km, %.0f minuten" /> + </output-gpx> + + </language> + +</routino-translations> diff --git a/xml/routino-translations.xsd b/xml/routino-translations.xsd new file mode 100644 index 0000000..75fbfab --- /dev/null +++ b/xml/routino-translations.xsd @@ -0,0 +1,171 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- ============================================================ + $Header: /home/amb/routino/xml/RCS/routino-translations.xsd,v 1.3 2010/05/29 13:54:43 amb Exp $ + + An XML Schema Definition for the Routino translations XML format + + Part of the Routino routing software. + ============================================================ + This file Copyright 2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + ============================================================ --> + +<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <!-- The top level Routino translation --> + + <xsd:element name="routino-translations" type="RoutinoTranslationsType"/> + + <xsd:complexType name="RoutinoTranslationsType"> + <xsd:sequence> + <xsd:element name="language" type="languageType" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="languageType"> + <xsd:sequence> + <xsd:element name="copyright" type="CopyrightType" minOccurs="0"/> + <xsd:element name="turn" type="TurnType" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="heading" type="HeadingType" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="highway" type="HighwayType" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="route" type="RouteType" minOccurs="0" maxOccurs="2"/> + <xsd:element name="output-html" type="HTMLType" minOccurs="0"/> + <xsd:element name="output-gpx" type="GPXType" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="lang" type="xsd:string"/> + </xsd:complexType> + + <!-- The copyright information (of the generated output, not of this file) --> + + <xsd:complexType name="CopyrightType"> + <xsd:sequence> + <xsd:element name="creator" type="CopyrightCreatorType" minOccurs="0"/> + <xsd:element name="source" type="CopyrightSourceType" minOccurs="0"/> + <xsd:element name="license" type="CopyrightLicenseType" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CopyrightCreatorType"> + <xsd:attribute name="string" type="xsd:string"/> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="CopyrightSourceType"> + <xsd:attribute name="string" type="xsd:string"/> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="CopyrightLicenseType"> + <xsd:attribute name="string" type="xsd:string"/> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <!-- The turn, heading, highway and route strings --> + + <xsd:complexType name="TurnType"> + <xsd:attribute name="direction" type="xsd:string"/> + <xsd:attribute name="string" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="HeadingType"> + <xsd:attribute name="direction" type="xsd:string"/> + <xsd:attribute name="string" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="HighwayType"> + <xsd:attribute name="type" type="xsd:string"/> + <xsd:attribute name="string" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="RouteType"> + <xsd:attribute name="type" type="xsd:string"/> + <xsd:attribute name="string" type="xsd:string"/> + </xsd:complexType> + + <!-- The HTML output strings --> + + <xsd:complexType name="HTMLType"> + <xsd:sequence> + <xsd:element name="waypoint" type="HTMLWaypointType" maxOccurs="2"/> + <xsd:element name="title" type="HTMLTitleType"/> + <xsd:element name="start" type="HTMLStartType"/> + <xsd:element name="node" type="HTMLNodeType"/> + <xsd:element name="segment" type="HTMLSegmentType"/> + <xsd:element name="stop" type="HTMLStopType"/> + <xsd:element name="total" type="HTMLTotalType"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="HTMLWaypointType"> + <xsd:attribute name="type" type="xsd:string"/> + <xsd:attribute name="string" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="HTMLTitleType"> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="HTMLStartType"> + <xsd:attribute name="string" type="xsd:string"/> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="HTMLNodeType"> + <xsd:attribute name="string" type="xsd:string"/> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="HTMLSegmentType"> + <xsd:attribute name="string" type="xsd:string"/> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="HTMLStopType"> + <xsd:attribute name="string" type="xsd:string"/> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="HTMLTotalType"> + <xsd:attribute name="string" type="xsd:string"/> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <!-- The GPX output strings --> + + <xsd:complexType name="GPXType"> + <xsd:sequence> + <xsd:element name="waypoint" type="GPXWaypointType" maxOccurs="4"/> + <xsd:element name="desc" type="GPXDescType"/> + <xsd:element name="name" type="GPXNameType"/> + <xsd:element name="step" type="GPXStepType"/> + <xsd:element name="final" type="GPXFinalType"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="GPXWaypointType"> + <xsd:attribute name="type" type="xsd:string"/> + <xsd:attribute name="string" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="GPXDescType"> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="GPXNameType"> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="GPXStepType"> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="GPXFinalType"> + <xsd:attribute name="text" type="xsd:string"/> + </xsd:complexType> + +</xsd:schema> diff --git a/xml/xsd.xsd b/xml/xsd.xsd new file mode 100644 index 0000000..3208cd3 --- /dev/null +++ b/xml/xsd.xsd @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8" ?> + +<!-- ============================================================ + $Header: /home/amb/routino/xml/RCS/xsd.xsd,v 1.1 2010/03/28 15:27:05 amb Exp $ + + An XML Schema Definition for the XML Schema Definition XML format + + Not a full definition but sufficient to allow the xsd-to-xmlparser to + read it to bootstrap itself - a program to read in other files in the + same format to create more XML parsers for other useful things. + ============================================================ + This file Copyright 2010 Andrew M. Bishop + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + ============================================================ --> + +<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <!-- The top level xsd:schema element --> + + <xsd:element name="xsd:schema" type="schemaType"/> + + <xsd:complexType name="schemaType"> + <xsd:sequence> + <xsd:element name="xsd:element" type="elementType"/> + <xsd:element name="xsd:complexType" type="complexType" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="elementFormDefault" type="xsd:string"/> + <xsd:attribute name="xmlns:xsd" type="xsd:string"/> + </xsd:complexType> + + <!-- The second level xsd:element and xsd:complexType elements --> + + <xsd:complexType name="elementType"> + <xsd:attribute name="name" type="xsd:string"/> + <xsd:attribute name="type" type="xsd:string"/> + <xsd:attribute name="minOccurs" type="xsd:string"/> + <xsd:attribute name="maxOccurs" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="complexType"> + <xsd:sequence> + <xsd:element name="xsd:sequence" type="sequenceType" minOccurs="0"/> + <xsd:element name="xsd:attribute" type="attributeType" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string"/> + </xsd:complexType> + + <!-- The third level elements and their contents --> + + <xsd:complexType name="sequenceType"> + <xsd:sequence> + <xsd:element name="xsd:element" type="elementType" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="attributeType"> + <xsd:attribute name="name" type="xsd:string"/> + <xsd:attribute name="type" type="xsd:string"/> + </xsd:complexType> + +</xsd:schema>