--- /dev/null
+2010-07-10 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ Version 1.4.1 released
+
+2010-07-10 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/Makefile:
+ Default compilation flags include optimisation and not debugging symbols.
+
+2010-07-08 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/superx.c: Change the algorithm used to determine supernodes.
+
+2010-07-03 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/router.c: Don't crash if start and finish are the same point.
+
+2010-06-27 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ Version 1.4 released
+
+2010-05-31 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/router.c: Make sure that some profiles are loaded.
+
+2010-05-27 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/xmlparse.l: Fix bug with encoding XML strings.
+
+2010-05-23 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/functionsx.h, src/osmparser.c, src/planetsplitter.c, src/ways.h, src/waysx.c,
+ src/waysx.h:
+ Remove the --transport=<transport>, --not-highway=<highway> and
+ --not-property=<property> options from planetsplitter because they can be done
+ by the tagging.xml file now.
+
+2010-05-18 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * xml/Makefile: New file.
+
+2010-04-06 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/functionsx.h, src/osmparser.c, src/planetsplitter.c:
+ Rename the old ParseXML() function as ParseOSM().
+
+2010-04-01 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/output.c: Wrap GPX descriptions in CDATA.
+
+2010-03-31 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/output.c: Re-order the code for HTML.
+
+2010-03-15 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/output.c: Create a simple HTML output.
+
+2010-03-06 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/router.c, src/nodes.c:
+ Speed up start/via/stop point search algorithm.
+
+2010-03-05 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/profiles.c:
+ Change the format of the output for the --help-profile-{pl|js} options.
+
+2010-01-21 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ Version 1.3 released
+
+2010-01-21 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * doc/NEWS.txt: Update to latest news.
+
+2010-01-18 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * doc/USAGE.txt, doc/TAGGING.txt, doc/INSTALL.txt:
+ Updated documentation.
+
+2010-01-15 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/output.c:
+ Change the test output formats to add turn, node type and bearing information.
+
+2009-12-16 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/router.c:
+ Added an option to use only nodes and not interpolate a point into a segment.
+
+2009-12-15 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/osmparser.c, src/profiles.c, src/types.h, src/ways.c:
+ Added wheelchair as type of transport.
+
+2009-12-13 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/waysx.c:
+ Write out the list of ways without memory mapping anything.
+
+2009-11-27 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/optimiser.c, src/router.c:
+ Made the verbose output consistent between different places.
+
+2009-11-18 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/router.c: Fix bug with previous segment-splitting routing.
+
+2009-11-14 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/filedumper.c:
+ Check the values for the --node=, --segment= and --way= options.
+
+2009-11-03 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/output.c:
+ Fix bug in code that determines waypoints for abbreviated output.
+
+2009-10-24 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ Version 1.2 released
+
+2009-10-21 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * doc/README.txt, doc/USAGE.txt, doc/NEWS.txt: Updated for version 1.2.
+
+2009-10-20 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/Makefile: Add sorting.o to the Makefile.
+
+2009-10-12 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/queue.c: Add comments describing the algorithm used.
+
+2009-09-23 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/nodesx.c, src/waysx.c:
+ Simplify the de-duplication when sorting and update some comments.
+
+2009-09-22 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/osmparser.c: Fix bug with memory allocation.
+
+2009-08-19 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/router.c:
+ Increase to 99 the number of waypoints that can be specified.
+
+2009-08-15 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/superx.c: Ensure that variable is reset before using it.
+
+2009-07-06 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/filedumper.c, src/nodes.h:
+ Allow dumping out of nodes, segments and ways.
+
+2009-06-15 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ Version 1.1 released
+
+2009-06-13 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/filedumper.c: Change help text.
+
+ * src/visualiser.c:
+ Change format of super-node/segment visualiser output.
+
+2009-06-07 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/osmparser.c:
+ Improve parsing of imperial units (mph, feet & inches).
+
+2009-06-03 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/nodesx.c:
+ Print an error message and exit if a node cannot be found.
+
+2009-05-31 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/profiles.c:
+ Change the default profile; horses are slower, bicycles may be allowed on
+ footways (and similar).
+
+2009-05-15 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/output.c:
+ Add better junction detection for deciding on route waypoints.
+
+2009-05-06 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/osmparser.c:
+ Fix for parsing nodes from XML (no effect on results).
+
+2009-04-12 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ Version 1.0 released
+
+2009-04-08 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/planetsplitter.c: Remove the --help-profile command line option.
+
+2009-03-28 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/optimiser.c:
+ Fix file headers (again) and fix segment distance/duration for abbreviated text
+ output.
+
+2009-03-24 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/nodes.c: Fix bug with finding nearest node.
+
+2009-03-03 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * src/superx.c: Fix the merging of super-segments.
+
+2009-03-01 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * src/profiles.c, src/profiles.h, src/router.c:
+ Print out Javascript code containing the profiles.
+
+2009-02-24 Andrew M. Bishop <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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 <amb@gedanken.demon.co.uk>
+
+ * 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.
+
--- /dev/null
+doc/INSTALL.txt
\ No newline at end of file
--- /dev/null
+# $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 <http://www.gnu.org/licenses/>.
+#
+
+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
--- /dev/null
+doc/NEWS.txt
\ No newline at end of file
--- /dev/null
+doc/README.txt
\ No newline at end of file
--- /dev/null
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+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
+<http://www.gnu.org/licenses/>.
--- /dev/null
+ 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.
--- /dev/null
+ 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.
+
+<?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>
+
+
+--------
+
+Copyright 2010 Andrew M. Bishop.
--- /dev/null
+ 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.
--- /dev/null
+ 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.
--- /dev/null
+# $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 <http://www.gnu.org/licenses/>.
+#
+
+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)/*
--- /dev/null
+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.
--- /dev/null
+ 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):
+
+<!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:
+
+ 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.
--- /dev/null
+ 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.
--- /dev/null
+ 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.
--- /dev/null
+ 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=<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:
+
+ 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=<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.
+
+
+--------
+
+Copyright 2008-2010 Andrew M. Bishop.
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino documentation - algorithm
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Algorithm</TITLE>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Algorithm</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2><a name="H_1_1"></a>Algorithms</h2>
+
+This page describes the development of the algorithm that is used in Routino for
+finding routes.
+
+<h3><a name="H_1_1_1"></a>Simplest Algorithm</h3>
+
+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.
+<p>
+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.
+
+<h3><a name="H_1_1_2"></a>Improved Algorithm</h3>
+
+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.
+<br>
+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.
+<br>
+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.
+<p>
+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).
+<p>
+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.
+
+<h3><a name="H_1_1_3"></a>Final Algorithm</h3>
+
+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.
+<p>
+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 <em>super-nodes</em>. Starting at each
+super-node a <em>super-segment</em> is generated that finishes on another
+super-node and contains the <em>shortest</em> 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.
+<p>
+<img alt="Original data" src="example0.png"><br>
+<img alt="Iteration 1" src="example1.png"><br>
+<img alt="Iteration 2" src="example2.png"><br>
+<p>
+To find a route between a start and finish point now comprises the following
+steps (assuming a shortest route is required):
+<ol>
+ <li>Find all shortest routes from the start point along normal segments and
+ stopping when super-nodes are reached.
+ <li>Find all shortest routes from the end point backwards along normal
+ segments and stopping when super-nodes are reached.
+ <li>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).
+ <li>For each super-segment in step 3 find the shortest route between the two
+ end-point super-nodes.
+</ol>
+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.
+
+<h3><a name="H_1_1_4"></a>Routing Preferences</h3>
+
+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.
+<p>
+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.
+<dl>
+ <dt>Segment length
+ <dd>When calculating the shortest route the length of the segment is the
+ starting point for the score.
+ <dt>Speed preference
+ <dd>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.
+ <dt>Oneway restriction
+ <dd>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.
+ <dt>Weight, height, width & length limits
+ <dd>If a highway has one of these limits and its value is less than the user's
+ specified requirement then the segment is ignored.
+ <dt>Highway preference
+ <dd>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.
+ <dt>Highway properties
+ <dd>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.
+</dl>
+
+<h3><a name="H_1_1_5"></a>Implementation</h3>
+
+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.
+<p>
+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.
+<p>
+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.
+<br>
+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.
+<br>
+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.
+<p>
+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.
+
+<h3><a name="H_1_1_6"></a>Practicalities</h3>
+
+At the time of writing (April 2010) the OpenStreetMap data for Great Britain
+(taken from
+<a class="ext" href="http://download.geofabrik.de/osm/europe/" title="GeoFabrik Mirror of OpenStreetMap Data">GeoFabrik</a>
+) contains:
+<ul>
+ <li>14,675,098 nodes
+ <ul>
+ <li>8,767,521 are highway nodes
+ <li>1,120,297 are super-nodes
+ </ul>
+ <li>1,876,822 ways
+ <ul>
+ <li>1,412,898 are highways
+ <ul>
+ <li>9,316,328 highway segments
+ <li>1,641,009 are super-segments
+ </ul>
+ </ul>
+ <li>60,572 relations
+</ul>
+
+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).
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino documentation - configuration
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Configuration</TITLE>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Configuration</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2><a name="H_1_1"></a>XML Configuration Files</h2>
+
+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:
+<ul>
+ <li>Tagging transformation rules for the <em>planetsplitter</em> program.
+ <li>Routing profiles for the <em>router</em> program.
+ <li>Output translations for the <em>router</em> program.
+</ul>
+
+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.
+
+<h3><a name="H_1_1_1" title="Tagging rules"></a>Tag Transformation Rules</h3>
+
+The default name of the tagging transformation rules XML configuration file
+is <em>tagging.xml</em> in the same directory as the generated database files.
+Other filenames can be specified on the command line using
+the <tt>--tagging</tt> 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.
+
+<p>
+
+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.
+
+<pre class="boxed">
+<?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>
+</pre>
+
+The rules all have the same format; an <em>if</em> element for matching the
+input and some <em>set</em> or <em>output</em> elements to either change the
+input tags or create an output tag. The <em>k</em> and <em>v</em> attributes
+have the same meaning as the attributes with the same names in the OSM XML file
+- the tag key and tag value.
+
+<p>
+
+An <em>if</em> rule that has both <em>k</em> and <em>v</em> specified is only
+applied if a tag exists in the input that matches both. An <em>if</em> rule
+that has only the <em>k</em> attribute is applied if a tag with that key exists
+and an <em>if</em> rule that has only the <em>v</em> attribute is applied to all
+tags with that value.
+
+<p>
+
+For the <em>set</em> and <em>output</em> elements the tag that is created in the
+input or output tag set uses the <em>k</em> and <em>v</em> attributes specified.
+If one or both are not specified then the original ones are used.
+
+
+<h3><a name="H_1_1_2" title="Profiles"></a>Routing Profiles</h3>
+
+The default name of the routing profiles XML configuration file
+is <em>profiles.xml</em> in the same directory as the database files. Other
+filenames can be specified on the command line using the <tt>--tagging</tt>
+option.
+
+<p>
+
+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 <tt>--profile</tt> option selects the named profile from the configuration
+file.
+
+<p>
+
+Part of the provided profiles.xml file showing the parameters for transport on
+foot is shown below:
+
+<pre class="boxed">
+<?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>
+</pre>
+
+
+<h3><a name="H_1_1_3" title="Translations"></a>Output Translations</h3>
+
+The default name of the output translations XML configuration file
+is <em>translations.xml</em> in the same directory as the database files. Other
+filenames can be specified on the command line using the <tt>--translations</tt>
+option.
+
+<p>
+
+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 <tt>--language</tt> option to the router. If no language is specified the
+first one in the file is used.
+
+<p>
+
+Part of the provided translations.xml file showing some of the English language
+(en) translations is shown below:
+
+<pre class="boxed">
+<?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>
+</pre>
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino documentation - data
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Data</TITLE>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Data</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2><a name="H_1_1"></a>Data</h2>
+
+A router relies on data to be able to find a route.
+
+<h3><a name="H_1_1_1"></a>OpenStreetMap Data</h3>
+
+The data that is collected by the OpenStreetMap project consists of
+<em>nodes</em>, <em>ways</em> and <em>relations</em>.
+<dl>
+ <dt>Node
+ <dd>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).
+ <dt>Way
+ <dd>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).
+ <dt>Relation
+ <dd>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).
+</dl>
+
+The
+<a class="ext" title="OpenStreetMap Wiki" href="http://wiki.openstreetmap.org/wiki/Main_Page">OpenStreetMap Wiki</a>
+explains the data much better than I can.
+
+<h3><a name="H_1_1_2"></a>Router Data</h3>
+
+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.
+<dl>
+ <dt>Location of highways (nodes)
+ <dd>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.
+ <dt>Location of highways (ways)
+ <dd>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 <em>segments</em> which are
+ individual parts of a way connected by two nodes.
+ <dt>Properties of highways (tags)
+ <dd>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).
+ <dt>Connections between highways
+ <dd>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.
+</dl>
+
+The information that is extracted from the OpenStreetMap data is stored in an
+optimised way that allows the routing to be performed quickly.
+
+<h3><a name="H_1_1_3" title="Data Tags"></a>Interpreting Data Tags</h3>
+
+The <em>tags</em> 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).
+<p>
+
+There are no well defined rules in OpenStreetMap about tagging, but there is
+guidance on the
+<a class="ext" title="Map Features" href="http://wiki.openstreetmap.org/index.php/Map_Features">OpenStreetMap Wiki "Map_Features"</a>
+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.
+<p>
+
+The <a title="Tagging" href="tagging.html">tagging rules</a> 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.
+
+
+<h3><a name="H_1_1_4" title="Problems With Data"></a>Problems With OpenStreetMap Data</h3>
+
+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.
+<p>
+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.
+<p>
+A lot of these problems can be found using the interactive data visualiser that
+uses the same Routino rouing database.
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino documentation - index
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Documentation</TITLE>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Documentation</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+
+<h2><a name="H_1_1"></a>Data</h2>
+
+A good router relies on good data and the
+<a class="ext" title="OpenStreetMap" href="http://www.openstreetmap.org/">OpenStreetMap</a>
+data is a good source. There are however a number of things that need to be
+considered about
+<a href="data.html" title="Data considerations">the data used</a>.
+
+
+<h2><a name="H_1_2"></a>Tagging</h2>
+
+In addition to the raw data the way that are tags are used is also important.
+With Routino the
+<a title="Tagging" href="tagging.html">tagging rules</a>
+are contained in a configuration file and can easily be customised to change the
+interpretation of each tag.
+
+
+<h2><a name="H_1_3"></a>Program Usage</h2>
+
+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.
+<a href="usage.html" title="Program Usage">Full instructions</a>
+for using the four programs are provided.
+
+
+<h2><a name="H_1_4"></a>Configuration Files</h2>
+
+When the programs are run they read in one or more
+<a href="configuration.html" title="Configuration Files">configuration files</a>.
+These files contain information about the routing preferences (types of highways,
+prefered speeds etc), tagging rules and translation information for the outputs.
+
+
+<h2><a name="H_1_5"></a>Output Files</h2>
+
+The final result of running the router is one or more
+<a href="output.html" title="Output Files">output files</a>
+that contain the calculated route.
+
+
+<h2><a name="H_1_6"></a>Algorithm</h2>
+
+The <a title="Algorithm" href="algorithm.html">algorithm</a> that is used by
+Routino takes the OpenStreetMap data and creates a local database of the
+important information for rapid routing.
+
+
+<h2><a name="H_1_7"></a>Installation</h2>
+
+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
+<a href="installation.html" title="Installation">installation</a>
+describes how to compile the programs and install them.
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino documentation - installation
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Installation</TITLE>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Installation</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+
+<h2><a name="H_1_1"></a>Compilation</h2>
+
+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.
+
+<p>
+
+Any information on improving the compilation process on anything other than
+32-bit x86 Linux is welcome.
+
+<p>
+
+No external libraries are required and the programs are written in standard C
+language.
+
+<p>
+
+To compile the programs just type 'make'.
+
+
+<h2><a name="H_1_2"></a>Installation</h2>
+
+After compilation the executable files are copied into the directory
+<tt>web/bin</tt> and the default XML configuration files are copied into the
+directory <tt>web/data</tt>. 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.
+
+<p>
+
+The executable files are called <tt>planetsplitter</tt>, <tt>router</tt> and
+<tt>filedumper</tt> (also <tt>tagmodifier</tt> for debugging tag modifications).
+They can be copied to any location and need no special installation environment.
+
+<p>
+
+The default configuration files are called <tt>profiles.xml</tt>,
+<tt>tagging.xml</tt> and <tt>translations.xml</tt>. 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.
+
+
+<h2><a name="H_1_3"></a>Example Web Page</h2>
+
+The directory <tt>web</tt> contains a set of files that can be used to create a
+working set of web pages with interfaces to the routing algorithm.
+
+<p>
+
+The files in the <tt>web</tt> 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 <tt>paths.pl</tt>
+(to set the directory paths) and <tt>router.js</tt> and <tt>visualiser.js</tt>
+to limit the range of the visible map (latitude, longitude and zoom).
+
+
+<h3><a name="H_1_3_1"></a>Configuration of web files</h3>
+
+The assumption in this description is that the whole of the directory called
+<tt>web</tt> is copied into a directory that is accessible by an Apache web
+server.
+
+<p>
+
+<em>This is not a secure configuration but an easy one to configure.</em>
+<br>
+<em>Only the directory <tt>www</tt> should be accessible by the web server.</em>
+<br>
+<em>Do not use this configuration unmodified in a public web server.</em>
+
+<p>
+
+The directory structure is as follows:
+
+<pre>
+ 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.
+</pre>
+
+The directory <tt>bin</tt> will be filled by running the compilation process.
+For a secure installation the <tt>bin</tt> directory should be outside of the
+web server, the file <tt>www/routino/paths.pl</tt> contains the path to
+the <tt>bin</tt> directory.
+
+<p>
+
+The directory <tt>data</tt> 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 <tt>data</tt> directory should be outside of the web server, the
+file <tt>www/routino/paths.pl</tt> contains the path to the <tt>data</tt>
+directory.
+
+<p>
+
+The directory <tt>results</tt> 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 <tt>results</tt> directory should be outside of the web server, the file
+<tt>www/routino/paths.pl</tt> contains the path to the <tt>results</tt> directory.
+
+<p>
+
+The directory <tt>www</tt> and its sub-directories are the only ones that need
+to be within the web server accessible directory.
+
+<p>
+
+The directory <tt>www/openlayers</tt> 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 <tt>www/openlayers/OpenLayers.js</tt>
+and the directories <tt>www/openlayers/img/</tt>, <tt>www/openlayers/theme/</tt>
+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.
+
+<p>
+
+The directory <tt>www/routino</tt> 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.
+
+<dl>
+ <dt>paths.pl
+ <dd>This contains the names of the directories that contain the executable
+ files, router database and temporary results.
+ <dt>router.pl
+ <dd>This file contains the filename prefix for the routing database files
+ (only needed if planetsplitter is run with the --prefix option).
+ <dt>router.js
+ <dd>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).
+ <dt>visualiser.js
+ <dd>The same parameters as in router.js are in this file.
+</dl>
+
+<p>
+
+The directory <tt>www/routino/documentation</tt> contains the HTML version of
+the Routino documentation.
+
+
+<h3><a name="H_1_3_2"></a>Configuration of web server</h3>
+
+The file <tt>www/routino/.htaccess</tt> 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 <tt>AllowOverride</tt> option works
+one of the configuration options has been commented out. This must be enabled
+in the main Apache server configuration file.
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino documentation - output
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Output</TITLE>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Output</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2><a name="H_1_1"></a>Router Output</h2>
+
+There are three different formats of output from the router, HTML,
+<a class="ext" title="GPX format" href="http://www.topografix.com/gpx.asp">GPX (GPS eXchange) XML format</a>
+and plain text with a total of five possible output files:
+<ul>
+ <li>HTML route instructions for each interesting junction.
+ <li>GPX track file containing every node.
+ <li>GPX route file with waypoints at interesting junctions.
+ <li>Plain text description with the interesting junctions.
+ <li>Plain text file with every node.
+</ul>
+
+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.
+
+<p>
+
+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".
+
+<p>
+
+The HTML file and GPX files are written out according to the selected language
+using the translations contained in the translations.xml configuration file.
+
+<!-- For reference the examples were produced from the following URL:
+ http://www.gedanken.org.uk/mapping/routino/customrouter.cgi?transport=motorcar;lon1=-0.12790;lat1=51.52468;lon2=-0.10365;lat2=51.47824 -->
+
+<h3><a name="H_1_1_1" title="HTML file"></a>HTML Route Instructions</h3>
+
+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.
+
+<p>
+
+An example HTML file output is below (some parts are missing, for example the
+style definitions):
+
+<pre class="boxed">
+<!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>
+</pre>
+
+The coordinates are included in the file but are not visible because of the
+style definitions.
+
+<h3><a name="H_1_1_2" title="GPX track file"></a>GPX Track File</h3>
+
+The GPX track file contains a track with all of the individual nodes that the
+route passes through.
+
+<p>
+
+An example GPX track file output is below:
+
+<pre class="boxed">
+<?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>
+</pre>
+
+
+<h3><a name="H_1_1_3" title="GPX route file"></a>GPX Route File</h3>
+
+The GPX route file contains a route (ordered set of waypoints) with all of the
+interesting junctions that the route passes through.
+
+<p>
+
+An example GPX route file output is below:
+
+<pre class="boxed">
+<?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>
+</pre>
+
+
+<h3><a name="H_1_1_4" title="Text file"></a>Text File</h3>
+
+The text file format contains one entry for all of the interesting junctions in
+the route and is intended to be easy to interpret.
+
+<p>
+
+An example text file output is below:
+
+<pre class="boxed">
+# 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
+</pre>
+
+<p>
+
+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:
+
+<table>
+ <tr>
+ <th>Item
+ <th class=left>Description
+ <tr>
+ <td>Latitude
+ <td>Location of the point (degrees)
+ <tr>
+ <td>Longitude
+ <td>Location of the point (degrees)
+ <tr>
+ <td>Section Distance
+ <td>The distance travelled on the section of the journey that ends at this
+ point (defined on this line).
+ <tr>
+ <td>Section Duration
+ <td>The duration of travel on the section of the journey that ends at this
+ point (defined on this line).
+ <tr>
+ <td>Total Distance
+ <td>The total distance travelled up to this point.
+ <tr>
+ <td>Total Duration
+ <td>The total duration of travel up to this point.
+ <tr>
+ <td>Point Type
+ <td>The type of point; either a waypoint <em>Waypt</em> or
+ junction <em>Junct</em>.
+ <tr>
+ <td>Turn
+ <td>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 = <em>Straight</em>, +2 = <em>Right</em>, -2 = <em>Left</em> and +/-4
+ = <em>Reverse</em>.
+ <tr>
+ <td>Bearing
+ <td>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 = <em>North</em>, +2 = <em>East</em>, -2
+ = <em>West</em> and +/-4 = <em>South</em>.
+ <tr>
+ <td>Highway
+ <td>The name (or description) of the highway to follow (missing on the first
+ line).
+</table>
+
+<p>
+
+The individual items are separated by tabs but some of the items contain spaces
+as well.
+
+
+<h3><a name="H_1_1_5" title="All nodes text file"></a>All Nodes Text File</h3>
+
+The all nodes text file format contains one entry for each of the nodes on the
+route.
+
+<p>
+
+An example all nodes text file output is below:
+
+<pre class="boxed">
+# 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
+</pre>
+
+<p>
+
+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:
+
+<table>
+ <tr>
+ <th>Item
+ <th class=left>Description
+ <tr>
+ <td>Latitude
+ <td>Location of the point in degrees.
+ <tr>
+ <td>Longitude
+ <td>Location of the point in degrees.
+ <tr>
+ <td>Node
+ <td>The internal node number and an indicator "*" if the node is a super-node.
+ <tr>
+ <td>Type
+ <td>The type of point; a waypoint <em>Waypt</em>, junction <em>Junct</em>,
+ change of highway <em>Change</em> or intermediate node <em>Inter</em>.
+ <tr>
+ <td>Segment Distance
+ <td>The distance travelled on the segment defined on this line.
+ <tr>
+ <td>Segment Duration
+ <td>The duration of travel on the segment defined on this line.
+ <tr>
+ <td>Total Distance
+ <td>The total distance travelled up to this point.
+ <tr>
+ <td>Total Duration
+ <td>The total duration of travel up to this point.
+ <tr>
+ <td>Speed
+ <td>The speed of travel on the segment defined on this line (missing on the
+ first line).
+ <tr>
+ <td>Bearing
+ <td>The direction that the segment defined on this line travels in degrees
+ (missing on the first line).
+ <tr>
+ <td>Highway
+ <td>The name (or description) of the highway segment (missing on the first
+ line).
+</table>
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+/*
+// 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 <http://www.gnu.org/licenses/>.
+*/
+
+
+/*----------------------------------*/
+/* 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;
+}
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino documentation - tagging
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Tagging Rules</TITLE>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Tagging Rules</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2><a name="H_1_1"></a>Tags And Attributes</h2>
+
+The different tags and attributes in the
+<a class="ext" title="OpenStreetMap" href="http://www.openstreetmap.org/">OSM</a>
+format XML that are used by Routino are described below.
+
+<p>
+
+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.
+
+
+<h2><a name="H_1_2" title="After Processing"></a>Tags Recognised After Processing</h2>
+
+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.
+
+<p>
+
+In all cases of tag processing values of <em>true</em>, <em>yes</em>, <em>1</em>
+are recognised as being affirmative and any other value is ignored.
+
+
+<h3><a name="H_1_2_1" title="Nodes"></a>Node Tags And Attributes</h3>
+
+None of the node tags are used but the node attributes <em>id</em>, <em>latitude</em>
+and <em>longitude</em> 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.
+
+
+<h3><a name="H_1_2_2" title="Ways"></a>Way Tags And Attributes</h3>
+
+The tags from the ways in the data are the ones that provide most of the
+information for routing. The <em>id</em> attribute is used only so that the
+many segments associated with a way can be share a set of tags taken from the
+way.
+
+
+<h4><a name="H_1_2_2_1" title="highway"></a>The highway Tag</h4>
+
+The most important tag that is used from a way is the <em>highway</em> tag.
+This defines the type of highway that the way represents. Any way that does not
+have a highway tag is discarded.
+
+<p>
+
+There are more highway types defined than are used by the router. The subset
+that the router uses are:
+
+<ul>
+ <li>motorway
+ <li>trunk
+ <li>primary
+ <li>secondary
+ <li>tertiary
+ <li>unclassified
+ <li>residential
+ <li>service
+ <li>track
+ <li>cycleway
+ <li>path (1)
+ <li>steps (2)
+</ul>
+
+<p>
+
+<i>
+ Note 1: This changed in version 1.3 of Routino - the bridleway and footway
+ types were included within the path highway type.
+ <br>
+ Note 2: This changed in version 1.3 of Routino - the steps type was separated
+ from the footway type.
+</i>
+
+
+<h4><a name="H_1_2_2_2" title="transport tags"></a>Transport Specific Tags</h4>
+
+One tag is recognised for each of the different modes of transport: <em>foot</em>,
+<em>horse</em>, <em>bicycle</em>, <em>wheelchair</em>, <em>moped</em>,
+<em>motorbike</em>, <em>motorcar</em>, <em>goods</em>, <em>hgv</em>
+and <em>psv</em>. These indicate whether the specific type of transport is
+allowed on the highway or not.
+
+
+<h4><a name="H_1_2_2_3" title="name"></a>The name Tag</h4>
+
+The <em>name</em> tag is used to provide the label for the highway when printing
+the results.
+
+
+<h4><a name="H_1_2_2_4" title="ref"></a>The ref Tag</h4>
+
+The <em>ref</em> tag is used to provide the label for the highway when printing
+the results.
+
+
+<h4><a name="H_1_2_2_5" title="junction"></a>The junction Tag</h4>
+
+The <em>junction</em> 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.
+
+
+<h4><a name="H_1_2_2_6" title="multilane"></a>The multilane Tag</h4>
+
+The <em>multilane</em> 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 <em>multilane</em> tag but one needs to be added by the tag
+processing transformations. Values of <em>true</em>, <em>yes</em>, <em>1</em>
+are recognised.
+
+
+<h4><a name="H_1_2_2_7" title="paved"></a>The paved Tag</h4>
+
+The <em>paved</em> tag is used to identify whether a highway is paved or not,
+this is one of the available highway properties. A <em>paved</em> tag may exist
+in the original data but normally the <em>surface</em> tag needs to be
+transformed into the paved tag.
+
+
+<h4><a name="H_1_2_2_8" title="bridge"></a>The bridge Tag</h4>
+
+The <em>bridge</em> tag is used to identify whether a highway is a bridge and
+therefore set one of the available properties.
+
+
+<h4><a name="H_1_2_2_9" title="tunnel"></a>The tunnel Tag</h4>
+
+The <em>tunnel</em> tag is used to identify whether a highway is a tunnel and
+therefore set one of the available properties.
+
+
+<h4><a name="H_1_2_2_10" title="oneway"></a>The oneway Tag</h4>
+
+The <em>oneway</em> tag is used to specify that traffic is only allowed to
+travel in one direction.
+
+
+<h4><a name="H_1_2_2_11" title="maxspeed"></a>The maxspeed Tag</h4>
+
+The <em>maxspeed</em> 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.
+
+
+<h4><a name="H_1_2_2_12" title="maxweight"></a>The maxweight Tag</h4>
+
+The <em>maxweight</em> 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.
+
+
+<h4><a name="H_1_2_2_13" title="maxheight"></a>The maxheight Tag</h4>
+
+The <em>maxheight</em> 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.
+
+
+<h4><a name="H_1_2_2_14" title="maxwidth"></a>The maxwidth Tag</h4>
+
+The <em>maxwidth</em> 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.
+
+
+<h4><a name="H_1_2_2_15" title="maxlength"></a>The maxlength Tag</h4>
+
+The <em>maxlength</em> 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.
+
+
+<h3><a name="H_1_2_3" title="Relations"></a>Relation Tags And Attributes</h3>
+
+Currently no relation tags or attributes are used.
+
+
+<h2><a name="H_1_3" title="Tag Transformations"></a>Tag Transformations</h2>
+
+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.
+
+
+<h3><a name="H_1_3_1" title="Nodes"></a>Node Tag Transformations</h3>
+
+No transformations are applicable since no node tags are recognised.
+
+
+<h3><a name="H_1_3_2" title="Ways"></a>Way Tag Transformations</h3>
+
+
+<h4><a name="H_1_3_2_1" title="Highway Defaults"></a>Highway Defaults</h4>
+
+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.
+
+<p>
+
+The first part of the transformation is to convert the highway tag into one that
+is recognised by Routino.
+
+<p>
+
+<table>
+ <caption>Mapping of equivalent highway types</caption>
+ <tr>
+ <th class="left">Original tag
+ <th class="left">Transformed tag
+ <tr>
+ <td class="left">bridleway
+ <td class="left">path
+ <tr>
+ <td class="left">byway
+ <td class="left">track
+ <tr>
+ <td class="left">footway
+ <td class="left">path
+ <tr>
+ <td class="left">living_street
+ <td class="left">residential
+ <tr>
+ <td class="left">minor
+ <td class="left">unclassified
+ <tr>
+ <td class="left">pedestrian
+ <td class="left">path
+ <tr>
+ <td class="left">road
+ <td class="left">unclassified
+ <tr>
+ <td class="left">services
+ <td class="left">service
+ <tr>
+ <td class="left">unsurfaced
+ <td class="left">track
+ <tr>
+ <td class="left">unpaved
+ <td class="left">track
+ <tr>
+ <td class="left">walkway
+ <td class="left">path
+</table>
+
+<p>
+
+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.
+
+<p>
+
+<table>
+ <caption>Transport types on different highway types</caption>
+ <tr>
+ <th class="left">Highway
+ <th class="center">foot
+ <th class="center">horse
+ <th class="center">bicycle
+ <th class="center">wheelchair
+ <th class="center">moped
+ <th class="center">motorbike
+ <th class="center">motorcar
+ <th class="center">goods
+ <th class="center">hgv
+ <th class="center">psv
+ <tr>
+ <td class="left">motorway
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <tr>
+ <td class="left">trunk
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <tr>
+ <td class="left">primary
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <tr>
+ <td class="left">secondary
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <tr>
+ <td class="left">tertiary
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <tr>
+ <td class="left">unclassified
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <tr>
+ <td class="left">residential
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <tr>
+ <td class="left">service
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <tr>
+ <td class="left">track
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <tr>
+ <td class="left">cycleway
+ <td class="center">yes
+ <td class="center">no
+ <td class="center">yes
+ <td class="center">yes
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <tr>
+ <td class="left">path
+ <td class="center">yes
+ <td class="center">yes (1)
+ <td class="center">yes
+ <td class="center">yes (1)
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <tr>
+ <td class="left">steps
+ <td class="center">yes
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+ <td class="center">no
+</table>
+
+<p>
+
+<i>
+ 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 <em>designation</em> tag (described below).
+</i>
+
+<p>
+
+Finally for the highway tag a number of properties are added depending on the
+highway type.
+
+<p>
+
+<table>
+ <caption>Properties on different highway types</caption>
+ <tr>
+ <th class="center">Highway
+ <th class="center">Properties
+ <tr>
+ <td class="center">motorway
+ <td class="center">paved, oneway, multilane
+ <tr>
+ <td class="center">trunk
+ <td class="center">paved
+ <tr>
+ <td class="center">primary
+ <td class="center">paved
+ <tr>
+ <td class="center">secondary
+ <td class="center">paved
+ <tr>
+ <td class="center">tertiary
+ <td class="center">paved
+ <tr>
+ <td class="center">unclassified
+ <td class="center">paved
+ <tr>
+ <td class="center">residential
+ <td class="center">paved
+ <tr>
+ <td class="center">service
+ <td class="center">paved
+ <tr>
+ <td class="center">track
+ <td class="center">paved (1)
+ <tr>
+ <td class="center">cycleway
+ <td class="center">paved
+ <tr>
+ <td class="center">path
+ <td class="center">paved (2)
+ <tr>
+ <td class="center">steps
+ <td class="center">
+</table>
+
+<p>
+
+<i>
+ Note 1: A track is paved only if it is tagged as tracktype=grade1.
+ <br>
+ Note 2: A path is paved only if it was originally tagged as highway=walkway or
+ highway=pedestrian.
+</i>
+
+
+<h4><a name="H_1_3_2_2" title="Generic access"></a>Generic Access Permissions</h4>
+
+The <em>access</em> 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).
+
+
+<h4><a name="H_1_3_2_3" title="Other access"></a>Other Access Permissions</h4>
+
+A tag named <em>vehicle</em> means any of the <em>bicycle</em>, <em>moped</em>,
+<em>motorbike</em>, <em>motorcar</em>, <em>goods</em>, <em>hgv</em>
+and <em>psv</em> transport types. A tag named <em>motor_vehicle</em> is
+transformed to mean any vehicle except a <em>bicycle</em>.
+
+<p>
+
+The <em>designation</em> 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.
+
+<p>
+
+<table>
+ <caption>Aliasing of designation types</caption>
+ <tr>
+ <th class="left">Designation tag
+ <th class="left">Equivalent access permissions
+ <tr>
+ <td class="left">bridleway or public_bridleway
+ <td class="left">foot=yes, wheelchair=yes, horse=yes, bicycle=yes
+ <tr>
+ <td class="left">restricted_byway
+ <td class="left">foot=yes, wheelchair=yes, horse=yes, bicycle=yes
+ <tr>
+ <td class="left">byway
+ <td class="left">foot=yes, wheelchair=yes, horse=yes, bicycle=yes, moped=yes, motorbike=yes, motorcar=yes
+ <tr>
+ <td class="left">footpath or public_footpath
+ <td class="left">foot=yes, wheelchair=yes
+</table>
+
+
+<h4><a name="H_1_3_2_4" title="Specific access"></a>Specific Access Permissions</h4>
+
+The final part of the access permissions is to use the specific transport type
+tags.
+
+<p>
+
+One tag is recognised for each of the different modes of transport: <em>foot</em>,
+<em>horse</em>, <em>bicycle</em>, <em>wheelchair</em>, <em>moped</em>,
+<em>motorbike</em>, <em>motorcar</em>, <em>goods</em>, <em>hgv</em>
+and <em>psv</em>. These indicate whether the specific type of transport is
+allowed on the highway or not.
+
+
+<h4><a name="H_1_3_2_5" title="Properties"></a>Highway Properties</h4>
+
+If there is a surface tag then the highway is assumed to be unpaved unless the
+tag value matches one of the following: <em>paved</em>, <em>asphalt</em>
+or <em>concrete</em>.
+
+<p>
+
+Support for the obsolete <em>paved</em> tag is also provided and the highway is
+paved if this is set to a true value.
+
+<p>
+
+The <em>lanes</em> 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.
+
+<p>
+
+The <em>bridge</em> and <em>tunnel</em> tags are copied directly from the input
+to the output.
+
+
+<h4><a name="H_1_3_2_6" title="Restrictions"></a>Highway Restrictions</h4>
+
+The <em>oneway</em>, <em>maxspeed</em>, <em>maxweight</em>, <em>maxheight</em>,
+<em>maxwidth</em> and <em>maxlength</em> are copied directly from the input to
+the output without modification.
+
+
+<h4><a name="H_1_3_2_7" title="Names and Refs"></a>Highway Names and References</h4>
+
+The <em>name</em> and <em>ref</em> tags are copied directly from the input to
+the output.
+
+
+<h3><a name="H_1_3_3" title="Relations"></a>Relation Tag Transformations</h3>
+
+No transformations are applicable since no relation tags are recognised.
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino documentation - usage
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Usage</TITLE>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Usage</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2><a name="H_1_1"></a>Program Usage</h2>
+
+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.
+
+<h3><a name="H_1_1_1"></a>planetsplitter</h3>
+
+This program reads in the OSM format XML file and splits it up to create the
+database that is used for routing.
+
+<pre class="boxed">
+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> ...]
+</pre>
+
+<dl>
+ <dt>--help
+ <dd>Prints out the help information.
+ <dt>--dir=<dirname>
+ <dd>Sets the directory name in which to save the results.
+ Defaults to the current directory.
+ <dt>--prefix=<name>
+ <dd>Sets the filename prefix for the files that are created.
+ Defaults to no prefix.
+ <dt>--slim
+ <dd>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.
+ <dt>--sort-ram-size=<size>
+ <dd>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.
+ <dt>--tmpdir=<dirname>
+ <dd>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.
+ <dt>--parse-only
+ <dd>Parse the input files and store them in a temporary file but don't process
+ the data into a routing database.
+ <dt>--process-only
+ <dd>Don't read in any files but process the existing temporary file into the
+ routing database.
+ <dt>--max-iterations=<number>
+ <dd>The maximum number of iterations to use when generating super-nodes and
+ super-segments. Defaults to 10 which is normally enough.
+ <dt>--tagging=<filename>
+ <dd>The name of the XML file containing the tagging rules (defaults to
+ 'tagging.xml' with '--dirname' and '--prefix' options).
+ <dt><filename.osm> ...
+ <dd>Specifies the filename(s) to read data from, by default data is read from
+ the standard input.
+</dl>
+
+<p>
+<i>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.</i>
+
+<p>
+Example usage:
+
+<pre class="boxed">
+./planetsplitter --dir=data --prefix=gb great_britain.osm
+</pre>
+
+This will generate the output files 'data/gb-nodes.mem', 'data/gb-segments.mem'
+and 'data/gb-ways.mem'.
+
+
+<h3><a name="H_1_1_2"></a>router</h3>
+
+This program performs the calculation of the optimum routes using the database
+generated by the planetsplitter program.
+
+<pre class="boxed">
+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>]
+</pre>
+
+<dl>
+ <dt>--help
+ <dd>Prints out the help information.
+ <dt>--help-profile
+ <dd>Prints out the selected transport profile (type, speed limits, highway
+ preferences etc.)
+ <dt>--help-profile-xml
+ <dd>Prints out all the loaded profiles as an XML file in the same format that
+ can be loaded in.
+ <dt>--help-profile-json
+ <dd>Prints out all the loaded profiles in JavaScript Object Notation (JSON)
+ format for use in the interactive webpage.
+ <dt>--help-profile-perl
+ <dd>Prints out all the loaded profiles as a Perl object for use in the router
+ CGI.
+ <dt>--dir=<dirname>
+ <dd>Sets the directory name in which to read the local database.
+ Defaults to the current directory.
+ <dt>--prefix=<name>
+ <dd>Sets the filename prefix for the files in the local database.
+ Defaults to no prefix.
+ <dt>--profiles=<filename>
+ <dd>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.
+ <dt>--translations=<filename>
+ <dd>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.
+ <dt>--exact-nodes-only
+ <dd>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).
+ <dt>--quiet
+ <dd>Don't generate any screen output while running (useful for running in a script).
+ <dt>--language=<lang>
+ <dd>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.
+ <dt>--output-html
+ <dt>--output-gpx-track
+ <dt>--output-gpx-route
+ <dt>--output-text
+ <dt>--output-text-all
+ <dd>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.
+ <dt>--output-none
+ <dd>Do not generate any output or read in any translations files.
+ <dt>--profile=<name>
+ <dd>Specifies the name of the profile to use.
+ <dt>--transport=<transport>
+ <dd>Select the type of transport to use, <transport> can be set to:
+ <ul>
+ <li>foot = Foot
+ <li>horse = Horse
+ <li>wheelchair = Wheelchair
+ <li>bicycle = Bicycle
+ <li>moped = Moped (Small motorbike, limited speed)
+ <li>motorbike = Motorbike
+ <li>motorcar = Motorcar
+ <li>goods = Goods (Small lorry, van)
+ <li>hgv = HGV (Heavy Goods Vehicle - large lorry)
+ <li>psv = PSV (Public Service Vehicle - bus, coach)
+ </ul>
+ 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.
+ <dt>--shortest
+ <dd>Find the shortest route between the waypoints.
+ <dt>--quickest
+ <dd>Find the quickest route between the waypoints.
+ <dt>--lon1=<longitude>, --lat1=<latitude>
+ <dt>--lon2=<longitude>, --lat2=<latitude>
+ <dt>... --lon99=<longitude>, --lat99=<latitude>
+ <dd>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.
+ <dt>--highway-<highway>=<preference>
+ <dd>Selects the percentage preference for using each particular type of
+ highway. The value of <highway> can be selected from:
+ <ul>
+ <li>motorway = Motorway
+ <li>trunk = Trunk
+ <li>primary = Primary
+ <li>secondary = Secondary
+ <li>tertiary = Tertiary
+ <li>unclassified = Unclassified
+ <li>residential = Residential
+ <li>service = Service
+ <li>track = Track
+ <li>cycleway = Cycleway
+ <li>path = Path
+ <li>steps = Steps
+ </ul>
+ Default value depends on the profile selected by the --transport option.
+ <dt>--speed-<highway>=<speed>
+ <dd>Selects the speed limit in km/hour for each type of highway. Default
+ value depends on the profile selected by the --transport option.
+ <dt>--property-<property>=<preference>
+ <dd>Selects the percentage preference for using each particular highway
+ property
+ The value of <property> can be selected from:
+ <ul>
+ <li>paved = Paved (suitable for normal wheels)
+ <li>multilane = Multiple lanes
+ <li>bridge = Bridge
+ <li>tunnel = Tunnel
+ </ul>
+ Default value depends on the profile selected by the --transport option.
+ <dt>--oneway=[0|1]
+ <dd>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.
+ <dt>--weight=<weight>
+ <dd>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.
+ <dt>--height=<height>
+ <dd>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.
+ <dt>--width=<width>
+ <dd>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.
+ <dt>--length=<length>
+ <dd>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.
+</dl>
+
+<p>
+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).
+
+<p>
+Example usage (motorbike journey, scenic route, not very fast):
+
+<pre class="boxed">
+./router --dir=data --prefix=gb --transport=motorbike --highway-motorway=0 \
+ --highway-trunk=0 --speed-primary=80 --speed-secondary=80 --quickest
+</pre>
+
+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.
+
+
+<h3><a name="H_1_1_3"></a>filedumper</h3>
+
+This program is used to extract statistics from the database, extract particular
+information for visualisation purposes or for dumping the database contents.
+
+<pre class="boxed">
+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>]]
+</pre>
+
+<dl>
+ <dt>--help
+ <dd>Prints out the help information.
+ <dt>--dir=<dirname>
+ <dd>Sets the directory name in which to read the local database.
+ Defaults to the current directory.
+ <dt>--prefix=<name>
+ <dd>Sets the filename prefix for the files in the local database.
+ <dt>--statistics
+ <dd>Prints out statistics about the database files.
+ <dt>--visualiser
+ <dd>Selects a data visualiser mode which will output a set of data according
+ to the other parameters below.
+ <dl>
+ <dt>--latmin=<latmin> --latmax=<latmax>
+ <dd>The range of latitudes to print the data for.
+ <dt>--lonmin=<lonmin> --lonmax=<lonmax>
+ <dd>The range of longitudes to print the data for.
+ <dt>--data=<data-type>
+ <dd>The type of data to output, <data-type> can be selected from:
+ <ul>
+ <li>junctions = segment count at each junction.
+ <li>super = super-node and super-segments.
+ <li>oneway = oneway segments.
+ <li>speed = speed limits.
+ <li>weight = weight limits.
+ <li>height = height limits.
+ <li>width = width limits.
+ <li>length = length limits.
+ </ul>
+ </dl>
+ <dt>--dump
+ <dd>Selects a data dumping mode which allows looking at individual items in
+ the databases (specifying 'all' instead of a number dumps all of them).
+ <dl>
+ <dt>--node=<node>
+ <dd>Prints the information about the selected node number (internal
+ number, not the node id number in the original source file).
+ <dt>--segment=<segment>
+ <dd>Prints the information about the selected segment number.
+ <dt>--way=<way>
+ <dd>Prints the information about the selected way number (internal
+ number, not the way id number in the original source file).
+ </dl>
+ <dt>--osm-dump
+ <dd>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.
+ <dl>
+ <dt>--no-super
+ <dd>The super segments will not be output.
+ <dt>--latmin=<latmin> --latmax=<latmax>
+ <dd>The range of latitudes to dump the data for.
+ <dt>--lonmin=<lonmin> --lonmax=<lonmax>
+ <dd>The range of longitudes to dump the data for.
+ </dl>
+</dl>
+
+
+<h3><a name="H_1_1_4"></a>tagmodifier</h3>
+
+This program is used to run the tag transformation process on an OSM XML file
+for test purposes.
+
+<pre class="boxed">
+Usage: tagmodifier [--help]
+ [--tagging=<filename>]
+ [<filename.osm>]
+</pre>
+
+<dl>
+ <dt>--help
+ <dd>Prints out the help information.
+ <dt>--tagging=<filename>
+ <dd>The name of the XML file containing the tagging rules (defaults to
+ 'tagging.xml' in the current directory).
+ <dt><filename.osm> ...
+ <dd>Specifies the filename to read data from, by default data is read from
+ the standard input.
+</dl>
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+# $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 <http://www.gnu.org/licenses/>.
+#
+
+# 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 :
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+
+#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;arg<argc;arg++)
+ {
+ if(!strcmp(argv[arg],"--help"))
+ print_usage(1);
+ else if(!strncmp(argv[arg],"--dir=",6))
+ dirname=&argv[arg][6];
+ else if(!strncmp(argv[arg],"--prefix=",9))
+ prefix=&argv[arg][9];
+ else if(!strcmp(argv[arg],"--statistics"))
+ option_statistics=1;
+ else if(!strcmp(argv[arg],"--visualiser"))
+ option_visualiser=1;
+ else if(!strcmp(argv[arg],"--dump"))
+ option_dump=1;
+ else if(!strcmp(argv[arg],"--dump-osm"))
+ option_dump_osm=1;
+ else if(!strncmp(argv[arg],"--latmin",8) && argv[arg][8]=='=')
+ {latmin=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+ else if(!strncmp(argv[arg],"--latmax",8) && argv[arg][8]=='=')
+ {latmax=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+ else if(!strncmp(argv[arg],"--lonmin",8) && argv[arg][8]=='=')
+ {lonmin=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+ else if(!strncmp(argv[arg],"--lonmax",8) && argv[arg][8]=='=')
+ {lonmax=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+ else if(!strncmp(argv[arg],"--data",6) && argv[arg][6]=='=')
+ option_data=&argv[arg][7];
+ else if(!strcmp(argv[arg],"--no-super"))
+ option_no_super=1;
+ else if(!strncmp(argv[arg],"--node=",7))
+ ;
+ else if(!strncmp(argv[arg],"--segment=",10))
+ ;
+ else if(!strncmp(argv[arg],"--way=",6))
+ ;
+ else
+ print_usage(0);
+ }
+
+ if(!option_statistics && !option_visualiser && !option_dump && !option_dump_osm)
+ print_usage(0);
+
+ /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */
+
+ OSMNodes=LoadNodeList(nodes_filename=FileName(dirname,prefix,"nodes.mem"));
+
+ OSMSegments=LoadSegmentList(segments_filename=FileName(dirname,prefix,"segments.mem"));
+
+ OSMWays=LoadWayList(ways_filename=FileName(dirname,prefix,"ways.mem"));
+
+ /* Write out the visualiser data */
+
+ if(option_visualiser)
+ {
+ if(coordcount!=4)
+ {
+ fprintf(stderr,"The --visualiser option must have --latmin, --latmax, --lonmin, --lonmax.\n");
+ exit(1);
+ }
+
+ if(!option_data)
+ {
+ fprintf(stderr,"The --visualiser option must have --data.\n");
+ exit(1);
+ }
+
+ if(!strcmp(option_data,"junctions"))
+ OutputJunctions(OSMNodes,OSMSegments,OSMWays,latmin,latmax,lonmin,lonmax);
+ else if(!strcmp(option_data,"super"))
+ OutputSuper(OSMNodes,OSMSegments,OSMWays,latmin,latmax,lonmin,lonmax);
+ else if(!strcmp(option_data,"oneway"))
+ OutputOneway(OSMNodes,OSMSegments,OSMWays,latmin,latmax,lonmin,lonmax);
+ else if(!strcmp(option_data,"speed"))
+ OutputSpeedLimits(OSMNodes,OSMSegments,OSMWays,latmin,latmax,lonmin,lonmax);
+ else if(!strcmp(option_data,"weight"))
+ OutputWeightLimits(OSMNodes,OSMSegments,OSMWays,latmin,latmax,lonmin,lonmax);
+ else if(!strcmp(option_data,"height"))
+ OutputHeightLimits(OSMNodes,OSMSegments,OSMWays,latmin,latmax,lonmin,lonmax);
+ else if(!strcmp(option_data,"width"))
+ OutputWidthLimits(OSMNodes,OSMSegments,OSMWays,latmin,latmax,lonmin,lonmax);
+ else if(!strcmp(option_data,"length"))
+ OutputLengthLimits(OSMNodes,OSMSegments,OSMWays,latmin,latmax,lonmin,lonmax);
+ else
+ {
+ fprintf(stderr,"Unrecognised data option '%s' with --visualiser.\n",option_data);
+ exit(1);
+ }
+ }
+
+ /* Print out statistics */
+
+ if(option_statistics)
+ {
+ struct stat buf;
+
+ /* Examine the files */
+
+ printf("Files\n");
+ printf("-----\n");
+ printf("\n");
+
+ stat(nodes_filename,&buf);
+
+ printf("'%s%snodes.mem' - %9lld Bytes\n",prefix?prefix:"",prefix?"-":"",(long long)buf.st_size);
+ printf("%s\n",RFC822Date(buf.st_mtime));
+ printf("\n");
+
+ stat(segments_filename,&buf);
+
+ printf("'%s%ssegments.mem' - %9lld Bytes\n",prefix?prefix:"",prefix?"-":"",(long long)buf.st_size);
+ printf("%s\n",RFC822Date(buf.st_mtime));
+ printf("\n");
+
+ stat(ways_filename,&buf);
+
+ printf("'%s%sways.mem' - %9lld Bytes\n",prefix?prefix:"",prefix?"-":"",(long long)buf.st_size);
+ printf("%s\n",RFC822Date(buf.st_mtime));
+ printf("\n");
+
+ /* Examine the nodes */
+
+ printf("Nodes\n");
+ printf("-----\n");
+ printf("\n");
+
+ printf("sizeof(Node) =%9d Bytes\n",sizeof(Node));
+ printf("Number =%9d\n",OSMNodes->number);
+ 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;arg<argc;arg++)
+ if(!strcmp(argv[arg],"--node=all"))
+ {
+ for(item=0;item<OSMNodes->number;item++)
+ print_node(OSMNodes,item);
+ }
+ else if(!strncmp(argv[arg],"--node=",7))
+ {
+ item=atoi(&argv[arg][7]);
+
+ if(item>=0 && item<OSMNodes->number)
+ 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;item<OSMSegments->number;item++)
+ print_segment(OSMSegments,item);
+ }
+ else if(!strncmp(argv[arg],"--segment=",10))
+ {
+ item=atoi(&argv[arg][10]);
+
+ if(item>=0 && item<OSMSegments->number)
+ 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;item<OSMWays->number;item++)
+ print_way(OSMWays,item);
+ }
+ else if(!strncmp(argv[arg],"--way=",6))
+ {
+ item=atoi(&argv[arg][6]);
+
+ if(item>=0 && item<OSMWays->number)
+ 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];node<OSMNodes->offsets[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 && lat<latmax && lon>lonmin && lon<lonmax)
+ {
+ Segment *segment;
+
+ print_node_osm(OSMNodes,node);
+
+ segment=FirstSegment(OSMSegments,OSMNodes,node);
+
+ while(segment)
+ {
+ if(node>OtherNode(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;item<OSMNodes->number;item++)
+ print_node_osm(OSMNodes,item);
+
+ for(item=0;item<OSMSegments->number;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("<?xml version='1.0' encoding='UTF-8'?>\n");
+ printf("<osm version='0.6' generator='JOSM'>\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(" <node id='%lu' lat='%.7f' lon='%.7f' version='1'>\n",(unsigned long)item+1,radians_to_degrees(latitude),radians_to_degrees(longitude));
+ printf(" <tag k='routino:super' v='yes' />\n");
+ printf(" </node>\n");
+ }
+ else
+ printf(" <node id='%lu' lat='%.7f' lon='%.7f' version='1' />\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(" <way id='%lu' version='1'>\n",(unsigned long)item+1);
+
+ if(IsOnewayTo(segment,segment->node1))
+ {
+ printf(" <nd ref='%lu' />\n",(unsigned long)segment->node2+1);
+ printf(" <nd ref='%lu' />\n",(unsigned long)segment->node1+1);
+ }
+ else
+ {
+ printf(" <nd ref='%lu' />\n",(unsigned long)segment->node1+1);
+ printf(" <nd ref='%lu' />\n",(unsigned long)segment->node2+1);
+ }
+
+ if(IsSuperSegment(segment))
+ printf(" <tag k='routino:super' v='yes' />\n");
+ if(IsNormalSegment(segment))
+ printf(" <tag k='routino:normal' v='yes' />\n");
+
+ if(way->type & Way_OneWay)
+ printf(" <tag k='oneway' v='yes' />\n");
+ if(way->type & Way_Roundabout)
+ printf(" <tag k='junction' v='roundabout' />\n");
+
+ printf(" <tag k='highway' v='%s' />\n",HighwayName(HIGHWAY(way->type)));
+
+ if(IsNormalSegment(segment) && WayNamed(ways,way))
+ printf(" <tag k='name' v='%s' />\n",ParseXML_Encode_Safe_XML(WayNameHighway(ways,way)));
+
+ for(i=1;i<Transport_Count;i++)
+ if(way->allow & ALLOWED(i))
+ printf(" <tag k='%s' v='yes' />\n",TransportName(i));
+
+ for(i=1;i<Property_Count;i++)
+ if(way->props & PROPERTIES(i))
+ printf(" <tag k='%s' v='yes' />\n",PropertyName(i));
+
+ if(way->speed)
+ printf(" <tag k='maxspeed' v='%d' />\n",speed_to_kph(way->speed));
+
+ if(way->weight)
+ printf(" <tag k='maxweight' v='%.1f' />\n",weight_to_tonnes(way->weight));
+ if(way->height)
+ printf(" <tag k='maxheight' v='%.1f' />\n",height_to_metres(way->height));
+ if(way->width)
+ printf(" <tag k='maxwidth' v='%.1f' />\n",width_to_metres(way->width));
+ if(way->length)
+ printf(" <tag k='maxlength' v='%.1f' />\n",length_to_metres(way->length));
+
+ printf(" </way>\n");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ Print out a tail in OSM XML format.
+ ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_tail_osm(void)
+{
+ printf("</osm>\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=<dirname>] [--prefix=<name>]\n"
+ " [--statistics]\n"
+ " [--visualiser --latmin=<latmin> --latmax=<latmax>\n"
+ " --lonmin=<lonmin> --lonmax=<lonmax>\n"
+ " --data=<data-type>]\n"
+ " [--dump [--node=<node> ...]\n"
+ " [--segment=<segment> ...]\n"
+ " [--way=<way> ...]]\n"
+ " [--dump-osm [--no-super]\n"
+ " [--latmin=<latmin> --latmax=<latmax>\n"
+ " --lonmin=<lonmin> --lonmax=<lonmax>]]\n");
+
+ if(detail)
+ fprintf(stderr,
+ "\n"
+ "--help Prints this information.\n"
+ "\n"
+ "--dir=<dirname> The directory containing the routing database.\n"
+ "--prefix=<name> 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=<latmin> * the minimum latitude (degrees N).\n"
+ " --latmax=<latmax> * the maximum latitude (degrees N).\n"
+ " --lonmin=<lonmin> * the minimum longitude (degrees E).\n"
+ " --lonmax=<lonmax> * the maximum longitude (degrees E).\n"
+ " --data=<data-type> * the type of data to select.\n"
+ "\n"
+ " <data-type> 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=<node> * the node with the selected number.\n"
+ " --segment=<segment> * the segment with the selected number.\n"
+ " --way=<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=<latmin> * the minimum latitude (degrees N).\n"
+ " --latmax=<latmax> * the maximum latitude (degrees N).\n"
+ " --lonmin=<lonmin> * the minimum longitude (degrees E).\n"
+ " --lonmax=<lonmax> * the maximum longitude (degrees E).\n");
+
+ exit(!detail);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#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;i<nmappedfiles;i++)
+ if(!strcmp(mappedfiles[i].filename,filename))
+ break;
+
+ if(i==nmappedfiles)
+ {
+ fprintf(stderr,"The file '%s' was not mapped using MapFile().\n",filename);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Close the file */
+
+ close(mappedfiles[i].fd);
+
+ /* Unmap the file */
+
+ munmap(mappedfiles[i].address,mappedfiles[i].length);
+
+ /* Shuffle the list of files */
+
+ nmappedfiles--;
+
+ if(nmappedfiles>i)
+ 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);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef FUNCTIONS_H
+#define FUNCTIONS_H /*+ To stop multiple inclusions. +*/
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef FUNCTIONSX_H
+#define FUNCTIONSX_H /*+ To stop multiple inclusions. +*/
+
+#include <stdio.h>
+
+#include "typesx.h"
+#include "profiles.h"
+
+
+/* In osmparser.c */
+
+int ParseOSM(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays);
+
+
+#endif /* FUNCTIONSX_H */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <math.h>
+
+#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)<delta && abs(lonb-lonbin)<delta)
+ continue;
+
+ llbin=lonb*nodes->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];i<nodes->offsets[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(dist<distance)
+ {
+ if(profile)
+ {
+ Segment *segment;
+
+ /* Decide if this is node is valid for the profile */
+
+ segment=FirstSegment(segments,nodes,i);
+
+ do
+ {
+ Way *way=LookupWay(ways,segment->way);
+
+ 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)<delta && abs(lonb-lonbin)<delta)
+ continue;
+
+ llbin=lonb*nodes->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];i<nodes->offsets[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(dist1<distance)
+ {
+ Segment *segment;
+
+ /* Check each segment for closeness and if valid for the profile */
+
+ segment=FirstSegment(segments,nodes,i);
+
+ do
+ {
+ if(IsNormalSegment(segment))
+ {
+ Way *way=NULL;
+
+ if(profile)
+ way=LookupWay(ways,segment->way);
+
+ 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]<index) /* Mid point is too low */
+ start=mid;
+ else if(nodes->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(lonbin<nodes->lonbins && 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]<index) /* Mid point is too low */
+ start=mid;
+ else if(nodes->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(latbin<nodes->latbins && 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));
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef NODES_H
+#define NODES_H /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#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_id<b_id)
+ return(-1);
+ else if(a_id>b_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_lon<b_lon)
+ return(-1);
+ else if(a_lon>b_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_lat<b_lat)
+ return(-1);
+ else if(a_lat>b_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_id<b_id)
+ return(-1);
+ else if(a_id>b_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(end<start) /* There are no nodes */
+ return(NO_NODE);
+ else if(id<nodesx->idata[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]<id) /* Mid point is too low */
+ start=mid+1;
+ else if(nodesx->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.latitude<lat_min)
+ lat_min=nodex.latitude;
+ if(nodex.latitude>lat_max)
+ lat_max=nodex.latitude;
+ if(nodex.longitude<lon_min)
+ lon_min=nodex.longitude;
+ if(nodex.longitude>lon_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;i<nodesx->number;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;i<segmentsx->number;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;i<nodesx->number;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;i<nodes->number;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);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef NODESX_H
+#define NODESX_H /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+
+#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->weight<profile->weight)
+ goto endloop;
+
+ if((way->height && way->height<profile->height) ||
+ (way->width && way->width <profile->width ) ||
+ (way->length && way->length<profile->length))
+ goto endloop;
+
+ segment_pref=profile->highway[HIGHWAY(way->type)];
+
+ for(i=1;i<Property_Count;i++)
+ if(ways->props & 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_score<result2->score) /* 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->score<finish_score)
+ InsertInQueue(queue,result2);
+ }
+ }
+
+ endloop:
+
+ if(IsFakeNode(node1))
+ segment=NextFakeSegment(segment,node1);
+ else if(IsFakeNode(node2))
+ segment=NULL; /* cannot call NextSegment() with a fake segment */
+ else
+ {
+ segment=NextSegment(segments,segment,node1);
+
+ if(!segment && IsFakeNode(finish))
+ segment=ExtraFakeSegment(node1,finish);
+ }
+ }
+ }
+
+ FreeQueueList(queue);
+
+ /* Check it worked */
+
+ if(!FindResult(results,finish))
+ {
+ FreeResultsList(results);
+ return(NULL);
+ }
+
+ FixForwardRoute(results,finish);
+
+ return(results);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ Find the optimum route between two nodes where the start and end are a set of pre-routed super-nodes.
+
+ Results *FindMiddleRoute 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.
+
+ Results *begin The initial portion of the route.
+
+ Results *end The final portion of the route.
+
+ Profile *profile The profile containing the transport type, speeds and allowed highways.
+ ++++++++++++++++++++++++++++++++++++++*/
+
+Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Results *begin,Results *end,Profile *profile)
+{
+ Results *results;
+ Queue *queue;
+ index_t node1,node2;
+ index_t end_prev;
+ score_t finish_score;
+ double finish_lat,finish_lon;
+ Result *result1,*result2,*result3;
+ Segment *segment;
+ Way *way;
+
+ if(!option_quiet)
+ {
+ printf("Routing: Super-Nodes checked = 0");
+ fflush(stdout);
+ }
+
+ /* Set up the finish conditions */
+
+ finish_score=INF_DISTANCE;
+ end_prev=NO_NODE;
+
+ if(IsFakeNode(end->finish))
+ 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->weight<profile->weight)
+ goto endloop;
+
+ if((way->height && way->height<profile->height) ||
+ (way->width && way->width <profile->width ) ||
+ (way->length && way->length<profile->length))
+ goto endloop;
+
+ segment_pref=profile->highway[HIGHWAY(way->type)];
+
+ for(i=1;i<Property_Count;i++)
+ if(ways->props & 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)<finish_score)
+ {
+ finish_score=result2->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_score<result2->score) /* 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)<finish_score)
+ {
+ finish_score=result2->score+result3->score;
+ end_prev=node2;
+ }
+ }
+ else if(result2->score<finish_score)
+ {
+ 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);
+ }
+ }
+
+ 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->weight<profile->weight)
+ goto endloop;
+
+ if((way->height && way->height<profile->height) ||
+ (way->width && way->width <profile->width ) ||
+ (way->length && way->length<profile->length))
+ goto endloop;
+
+ segment_pref=profile->highway[HIGHWAY(way->type)];
+
+ for(i=1;i<Property_Count;i++)
+ if(ways->props & 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_score<result2->score) /* 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->weight<profile->weight)
+ goto endloop;
+
+ if((way->height && way->height<profile->height) ||
+ (way->width && way->width <profile->width ) ||
+ (way->length && way->length<profile->length))
+ goto endloop;
+
+ segment_pref=profile->highway[HIGHWAY(way->type)];
+
+ for(i=1;i<Property_Count;i++)
+ if(ways->props & 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_score<result2->score) /* 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;
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#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;i<tags->ntags;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.type<Way_Count)
+ {
+ if(way.allow)
+ {
+ char *refname;
+
+ if(oneway)
+ way.type|=Way_OneWay;
+
+ if(roundabout)
+ way.type|=Way_Roundabout;
+
+ if(ref && name)
+ {
+ refname=(char*)malloc(strlen(ref)+strlen(name)+4);
+ sprintf(refname,"%s (%s)",name,ref);
+ }
+ else if(ref && !name)
+ refname=ref;
+ else if(!ref && name)
+ refname=name;
+ else /* if(!ref && !name) */
+ refname="";
+
+ AppendWay(ways,id,&way,refname);
+
+ if(ref && name)
+ free(refname);
+
+ for(i=1;i<way_nnodes;i++)
+ {
+ node_t from=way_nodes[i-1];
+ node_t to =way_nodes[i];
+
+ if(oneway>0)
+ {
+ 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);
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <math.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#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,"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
+ fprintf(htmlfile,"<HTML>\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,"<HEAD>\n");
+ fprintf(htmlfile,"<TITLE>");
+ fprintf(htmlfile,translate_html_title,option_quickest?translate_route_quickest:translate_route_shortest);
+ fprintf(htmlfile,"</TITLE>\n");
+ fprintf(htmlfile,"<STYLE type='text/css'>\n");
+ fprintf(htmlfile,"<!--\n");
+ fprintf(htmlfile," table {table-layout: fixed; border: none; border-collapse: collapse;}\n");
+ fprintf(htmlfile," table.c {color: grey; font-size: x-small;} /* copyright */\n");
+ fprintf(htmlfile," tr {border: 0px;}\n");
+ fprintf(htmlfile," tr.c {display: none;} /* coords */\n");
+ fprintf(htmlfile," tr.n {} /* node */\n");
+ fprintf(htmlfile," tr.s {} /* segment */\n");
+ fprintf(htmlfile," tr.t {font-weight: bold;} /* total */\n");
+ fprintf(htmlfile," td.l {font-weight: bold;}\n");
+ fprintf(htmlfile," td.r {}\n");
+ fprintf(htmlfile," span.w {font-weight: bold;} /* waypoint */\n");
+ fprintf(htmlfile," span.h {text-decoration: underline;} /* highway */\n");
+ fprintf(htmlfile," span.d {} /* segment distance */\n");
+ fprintf(htmlfile," span.j {font-style: italic;} /* total journey distance */\n");
+ fprintf(htmlfile," span.t {font-variant: small-caps;} /* turn */\n");
+ fprintf(htmlfile," span.b {font-variant: small-caps;} /* bearing */\n");
+ fprintf(htmlfile,"-->\n");
+ fprintf(htmlfile,"</STYLE>\n");
+ fprintf(htmlfile,"</HEAD>\n");
+ fprintf(htmlfile,"<BODY>\n");
+ fprintf(htmlfile,"<H1>");
+ fprintf(htmlfile,translate_html_title,option_quickest?translate_route_quickest:translate_route_shortest);
+ fprintf(htmlfile,"</H1>\n");
+ fprintf(htmlfile,"<table>\n");
+ }
+
+ if(gpxtrackfile)
+ {
+ fprintf(gpxtrackfile,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(gpxtrackfile,"<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\">\n");
+
+ fprintf(gpxtrackfile,"<metadata>\n");
+ fprintf(gpxtrackfile,"<desc>%s : %s</desc>\n",translate_copyright_creator[0],translate_copyright_creator[1]);
+ if(translate_copyright_source[1])
+ {
+ fprintf(gpxtrackfile,"<copyright author=\"%s\">\n",translate_copyright_source[1]);
+
+ if(translate_copyright_license[1])
+ fprintf(gpxtrackfile,"<license>%s</license>\n",translate_copyright_license[1]);
+
+ fprintf(gpxtrackfile,"</copyright>\n");
+ }
+ fprintf(gpxtrackfile,"</metadata>\n");
+
+ fprintf(gpxtrackfile,"<trk>\n");
+ fprintf(gpxtrackfile,"<name>");
+ fprintf(gpxtrackfile,translate_gpx_name,option_quickest?translate_route_quickest:translate_route_shortest);
+ fprintf(gpxtrackfile,"</name>\n");
+ fprintf(gpxtrackfile,"<desc>");
+ fprintf(gpxtrackfile,translate_gpx_desc,option_quickest?translate_route_quickest:translate_route_shortest);
+ fprintf(gpxtrackfile,"</desc>\n");
+ }
+
+ if(gpxroutefile)
+ {
+ fprintf(gpxroutefile,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(gpxroutefile,"<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\">\n");
+
+ fprintf(gpxroutefile,"<metadata>\n");
+ fprintf(gpxroutefile,"<desc>%s : %s</desc>\n",translate_copyright_creator[0],translate_copyright_creator[1]);
+ if(translate_copyright_source[1])
+ {
+ fprintf(gpxroutefile,"<copyright author=\"%s\">\n",translate_copyright_source[1]);
+
+ if(translate_copyright_license[1])
+ fprintf(gpxroutefile,"<license>%s</license>\n",translate_copyright_license[1]);
+
+ fprintf(gpxroutefile,"</copyright>\n");
+ }
+ fprintf(gpxroutefile,"</metadata>\n");
+
+ fprintf(gpxroutefile,"<rte>\n");
+ fprintf(gpxroutefile,"<name>");
+ fprintf(gpxroutefile,translate_gpx_name,option_quickest?translate_route_quickest:translate_route_shortest);
+ fprintf(gpxroutefile,"</name>\n");
+ fprintf(gpxroutefile,"<desc>");
+ fprintf(gpxroutefile,translate_gpx_desc,option_quickest?translate_route_quickest:translate_route_shortest);
+ fprintf(gpxroutefile,"</desc>\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,"<trkseg>\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,"<trkpt lat=\"%.6f\" lon=\"%.6f\"/>\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,"<tr class='s'><td class='l'>%s:<td class='r'>",translate_html_segment[0]);
+ fprintf(htmlfile,translate_html_segment[1],
+ waynamexml,
+ distance_to_km(junc_distance),duration_to_minutes(junc_duration));
+ fprintf(htmlfile," [<span class='j'>");
+ fprintf(htmlfile,translate_html_total[1],
+ distance_to_km(cum_distance),duration_to_minutes(cum_duration));
+ fprintf(htmlfile,"</span>]\n");
+
+ fprintf(htmlfile,"<tr class='c'><td class='l'><td class='r'>%.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,"<tr class='n'><td class='l'>%s:<td class='r'>",translate_html_node[0]);
+ fprintf(htmlfile,translate_html_node[1],
+ type,
+ turn_str,
+ bearing_next_str);
+ fprintf(htmlfile,"\n");
+ }
+ else
+ {
+ fprintf(htmlfile,"<tr class='n'><td class='l'>%s:<td class='r'>",translate_html_stop[0]);
+ fprintf(htmlfile,translate_html_stop[1],
+ translate_html_waypoint);
+ fprintf(htmlfile,"\n");
+ fprintf(htmlfile,"<tr class='t'><td class='l'>%s:<td class='r'><span class='j'>",translate_html_total[0]);
+ fprintf(htmlfile,translate_html_total[1],
+ distance_to_km(cum_distance),duration_to_minutes(cum_duration));
+ fprintf(htmlfile,"</span>\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,"<desc>");
+ fprintf(gpxroutefile,translate_gpx_step,
+ bearing_str,
+ waynamexml,
+ distance_to_km(junc_distance),duration_to_minutes(junc_duration));
+ fprintf(gpxroutefile,"</desc></rtept>\n");
+
+ if(!nextresult)
+ {
+ fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s</name>\n",
+ radians_to_degrees(finish_lat),radians_to_degrees(finish_lon),
+ translate_gpx_finish);
+ fprintf(gpxroutefile,"<desc>");
+ fprintf(gpxroutefile,translate_gpx_final,
+ distance_to_km(cum_distance),duration_to_minutes(cum_duration));
+ fprintf(gpxroutefile,"</desc></rtept>\n");
+ }
+ else if(important==10)
+ fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s%d</name>\n",
+ radians_to_degrees(latitude),radians_to_degrees(longitude),
+ translate_gpx_inter,++segment_count);
+ else
+ fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s%03d</name>\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,"<tr class='c'><td class='l'><td class='r'>%.6f %.6f\n",
+ radians_to_degrees(latitude),radians_to_degrees(longitude));
+ fprintf(htmlfile,"<tr class='n'><td class='l'>%s:<td class='r'>",translate_html_start[0]);
+ fprintf(htmlfile,translate_html_start[1],
+ translate_html_waypoint,
+ bearing_next_str);
+ fprintf(htmlfile,"\n");
+ }
+
+ if(gpxroutefile)
+ fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s</name>\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,"</trkseg>\n");
+
+ point=nextpoint;
+ }
+
+ /* Print the tail of the files */
+
+ if(htmlfile)
+ {
+ fprintf(htmlfile,"</table>\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,"<p>\n");
+ fprintf(htmlfile,"<table class='c'>\n");
+ if(translate_copyright_creator[0] && translate_copyright_creator[1])
+ fprintf(htmlfile,"<tr><td class='l'>%s:<td class='r'>%s\n",translate_copyright_creator[0],translate_copyright_creator[1]);
+ if(translate_copyright_source[0] && translate_copyright_source[1])
+ fprintf(htmlfile,"<tr><td class='l'>%s:<td class='r'>%s\n",translate_copyright_source[0],translate_copyright_source[1]);
+ if(translate_copyright_license[0] && translate_copyright_license[1])
+ fprintf(htmlfile,"<tr><td class='l'>%s:<td class='r'>%s\n",translate_copyright_license[0],translate_copyright_license[1]);
+ fprintf(htmlfile,"</table>\n");
+ }
+
+ fprintf(htmlfile,"</BODY>\n");
+ fprintf(htmlfile,"</HTML>\n");
+ }
+
+ if(gpxtrackfile)
+ {
+ fprintf(gpxtrackfile,"</trk>\n");
+ fprintf(gpxtrackfile,"</gpx>\n");
+ }
+
+ if(gpxroutefile)
+ {
+ fprintf(gpxroutefile,"</rte>\n");
+ fprintf(gpxroutefile,"</gpx>\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);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#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;arg<argc;arg++)
+ {
+ if(!strcmp(argv[arg],"--help"))
+ print_usage(1);
+ else if(!strcmp(argv[arg],"--slim"))
+ option_slim=1;
+ else if(!strncmp(argv[arg],"--sort-ram-size=",16))
+ option_filesort_ramsize=atoi(&argv[arg][16]);
+ else if(!strncmp(argv[arg],"--dir=",6))
+ dirname=&argv[arg][6];
+ else if(!strncmp(argv[arg],"--tmpdir=",9))
+ option_tmpdirname=&argv[arg][9];
+ else if(!strncmp(argv[arg],"--prefix=",9))
+ prefix=&argv[arg][9];
+ else if(!strcmp(argv[arg],"--parse-only"))
+ option_parse_only=1;
+ else if(!strcmp(argv[arg],"--process-only"))
+ option_process_only=1;
+ else if(!strncmp(argv[arg],"--max-iterations=",17))
+ max_iterations=atoi(&argv[arg][17]);
+ else if(!strncmp(argv[arg],"--tagging=",10))
+ tagging=&argv[arg][10];
+ else if(argv[arg][0]=='-' && argv[arg][1]=='-')
+ print_usage(0);
+ else
+ option_filenames++;
+ }
+
+ /* Check the specified command line options */
+
+ if(option_parse_only && option_process_only)
+ print_usage(0);
+
+ if(option_filenames && option_process_only)
+ print_usage(0);
+
+ if(!option_filesort_ramsize)
+ {
+ if(option_slim)
+ option_filesort_ramsize=64*1024*1024;
+ else
+ option_filesort_ramsize=256*1024*1024;
+ }
+ else
+ option_filesort_ramsize*=1024*1024;
+
+ if(!option_tmpdirname)
+ {
+ if(!dirname)
+ option_tmpdirname=".";
+ else
+ option_tmpdirname=dirname;
+ }
+
+ if(tagging && ExistsFile(tagging))
+ ;
+ else if(!tagging && ExistsFile(FileName(dirname,prefix,"tagging.xml")))
+ tagging=FileName(dirname,prefix,"tagging.xml");
+
+ if(tagging && ParseXMLTaggingRules(tagging))
+ {
+ fprintf(stderr,"Error: Cannot read the tagging rules in the file '%s'.\n",tagging);
+ return(1);
+ }
+
+ if(!tagging)
+ {
+ fprintf(stderr,"Error: Cannot run without reading some tagging rules.\n");
+ return(1);
+ }
+
+ /* Create new node, segment and way variables */
+
+ Nodes=NewNodeList(option_parse_only||option_process_only);
+
+ Segments=NewSegmentList(option_parse_only||option_process_only);
+
+ Ways=NewWayList(option_parse_only||option_process_only);
+
+ /* Parse the file */
+
+ if(option_filenames)
+ {
+ for(arg=1;arg<argc;arg++)
+ {
+ FILE *file;
+
+ if(argv[arg][0]=='-' && argv[arg][1]=='-')
+ continue;
+
+ file=fopen(argv[arg],"rb");
+
+ if(!file)
+ {
+ fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",argv[arg],strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("\nParse OSM Data [%s]\n==============\n\n",argv[arg]);
+ fflush(stdout);
+
+ if(ParseOSM(file,Nodes,Segments,Ways))
+ exit(EXIT_FAILURE);
+
+ fclose(file);
+ }
+ }
+ else if(!option_process_only)
+ {
+ printf("\nParse OSM Data\n==============\n\n");
+ fflush(stdout);
+
+ if(ParseOSM(stdin,Nodes,Segments,Ways))
+ exit(EXIT_FAILURE);
+ }
+
+ if(option_parse_only)
+ {
+ FreeNodeList(Nodes,1);
+ FreeSegmentList(Segments,1);
+ FreeWayList(Ways,1);
+
+ return(0);
+ }
+
+ /* Process the data */
+
+ printf("\nProcess OSM Data\n================\n\n");
+ fflush(stdout);
+
+ /* Sort the nodes, segments and ways */
+
+ SortNodeList(Nodes);
+
+ SortSegmentList(Segments);
+
+ SortWayList(Ways);
+
+ /* Remove bad segments (must be after sorting the nodes and segments) */
+
+ RemoveBadSegments(Nodes,Segments);
+
+ /* Remove non-highway nodes (must be after removing the bad segments) */
+
+ RemoveNonHighwayNodes(Nodes,Segments);
+
+ /* Measure the segments and replace node/way id with index (must be after removing non-highway nodes) */
+
+ UpdateSegments(Segments,Nodes,Ways);
+
+
+ /* Repeated iteration on Super-Nodes and Super-Segments */
+
+ do
+ {
+ printf("\nProcess Super-Data (iteration %d)\n================================%s\n\n",iteration,iteration>9?"=":"");
+ 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<node2 */
+
+ RotateSegments(Segments);
+
+ /* Sort the segments */
+
+ SortSegmentList(Segments);
+
+ /* Remove duplicated segments */
+
+ DeduplicateSegments(Segments,Nodes,Ways);
+
+ /* Cross reference the nodes and segments */
+
+ printf("\nCross-Reference Nodes and Segments\n==================================\n\n");
+ fflush(stdout);
+
+ /* Sort the node list geographically */
+
+ SortNodeListGeographically(Nodes);
+
+ /* Create the real segments and nodes */
+
+ CreateRealNodes(Nodes,iteration);
+
+ CreateRealSegments(Segments,Ways);
+
+ /* Fix the segment and node indexes */
+
+ IndexNodes(Nodes,Segments);
+
+ IndexSegments(Segments,Nodes);
+
+ /* Output the results */
+
+ printf("\nWrite Out Database Files\n========================\n\n");
+ fflush(stdout);
+
+ /* Write out the nodes */
+
+ SaveNodeList(Nodes,FileName(dirname,prefix,"nodes.mem"));
+
+ FreeNodeList(Nodes,0);
+
+ /* Write out the segments */
+
+ SaveSegmentList(Segments,FileName(dirname,prefix,"segments.mem"));
+
+ FreeSegmentList(Segments,0);
+
+ /* Write out the ways */
+
+ SaveWayList(Ways,FileName(dirname,prefix,"ways.mem"));
+
+ FreeWayList(Ways,0);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ 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: planetsplitter [--help]\n"
+ " [--dir=<dirname>] [--prefix=<name>]\n"
+ " [--slim] [--sort-ram-size=<size>]\n"
+ " [--tmpdir=<dirname>]\n"
+ " [--parse-only | --process-only]\n"
+ " [--max-iterations=<number>]\n"
+ " [--tagging=<filename>]\n"
+ " [<filename.osm> ...]\n");
+
+ if(detail)
+ fprintf(stderr,
+ "\n"
+ "--help Prints this information.\n"
+ "\n"
+ "--dir=<dirname> The directory containing the routing database.\n"
+ "--prefix=<name> The filename prefix for the routing database.\n"
+ "\n"
+ "--slim Use less RAM and more temporary files.\n"
+ "--sort-ram-size=<size> The amount of RAM (in MB) to use for data sorting\n"
+ " (defaults to 64MB with '--slim' or 256MB otherwise.)\n"
+ "--tmpdir=<dirname> 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=<number> The number of iterations for finding super-nodes.\n"
+ "\n"
+ "--tagging=<filename> The name of the XML file containing the tagging rules\n"
+ " (defaults to 'tagging.xml' with '--dirname' and\n"
+ " '--prefix' options).\n"
+ "\n"
+ "<filename.osm> ... The name(s) of the file(s) to process (by default\n"
+ " data is read from standard input).\n"
+ "\n"
+ "<transport> defaults to all but can be set to:\n"
+ "%s"
+ "\n"
+ "<highway> can be selected from:\n"
+ "%s"
+ "\n"
+ "<property> can be selected from:\n"
+ "%s",
+ TransportList(),HighwayList(),PropertyList());
+
+ exit(!detail);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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;i<nloaded_profiles;i++)
+ if(!strcmp(name,loaded_profiles[i]->name))
+ 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;i<nloaded_profiles;i++)
+ free(loaded_profiles[i]);
+ free(loaded_profiles);
+
+ nloaded_profiles=0;
+
+ return(1);
+ }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ Get the profile for a type of transport.
+
+ Profile *GetProfile Returns a pointer to the profile.
+
+ const char *name The name of the profile.
+ ++++++++++++++++++++++++++++++++++++++*/
+
+Profile *GetProfile(const char *name)
+{
+ int i;
+
+ for(i=0;i<nloaded_profiles;i++)
+ if(!strcmp(loaded_profiles[i]->name,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;i<Way_Count;i++)
+ {
+ if(profile->highway[i]<0)
+ profile->highway[i]=0;
+
+ if(profile->highway[i]>hmax)
+ hmax=profile->highway[i];
+ }
+
+ if(hmax==0)
+ return(1);
+
+ for(i=1;i<Way_Count;i++)
+ profile->highway[i]/=hmax;
+
+ /* Normalise the property preferences into the range 0 -> 2 */
+
+ for(i=1;i<Property_Count;i++)
+ {
+ if(profile->props_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;i<Way_Count;i++)
+ if(profile->speed[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;i<Property_Count;i++)
+ if(ways->props & 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;i<Way_Count;i++)
+ printf("Highway %-12s: %3d%%\n",HighwayName(i),(int)profile->highway[i]);
+
+ printf("\n");
+
+ for(i=1;i<Way_Count;i++)
+ if(profile->highway[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;i<Property_Count;i++)
+ printf("Highway property %-12s: %3d%%\n",PropertyName(i),(int)profile->props_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("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+ printf("\n");
+
+ printf("<routino-profiles xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"routino-profiles.xsd\">\n");
+ printf("\n");
+
+ for(j=0;j<nloaded_profiles;j++)
+ {
+ printf(" <profile name=\"%s\" transport=\"%s\">\n",loaded_profiles[j]->name,TransportName(loaded_profiles[j]->transport));
+
+ printf(" <speeds>\n");
+ for(i=1;i<Way_Count;i++)
+ printf(" <speed highway=\"%s\"%s kph=\"%d\" />\n",HighwayName(i),padding+3+strlen(HighwayName(i)),loaded_profiles[j]->speed[i]);
+ printf(" </speeds>\n");
+
+ printf(" <preferences>\n");
+ for(i=1;i<Way_Count;i++)
+ printf(" <preference highway=\"%s\"%s percent=\"%.0f\" />\n",HighwayName(i),padding+3+strlen(HighwayName(i)),loaded_profiles[j]->highway[i]);
+ printf(" </preferences>\n");
+
+ printf(" <properties>\n");
+ for(i=1;i<Property_Count;i++)
+ printf(" <property type=\"%s\"%s percent=\"%.0f\" />\n",PropertyName(i),padding+6+strlen(PropertyName(i)),loaded_profiles[j]->props_yes[i]);
+ printf(" </properties>\n");
+
+ printf(" <restrictions>\n");
+ printf(" <oneway obey=\"%d\" /> \n",loaded_profiles[j]->oneway);
+ printf(" <weight limit=\"%.1f\" />\n",weight_to_tonnes(loaded_profiles[j]->weight));
+ printf(" <height limit=\"%.1f\" />\n",height_to_metres(loaded_profiles[j]->height));
+ printf(" <width limit=\"%.1f\" />\n",width_to_metres(loaded_profiles[j]->width));
+ printf(" <length limit=\"%.1f\" />\n",length_to_metres(loaded_profiles[j]->length));
+ printf(" </restrictions>\n");
+
+ printf(" </profile>\n");
+ printf("\n");
+ }
+
+ printf("</routino-profiles>\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;j<nloaded_profiles;j++)
+ printf("%s%s: %d",j==1?"":", ",TransportName(loaded_profiles[j]->transport),j);
+ printf("},\n");
+ printf("\n");
+
+ printf(" // Highway types\n");
+ printf(" highways: {");
+ for(i=1;i<Way_Count;i++)
+ printf("%s%s: %d",i==1?"":", ",HighwayName(i),i);
+ printf("},\n");
+ printf("\n");
+
+ printf(" // Property types\n");
+ printf(" properties: {");
+ for(i=1;i<Property_Count;i++)
+ printf("%s%s: %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<Way_Count;i++)
+ {
+ printf(" %12s: {",HighwayName(i));
+ for(j=0;j<nloaded_profiles;j++)
+ printf("%s%s: %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<Way_Count;i++)
+ {
+ printf(" %12s: {",HighwayName(i));
+ for(j=0;j<nloaded_profiles;j++)
+ printf("%s%s: %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<Property_Count;i++)
+ {
+ printf(" %12s: {",PropertyName(i));
+ for(j=0;j<nloaded_profiles;j++)
+ printf("%s%s: %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<nloaded_profiles;j++)
+ printf("%s%s: %4d",j==1?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->oneway);
+ printf("},\n");
+ printf(" %12s: {","weight");
+ for(j=0;j<nloaded_profiles;j++)
+ printf("%s%s: %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<nloaded_profiles;j++)
+ printf("%s%s: %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<nloaded_profiles;j++)
+ printf("%s%s: %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<nloaded_profiles;j++)
+ printf("%s%s: %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");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ 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<nloaded_profiles;j++)
+ printf("%s%s => %d",j==1?"":", ",TransportName(loaded_profiles[j]->transport),j);
+ printf("},\n");
+ printf("\n");
+
+ printf(" # Highway types\n");
+ printf(" highways => {");
+ for(i=1;i<Way_Count;i++)
+ printf("%s%s => %d",i==1?"":", ",HighwayName(i),i);
+ printf("},\n");
+ printf("\n");
+
+ printf(" # Property types\n");
+ printf(" properties => {");
+ for(i=1;i<Property_Count;i++)
+ printf("%s%s => %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<Way_Count;i++)
+ {
+ printf(" %12s => {",HighwayName(i));
+ for(j=0;j<nloaded_profiles;j++)
+ printf("%s %s => %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<Way_Count;i++)
+ {
+ printf(" %12s => {",HighwayName(i));
+ for(j=0;j<nloaded_profiles;j++)
+ printf("%s %s => %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<Property_Count;i++)
+ {
+ printf(" %12s => {",PropertyName(i));
+ for(j=0;j<nloaded_profiles;j++)
+ printf("%s %s => %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<nloaded_profiles;j++)
+ printf("%s %s => %4d",j==1?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->oneway);
+ printf("},\n");
+ printf(" %12s => {","weight");
+ for(j=0;j<nloaded_profiles;j++)
+ printf("%s %s => %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<nloaded_profiles;j++)
+ printf("%s %s => %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<nloaded_profiles;j++)
+ printf("%s %s => %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<nloaded_profiles;j++)
+ printf("%s %s => %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");
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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]->sortby<queue->data[(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)<queue->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]->sortby<queue->data[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);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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;i<results->nbins;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;i<results->nbins;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;i<results->nbins;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]);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef RESULTS_H
+#define RESULTS_H /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#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;arg<argc;arg++)
+ {
+ if(!strcmp(argv[arg],"--help"))
+ print_usage(1);
+ else if(!strcmp(argv[arg],"--help-profile"))
+ help_profile=1;
+ else if(!strcmp(argv[arg],"--help-profile-xml"))
+ help_profile_xml=1;
+ else if(!strcmp(argv[arg],"--help-profile-json"))
+ help_profile_json=1;
+ else if(!strcmp(argv[arg],"--help-profile-perl"))
+ help_profile_pl=1;
+ else if(!strncmp(argv[arg],"--dir=",6))
+ dirname=&argv[arg][6];
+ else if(!strncmp(argv[arg],"--prefix=",9))
+ prefix=&argv[arg][9];
+ else if(!strncmp(argv[arg],"--profiles=",11))
+ profiles=&argv[arg][11];
+ else if(!strncmp(argv[arg],"--translations=",15))
+ translations=&argv[arg][15];
+ else if(!strcmp(argv[arg],"--exact-nodes-only"))
+ exactnodes=1;
+ else if(!strcmp(argv[arg],"--quiet"))
+ option_quiet=1;
+ else if(!strcmp(argv[arg],"--output-html"))
+ option_html=1;
+ else if(!strcmp(argv[arg],"--output-gpx-track"))
+ option_gpx_track=1;
+ else if(!strcmp(argv[arg],"--output-gpx-route"))
+ option_gpx_route=1;
+ else if(!strcmp(argv[arg],"--output-text"))
+ option_text=1;
+ else if(!strcmp(argv[arg],"--output-text-all"))
+ option_text_all=1;
+ else if(!strcmp(argv[arg],"--output-none"))
+ option_none=1;
+ else if(!strncmp(argv[arg],"--profile=",10))
+ profilename=&argv[arg][10];
+ else if(!strncmp(argv[arg],"--language=",11))
+ language=&argv[arg][11];
+ else if(!strncmp(argv[arg],"--transport=",12))
+ {
+ transport=TransportType(&argv[arg][12]);
+
+ if(transport==Transport_None)
+ print_usage(0);
+ }
+ else
+ continue;
+
+ argv[arg]=NULL;
+ }
+
+ /* Load in the profiles */
+
+ if(transport==Transport_None)
+ transport=Transport_Motorcar;
+
+ if(profiles)
+ {
+ if(!ExistsFile(profiles))
+ {
+ fprintf(stderr,"Error: The '--profiles' option specifies a file that does not exist.\n");
+ return(1);
+ }
+ }
+ else
+ {
+ if(ExistsFile(FileName(dirname,prefix,"profiles.xml")))
+ profiles=FileName(dirname,prefix,"profiles.xml");
+ else
+ {
+ fprintf(stderr,"Error: The '--profiles' option was not used and the default 'profiles.xml' does not exist.\n");
+ return(1);
+ }
+ }
+
+ if(profiles && ParseXMLProfiles(profiles))
+ {
+ fprintf(stderr,"Error: Cannot read the profiles in the file '%s'.\n",profiles);
+ return(1);
+ }
+
+ if(profilename)
+ {
+ profile=GetProfile(profilename);
+
+ if(!profile)
+ {
+ fprintf(stderr,"Error: Cannot find a profile called '%s' in '%s'.\n",profilename,profiles);
+ return(1);
+ }
+ }
+ else
+ profile=GetProfile(TransportName(transport));
+
+ if(!profile)
+ {
+ profile=(Profile*)calloc(1,sizeof(Profile));
+ profile->transport=transport;
+ }
+
+ /* Parse the other command line arguments */
+
+ for(arg=1;arg<argc;arg++)
+ {
+ if(!argv[arg])
+ continue;
+ else if(!strcmp(argv[arg],"--shortest"))
+ option_quickest=0;
+ else if(!strcmp(argv[arg],"--quickest"))
+ option_quickest=1;
+ else if(isdigit(argv[arg][0]) ||
+ ((argv[arg][0]=='-' || argv[arg][0]=='+') && isdigit(argv[arg][1])))
+ {
+ for(point=1;point<=NWAYPOINTS;point++)
+ if(point_used[point]!=3)
+ {
+ if(point_used[point]==0)
+ {
+ point_lon[point]=degrees_to_radians(atof(argv[arg]));
+ point_used[point]=1;
+ }
+ else /* if(point_used[point]==1) */
+ {
+ point_lat[point]=degrees_to_radians(atof(argv[arg]));
+ point_used[point]=3;
+ }
+ break;
+ }
+ }
+ else if(!strncmp(argv[arg],"--lon",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]&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(dist1<km_to_distance(MINSEGMENT) && dist2>km_to_distance(MINSEGMENT))
+ return(node1);
+
+ if(dist2<km_to_distance(MINSEGMENT) && dist1>km_to_distance(MINSEGMENT))
+ return(node2);
+
+ if(dist1<km_to_distance(MINSEGMENT) && dist2<km_to_distance(MINSEGMENT))
+ {
+ if(dist1<dist2)
+ return(node1);
+ else
+ return(node2);
+ }
+
+ /* Create the fake node */
+
+ fakenode=point|NODE_SUPER;
+
+ GetLatLong(nodes,node1,&lat1,&lon1);
+ GetLatLong(nodes,node2,&lat2,&lon2);
+
+ if(lat1>3 && 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=<dirname>] [--prefix=<name>]\n"
+ " [--profiles=<filename>] [--translations=<filename>]\n"
+ " [--exact-nodes-only]\n"
+ " [--quiet]\n"
+ " [--language=<lang>]\n"
+ " [--output-html]\n"
+ " [--output-gpx-track] [--output-gpx-route]\n"
+ " [--output-text] [--output-text-all]\n"
+ " [--output-none]\n"
+ " [--profile=<name>]\n"
+ " [--transport=<transport>]\n"
+ " [--shortest | --quickest]\n"
+ " --lon1=<longitude> --lat1=<latitude>\n"
+ " --lon2=<longitude> --lon2=<latitude>\n"
+ " [ ... --lon99=<longitude> --lon99=<latitude>]\n"
+ " [--highway-<highway>=<preference> ...]\n"
+ " [--speed-<highway>=<speed> ...]\n"
+ " [--property-<property>=<preference> ...]\n"
+ " [--oneway=(0|1)]\n"
+ " [--weight=<weight>]\n"
+ " [--height=<height>] [--width=<width>] [--length=<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=<dirname> The directory containing the routing database.\n"
+ "--prefix=<name> The filename prefix for the routing database.\n"
+ "--profiles=<filename> The name of the profiles (defaults to 'profiles.xml'\n"
+ " with '--dirname' and '--prefix' options).\n"
+ "--translations=<fname> 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=<lang> 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=<name> Select the loaded profile with this name.\n"
+ "--transport=<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<n>=<longitude> Specify the longitude of the n'th waypoint.\n"
+ "--lat<n>=<latitude> Specify the latitude of the n'th waypoint.\n"
+ "\n"
+ " Routing preference options\n"
+ "--highway-<highway>=<preference> * preference for highway type (%%).\n"
+ "--speed-<highway>=<speed> * speed for highway type (km/h).\n"
+ "--property-<property>=<preference> * preference for proprty type (%%).\n"
+ "--oneway=(0|1) * oneway streets are to be obeyed.\n"
+ "--weight=<weight> * maximum weight limit (tonnes).\n"
+ "--height=<height> * maximum height limit (metres).\n"
+ "--width=<width> * maximum width limit (metres).\n"
+ "--length=<length> * maximum length limit (metres).\n"
+ "\n"
+ "<transport> defaults to motorcar but can be set to:\n"
+ "%s"
+ "\n"
+ "<highway> can be selected from:\n"
+ "%s"
+ "\n"
+ "<property> can be selected from:\n"
+ "%s",
+ TransportList(),HighwayList(),PropertyList());
+
+ exit(!detail);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+#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);
+ }
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef SEGMENTS_H
+#define SEGMENTS_H /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#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_id1<b_id1)
+ return(-1);
+ else if(a_id1>b_id1)
+ return(1);
+ else /* if(a_id1==b_id1) */
+ {
+ node_t a_id2=a->node2;
+ node_t b_id2=b->node2;
+
+ if(a_id2<b_id2)
+ return(-1);
+ else if(a_id2>b_id2)
+ return(1);
+ else
+ {
+ distance_t a_distance=a->distance;
+ distance_t b_distance=b->distance;
+
+ if(a_distance<b_distance)
+ return(-1);
+ else if(a_distance>b_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(end<start) /* There are no nodes */
+ return(NO_SEGMENT);
+ else if(node<segmentsx->idata[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]<node) /* Mid point is too low */
+ start=mid;
+ else if(segmentsx->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;i<nodesx->number;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(index<segmentsx->firstnode[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 (node1<node2).
+
+ SegmentsX* segmentsx The set of segments to process.
+ ++++++++++++++++++++++++++++++++++++++*/
+
+void RotateSegments(SegmentsX* segmentsx)
+{
+ int index=0,rotated=0;
+ int fd;
+ SegmentX segmentx;
+
+ /* Check the start conditions */
+
+ assert(!segmentsx->idata); /* 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;i<nodesx->number;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(previndex<index)
+ {
+ int offset=previndex-firstindex;
+
+ if(DISTFLAG(segmentx.distance)==DISTFLAG(prevsegmentx[offset].distance))
+ {
+ WayX *wayx1=LookupWayX(waysx,prevsegmentx[offset].way,1);
+ WayX *wayx2=LookupWayX(waysx, segmentx .way,2);
+
+ if(!WaysCompare(&wayx1->way,&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(good<segmentsx->firstnode[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;i<segmentsx->number;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;i<nodesx->number;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;i<segmentsx->number;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;i<segments->number;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);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef SEGMENTSX_H
+#define SEGMENTSX_H /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#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;i<nitems;i++)
+ {
+ datap[i]=data+i*itemsize;
+
+ if(ReadFile(fd_in,datap[i],itemsize))
+ {
+ more=0;
+ break;
+ }
+
+ total++;
+ }
+
+ n=i;
+
+ 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;i<n;i++)
+ {
+ if(!buildindex || buildindex(datap[i],count))
+ {
+ WriteFile(fd_out,datap[i],itemsize);
+ count++;
+ }
+ }
+
+ goto tidy_and_exit;
+ }
+
+ /* Create a temporary file and write the result */
+
+ sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,nfiles);
+
+ fd=OpenFile(filename);
+
+ for(i=0;i<n;i++)
+ WriteFile(fd,datap[i],itemsize);
+
+ CloseFile(fd);
+
+ nfiles++;
+ }
+ while(more);
+
+ /* Shortcut if only one file (unlucky for us there must have been exactly
+ nitems, lucky for us we still have the data in RAM) */
+
+ if(nfiles==1)
+ {
+ for(i=0;i<nitems;i++)
+ {
+ if(!buildindex || buildindex(datap[i],count))
+ {
+ WriteFile(fd_out,datap[i],itemsize);
+ count++;
+ }
+ }
+
+ DeleteFile(filename);
+
+ goto tidy_and_exit;
+ }
+
+ /* Check that number of files is less than file size */
+
+ assert(nfiles<nitems);
+
+ /* Open all of the temporary files */
+
+ fds=(int*)malloc(nfiles*sizeof(int));
+
+ for(i=0;i<nfiles;i++)
+ {
+ sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,i);
+
+ fds[i]=ReOpenFile(filename);
+
+ DeleteFile(filename);
+ }
+
+ /* Perform an n-way merge using a binary heap */
+
+ heap=(int*)malloc(nfiles*sizeof(int));
+
+ /* Fill the heap to start with */
+
+ for(i=0;i<nfiles;i++)
+ {
+ int index;
+
+ datap[i]=data+i*itemsize;
+
+ ReadFile(fds[i],datap[i],itemsize);
+
+ heap[i]=i;
+
+ index=i;
+
+ /* Bubble up the new value */
+
+ while(index>0 &&
+ 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)<ndata &&
+ (compare(datap[heap[index]],datap[heap[2*index+1]])>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;i<nfiles;i++)
+ CloseFile(fds[i]);
+ free(fds);
+ }
+
+ if(heap)
+ free(heap);
+
+ free(data);
+ free(datap);
+ free(filename);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ A function to sort the contents of a file of variable length objects (each
+ preceded by its length in 2 bytes) 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).
+
+ 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_vary(int fd_in,int fd_out,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;
+ FILESORT_VARINT nextitemsize,largestitemsize=0;
+ void *data=NULL,**datap=NULL;
+ char *filename;
+ int i,more=1;
+
+ /* Allocate the RAM buffer and other bits */
+
+ data=malloc(option_filesort_ramsize);
+
+ filename=(char*)malloc(strlen(option_tmpdirname)+24);
+
+ /* Loop around, fill the buffer, sort the data and write a temporary file */
+
+ if(ReadFile(fd_in,&nextitemsize,FILESORT_VARSIZE)) /* Always have the next item size known in advance */
+ goto tidy_and_exit;
+
+ do
+ {
+ int fd,n=0;
+ size_t ramused=FILESORT_VARALIGN-FILESORT_VARSIZE;
+
+ datap=data+option_filesort_ramsize;
+
+ /* Read in the data and create pointers */
+
+ while((ramused+FILESORT_VARSIZE+nextitemsize)<=((void*)datap-sizeof(void*)-data))
+ {
+ FILESORT_VARINT itemsize=nextitemsize;
+
+ if(itemsize>largestitemsize)
+ 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;i<n;i++)
+ {
+ if(!buildindex || buildindex(datap[i],count))
+ {
+ FILESORT_VARINT itemsize=*(FILESORT_VARINT*)(datap[i]-FILESORT_VARSIZE);
+
+ WriteFile(fd_out,datap[i]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE);
+ count++;
+ }
+ }
+
+ goto tidy_and_exit;
+ }
+
+ /* Create a temporary file and write the result */
+
+ sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,nfiles);
+
+ fd=OpenFile(filename);
+
+ for(i=0;i<n;i++)
+ {
+ FILESORT_VARINT itemsize=*(FILESORT_VARINT*)(datap[i]-FILESORT_VARSIZE);
+
+ WriteFile(fd,datap[i]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE);
+ }
+
+ CloseFile(fd);
+
+ nfiles++;
+ }
+ while(more);
+
+ /* Check that number of files is less than file size */
+
+ largestitemsize=FILESORT_VARALIGN*(1+(largestitemsize+FILESORT_VARALIGN-FILESORT_VARSIZE)/FILESORT_VARALIGN);
+
+ assert(nfiles<((option_filesort_ramsize-nfiles*sizeof(void*))/largestitemsize));
+
+ /* Open all of the temporary files */
+
+ fds=(int*)malloc(nfiles*sizeof(int));
+
+ for(i=0;i<nfiles;i++)
+ {
+ sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,i);
+
+ fds[i]=ReOpenFile(filename);
+
+ DeleteFile(filename);
+ }
+
+ /* Perform an n-way merge using a binary heap */
+
+ heap=(int*)malloc(nfiles*sizeof(int));
+
+ datap=data+option_filesort_ramsize-nfiles*sizeof(void*);
+
+ /* Fill the heap to start with */
+
+ for(i=0;i<nfiles;i++)
+ {
+ int index;
+ FILESORT_VARINT itemsize;
+
+ datap[i]=data+FILESORT_VARALIGN-FILESORT_VARSIZE+i*largestitemsize;
+
+ ReadFile(fds[i],&itemsize,FILESORT_VARSIZE);
+
+ *(FILESORT_VARINT*)(datap[i]-FILESORT_VARSIZE)=itemsize;
+
+ ReadFile(fds[i],datap[i],itemsize);
+
+ heap[i]=i;
+
+ index=i;
+
+ /* Bubble up the new value */
+
+ while(index>0 &&
+ 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)<ndata &&
+ (compare(datap[heap[index]],datap[heap[2*index+1]])>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;i<nfiles;i++)
+ CloseFile(fds[i]);
+ free(fds);
+ }
+
+ if(heap)
+ free(heap);
+
+ free(data);
+ free(filename);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ A function to sort an array of pointers efficiently.
+
+ The data is sorted using a "Heap sort" http://en.wikipedia.org/wiki/Heapsort,
+ in particular an this good because it can operate in-place and doesn't
+ allocate more memory like using qsort() does.
+
+ void **datap A pointer to the array of pointers to sort.
+
+ size_t nitems The number of items of data to sort.
+
+ int(*compare)(const void *, const void *) The comparison function (identical to qsort if the
+ data to be sorted was an array of things not pointers).
+ ++++++++++++++++++++++++++++++++++++++*/
+
+void heapsort(void **datap,size_t nitems,int(*compare)(const void*, const void*))
+{
+ int i;
+
+ /* Fill the heap by pretending to insert the data that is already there */
+
+ for(i=1;i<nitems;i++)
+ {
+ int index=i;
+
+ /* Bubble up the new value (upside-down, put largest at top) */
+
+ while(index>0 &&
+ 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)<i &&
+ (compare(datap[index],datap[2*index+1])<0 || /* reversed compared to filesort() above */
+ compare(datap[index],datap[2*index+2])<0)) /* reversed compared to filesort() above */
+ {
+ int newindex;
+ void *temp;
+
+ if(compare(datap[2*index+1],datap[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;
+ }
+ }
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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;i<nodesx->number;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;i<nodesx->number;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;i<segmentsx->number;i++)
+ {
+ int super=0;
+ SegmentX *segmentx=LookupSegmentX(segmentsx,i,1);
+
+ while(j<supersegmentsx->number)
+ {
+ 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_distance<result2->score)
+ {
+ 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);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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;i<tags->ntags;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;i<tags->ntags;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;i<rules->nrules;i++)
+ {
+ if(rules->rules[i].k && rules->rules[i].v)
+ {
+ for(j=0;j<tags->ntags;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;j<tags->ntags;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;j<tags->ntags;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;j<tags->ntags;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;i<rule->nactions;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);
+ }
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#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;i<result->ntags;i++)
+ {
+ printf(" <tag");
+ printf(" k=\"%s\"",ParseXML_Encode_Safe_XML(result->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;i<result->ntags;i++)
+ {
+ printf(" <tag");
+ printf(" k=\"%s\"",ParseXML_Encode_Safe_XML(result->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;i<result->ntags;i++)
+ {
+ printf(" <tag");
+ printf(" k=\"%s\"",ParseXML_Encode_Safe_XML(result->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("<?%s",_tag_);
+ if(version) printf(" version=\"%s\"",ParseXML_Encode_Safe_XML(version));
+ if(encoding) printf(" encoding=\"%s\"",ParseXML_Encode_Safe_XML(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<argc;arg++)
+ {
+ if(!strcmp(argv[arg],"--help"))
+ print_usage(1);
+ else if(!strncmp(argv[arg],"--tagging=",10))
+ tagging=&argv[arg][10];
+ else if(argv[arg][0]=='-' && argv[arg][1]=='-')
+ print_usage(0);
+ else if(filename)
+ print_usage(0);
+ else
+ filename=argv[arg];
+ }
+
+ /* Check the specified command line options */
+
+ if(tagging && ExistsFile(tagging))
+ ;
+ else if(!tagging && ExistsFile("tagging.xml"))
+ tagging="tagging.xml";
+
+ if(tagging && ParseXMLTaggingRules(tagging))
+ {
+ fprintf(stderr,"Error: Cannot read the tagging rules in the file '%s'.\n",tagging);
+ return(1);
+ }
+
+ if(!tagging)
+ {
+ fprintf(stderr,"Error: Cannot run without reading some tagging rules.\n");
+ return(1);
+ }
+
+ if(filename)
+ {
+ file=fopen(filename,"rb");
+
+ if(!file)
+ {
+ fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",argv[arg],strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+ else
+ file=stdin;
+
+ /* Parse the file */
+
+ fprintf(stderr,"\rReading: Lines=0 Nodes=0 Ways=0 Relations=0");
+
+ retval=ParseXML(file,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE);
+
+ fprintf(stderr,"\rRead: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld \n",ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+ /* Tidy up */
+
+ if(filename)
+ fclose(file);
+
+ return(retval);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ 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: tagmodifier [--help]\n"
+ " [--tagging=<filename>]\n"
+ " [<filename.osm>]\n");
+
+ if(detail)
+ fprintf(stderr,
+ "\n"
+ "--help Prints this information.\n"
+ "\n"
+ "--tagging=<filename> The name of the XML file containing the tagging rules\n"
+ " (defaults to 'tagging.xml' in current directory).\n"
+ "\n"
+ "<filename.osm> The name of the file to process (by default data is\n"
+ " read from standard input).\n");
+
+ exit(!detail);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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="<span class='w'>Waypoint</span>";
+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("<span class='w'>")+sizeof("</span>"));
+ sprintf(translate_html_waypoint,"<span class='w'>%s</span>",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("<span class='b'>")+sizeof("</span>"));
+ sprintf(translate_html_start[1],text,"%s","<span class='b'>%s</span>");
+ }
+
+ 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("<span class='b'>")+2*sizeof("</span>"));
+ sprintf(translate_html_node[1],text,"%s","<span class='t'>%s</span>","<span class='b'>%s</span>");
+ }
+
+ 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("<span class='b'>")+2*sizeof("</span>"));
+
+ p=text;
+ q=translate_html_segment[1];
+
+ while(*p!='%' && *(p+1)!='s')
+ *q++=*p++;
+
+ p+=2;
+ strcpy(q,"<span class='h'>%s</span>"); q+=sizeof("<span class='h'>%s</span>")-1;
+
+ while(*p!='%')
+ *q++=*p++;
+
+ strcpy(q,"<span class='d'>"); q+=sizeof("<span class='d'>")-1;
+
+ strcpy(q,p);
+ strcat(q,"</span>");
+ }
+
+ 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);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <string.h>
+
+#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"
+ ;
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef TYPES_H
+#define TYPES_H /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+#include <math.h>
+
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef TYPESX_H
+#define TYPESX_H /*+ To stop multiple inclusions. +*/
+
+
+#include <stdint.h>
+
+
+/* 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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 || (lat<LatMin || lat>LatMax || lon<LonMin || lon>LonMax))
+ 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]->type<Way_Track)
+ count++;
+ }
+
+ segment=NextSegment(OSMSegments,segment,node);
+ }
+ while(segment);
+
+ /* Nodes with only one limit are not interesting */
+
+ if(count==1)
+ return;
+
+ /* Nodes with all segments the same limit is not interesting */
+
+ same=0;
+ for(j=0;j<count;j++)
+ if(limits[0]==limits[j])
+ same++;
+
+ if(same==count)
+ return;
+
+ /* Display the interesting speed limits */
+
+ printf("%.6f %.6f\n",radians_to_degrees(latitude),radians_to_degrees(longitude));
+
+ for(i=0;i<count;i++)
+ {
+ same=0;
+ for(j=0;j<count;j++)
+ if(limits[i]==limits[j])
+ same++;
+
+ if(count==2 || same!=(count-1))
+ {
+ double lat,lon;
+
+ GetLatLong(OSMNodes,OtherNode(segments[i],node),&lat,&lon);
+
+ switch(limit_type)
+ {
+ case SPEED_LIMIT:
+ printf("%.6f %.6f %d\n",radians_to_degrees(lat),radians_to_degrees(lon),speed_to_kph(limits[i]));
+ break;
+ case WEIGHT_LIMIT:
+ printf("%.6f %.6f %.1f\n",radians_to_degrees(lat),radians_to_degrees(lon),weight_to_tonnes(limits[i]));
+ break;
+ case HEIGHT_LIMIT:
+ printf("%.6f %.6f %.1f\n",radians_to_degrees(lat),radians_to_degrees(lon),height_to_metres(limits[i]));
+ break;
+ case WIDTH_LIMIT:
+ printf("%.6f %.6f %.1f\n",radians_to_degrees(lat),radians_to_degrees(lon),width_to_metres(limits[i]));
+ break;
+ case LENGTH_LIMIT:
+ printf("%.6f %.6f %.1f\n",radians_to_degrees(lat),radians_to_degrees(lon),length_to_metres(limits[i]));
+ break;
+ }
+ }
+ }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ A function to iterate through all nodes and call a callback function for each one.
+
+ Nodes *nodes The list of nodes to process.
+
+ callback_t callback The callback function for each node.
+ ++++++++++++++++++++++++++++++++++++++*/
+
+static void find_all_nodes(Nodes *nodes,callback_t callback)
+{
+ int32_t latminbin=latlong_to_bin(radians_to_latlong(LatMin))-nodes->latzero;
+ 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];node<nodes->offsets[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 && lat<LatMax && lon>LonMin && lon<LonMax)
+ (*callback)(node,lat,lon);
+ }
+ }
+}
--- /dev/null
+/***************************************
+ $Header: /home/amb/routino/src/RCS/visualiser.h,v 1.2 2009/07/09 17:31:56 amb Exp $
+
+ Header file for visualiser 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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+
+#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);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef WAYS_H
+#define WAYS_H /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#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 */
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#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(position<size)
+ {
+ FILESORT_VARINT waysize;
+
+ SeekFile(waysx->fd,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;i<waysx->number;i++)
+ {
+ WayX wayx;
+ FILESORT_VARINT size;
+
+ ReadFile(waysx->fd,&size,FILESORT_VARSIZE);
+
+ if(namelen[nnames%2]<size)
+ names[nnames%2]=(char*)realloc((void*)names[nnames%2],namelen[nnames%2]=size);
+
+ ReadFile(waysx->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_id<b_id)
+ return(-1);
+ else if(a_id>b_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(end<start) /* There are no ways */
+ return(NO_WAY);
+ else if(id<waysx->idata[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]<id) /* Mid point is too low */
+ start=mid+1;
+ else if(waysx->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;i<waysx->number;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(position<waysx->nlength)
+ {
+ 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);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef WAYSX_H
+#define WAYSX_H /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#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 */
--- /dev/null
+# $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 <http://www.gnu.org/licenses/>.
+#
+
+# 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 :
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1="value1 & value2 < ŀ">
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1="value1 & value2 &tl;  ">
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ <![[CDATA <level1> ]]>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- bad comment --->
+
+<test>
+
+ <level1>
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1="value1 & value2">
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1="value1 < value2">
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1="value1 > value2">
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ </level2>
+ </level1>
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ </level2>
+ </ level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ </level2>
+ < /level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ </level2>
+ </level1 >
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ </level2>
+ </level1 attr1="value">
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1='value1 & value2'>
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1='value1 < value2'>
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1='value1 > value2'>
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ < level1>
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1=value>
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1= "value">
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1 ="value">
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level2>
+ <level1>
+ </level1>
+ </level2>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ </level2>
+ </level2>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attribute="value">
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ </level1>
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ <
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ >
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<? xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" >
+
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<!-- good comment -->
+
+<test>
+
+ <level1>
+ <level2>
+ </level2>
+ </level1>
+
+</test>
+
+<?xml version="1.0" encoding="utf-8" ?>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+ <level1 attr1="value1 & value2 <  ">
+ <level2>
+ <![CDATA[ <angle brackets> ]]>
+ </level2>
+ </level1>
+
+</test>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- ============================================================
+ An XML Schema Definition for a test XML file
+ ============================================================
+ 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:element name="test" type="schemaType"/>
+
+ <!-- The first level element -->
+
+ <xsd:complexType name="schemaType">
+ <xsd:sequence>
+ <xsd:element name="level1" type="level1Type"/>
+ </xsd:sequence>
+ <xsd:attribute name="attr1" type="xsd:string"/>
+ <xsd:attribute name="attr2" type="xsd:string"/>
+ </xsd:complexType>
+
+ <!-- The second level element -->
+
+ <xsd:complexType name="level1Type">
+ <xsd:sequence>
+ <xsd:element name="level2" type="level2Type" minOccurs="0"/>
+ </xsd:sequence>
+ <xsd:attribute name="attr1" type="xsd:string"/>
+ </xsd:complexType>
+
+</xsd:schema>
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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;i<ntagsx;i++)
+ if(!strcmp(type,tagsx[i]->type) && !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;i<ntagsx;i++)
+ if(!strcmp(tagsx[i]->type,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;i<ntagsx;i++)
+ if(!strcmp(tagsx[i]->type,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;i<ntagsx;i++)
+ {
+ for(j=0;j<tagsx[i]->nsubtagsx;j++)
+ {
+ for(k=0;k<ntagsx;k++)
+ if(tagsx[i]->subtagsx[j]==tagsx[k])
+ break;
+
+ if(i<k)
+ {
+ xmltagx *temp=tagsx[i];
+
+ tagsx[i]=tagsx[k];
+
+ tagsx[k]=temp;
+
+ goto sorttags;
+ }
+ }
+ }
+
+ /* Print the header */
+
+ printf("/***************************************\n");
+ printf(" An automatically generated skeleton XML parser.\n");
+ printf("\n");
+ printf(" Automatically generated by xsd-to-xmlparser.\n");
+ printf(" ***************************************/\n");
+ printf("\n");
+ printf("\n");
+ printf("#include <stdio.h>\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;j<tagsx[i]->nattributes;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;i<ntagsx;i++)
+ {
+ printf("\n");
+ printf("/*+ The %s type tag. +*/\n",tagsx[i]->type);
+ printf("static xmltag %s_tag=\n",safe(tagsx[i]->type));
+ printf(" {\"%s\",\n",tagsx[i]->name);
+
+ printf(" %d, {",tagsx[i]->nattributes);
+ for(j=0;j<tagsx[i]->nattributes;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;j<tagsx[i]->nsubtagsx;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;i<ntagsx;i++)
+ {
+ printf("\n");
+ printf("\n");
+ printf("/*++++++++++++++++++++++++++++++++++++++\n");
+ if(i==(ntagsx-1)) /* XML tag */
+ printf(" The function that is called when the XML declaration is seen\n");
+ else
+ printf(" The function that is called when the %s XSD type is seen\n",tagsx[i]->type);
+ 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;j<tagsx[i]->nattributes;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;j<tagsx[i]->nattributes;j++)
+ printf(",const char *%s",safe(tagsx[i]->attributes[j]));
+
+ printf(")\n");
+
+ printf("{\n");
+
+ if(i==(ntagsx-1)) /* XML tag */
+ {
+ printf(" printf(\"<?%%s\",_tag_);\n");
+ for(j=0;j<tagsx[i]->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;j<tagsx[i]->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(\"%%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);
+}
--- /dev/null
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef XMLPARSE_H
+#define XMLPARSE_H /*+ To stop multiple inclusions. +*/
+
+#include <stdio.h>
+
+
+/*+ 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 */
--- /dev/null
+%{
+/***************************************
+ $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 <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#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 */
+
+"<!--" { BEGIN(COMMENT); }
+"<![CDATA[" { BEGIN(CDATA); }
+"<!DOCTYPE" { BEGIN(DOCTYPE); doctype_depth=0; }
+"</" { BEGIN(END_TAG1); }
+"<?" { BEGIN(XML_DECL_START); }
+"<" { BEGIN(TAG_START); }
+">" { return(LEX_ERROR_CLOSE); }
+[^<>]+ { }
+
+ /* Comments */
+
+<COMMENT>"--->" { return(LEX_ERROR_COMMENT); }
+<COMMENT>"-->" { BEGIN(INITIAL); }
+<COMMENT>"--"[^->]+ { }
+<COMMENT>[^-]+ { }
+<COMMENT>"-" { }
+
+ /* CDATA */
+
+<CDATA>"]]>" { BEGIN(INITIAL); }
+<CDATA>"]" { }
+<CDATA>[^]]+ { }
+
+ /* CDATA */
+
+<DOCTYPE>"<" { doctype_depth++; }
+<DOCTYPE>">" { if(doctype_depth==0) BEGIN(INITIAL); else doctype_depth--; }
+<DOCTYPE>[^<>]+ { }
+
+ /* XML Declaration start */
+
+<XML_DECL_START>{name} { BEGIN(XML_DECL); yylval=yytext; return(LEX_XML_DECL_BEGIN); }
+<XML_DECL_START>.|\n { return(LEX_ERROR_XML_DECL_START); }
+
+ /* Tag middle */
+
+<XML_DECL>"?>" { BEGIN(INITIAL); return(LEX_XML_DECL_FINISH); }
+<XML_DECL>{S}+ { }
+<XML_DECL>{name} { after_attr=XML_DECL; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); }
+<XML_DECL>.|\n { return(LEX_ERROR_XML_DECL); }
+
+ /* Any tag start */
+
+<TAG_START>{name} { BEGIN(TAG); yylval=yytext; return(LEX_TAG_BEGIN); }
+<TAG_START>.|\n { return(LEX_ERROR_TAG_START); }
+
+ /* End-tag start */
+
+<END_TAG1>{name} { BEGIN(END_TAG2); yylval=yytext; return(LEX_TAG_POP); }
+<END_TAG1>.|\n { return(LEX_ERROR_END_TAG); }
+
+<END_TAG2>">" { BEGIN(INITIAL); }
+<END_TAG2>.|\n { return(LEX_ERROR_END_TAG); }
+
+ /* Any tag middle */
+
+<TAG>"/>" { BEGIN(INITIAL); return(LEX_TAG_FINISH); }
+<TAG>">" { BEGIN(INITIAL); return(LEX_TAG_PUSH); }
+<TAG>{S}+ { }
+<TAG>{name} { after_attr=TAG; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); }
+<TAG>.|\n { return(LEX_ERROR_TAG); }
+
+ /* Attributes */
+
+<ATTR_KEY>= { BEGIN(ATTR_VAL); }
+<ATTR_KEY>.|\n { return(LEX_ERROR_ATTR); }
+
+<ATTR_VAL>\" { BEGIN(DQUOTED); reset_string; }
+<ATTR_VAL>\' { BEGIN(SQUOTED); reset_string; }
+<ATTR_VAL>.|\n { return(LEX_ERROR_ATTR); }
+
+ /* Quoted strings */
+
+<DQUOTED>\" { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); }
+<DQUOTED>{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);} } }
+<DQUOTED>{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);} } }
+<DQUOTED>[<>&] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
+<DQUOTED>[^<>&\"]+ { append_string(yytext); }
+
+<SQUOTED>\' { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); }
+<SQUOTED>{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);} } }
+<SQUOTED>{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);} } }
+<SQUOTED>[<>&] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
+<SQUOTED>[^<>&\']+ { append_string(yytext); }
+
+ /* End of file */
+
+<<EOF>> { 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;i<tag->nattributes;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 '</%s>' 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 '</%s>' seen but there was no start tag '<%s ...>'.\n",yylineno,yylval,yylval);
+ yychar=LEX_ERROR_NO_START;
+ }
+
+ for(i=0;i<tag->nattributes;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;i<tag->nattributes;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 '</%s>'.\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 '<?' seen not at start of XML declaration.\n",yylineno);
+ break;
+
+ case LEX_ERROR_TAG:
+ fprintf(stderr,"XML Parser: Error on line %d: invalid character seen inside tag '<%s...>'.\n",yylineno,tag->name);
+ break;
+
+ case LEX_ERROR_XML_DECL:
+ fprintf(stderr,"XML Parser: Error on line %d: invalid character seen inside XML declaration '<?%s...>'.\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<LEX_ERROR);
+
+ /* Delete the tagdata */
+
+ for(i=0;i<XMLPARSE_MAX_ATTRS;i++)
+ if(attributes[i])
+ free(attributes[i]);
+
+ if(stackdepth)
+ {
+ free(tag_stack);
+ free(tags_stack);
+ }
+
+ return(yychar);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ Return the current parser line number.
+
+ unsigned long ParseXML_LineNumber Returns the line number.
+ ++++++++++++++++++++++++++++++++++++++*/
+
+unsigned long ParseXML_LineNumber(void)
+{
+ return(yylineno);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+ Convert an XML entity reference into an ASCII string.
+
+ char *ParseXML_Decode_Entity_Ref Returns a pointer to the replacement decoded string.
+
+ const char *string The entity reference string.
+ ++++++++++++++++++++++++++++++++++++++*/
+
+char *ParseXML_Decode_Entity_Ref(const char *string)
+{
+ if(!strcmp(string,"&")) return("&");
+ if(!strcmp(string,"<")) return("<");
+ if(!strcmp(string,">")) return(">");
+ 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<len && string[i];i++)
+ if(string[i]=='<')
+ {
+ result[j++]='&';
+ result[j++]='l';
+ result[j++]='t';
+ result[j++]=';';
+ }
+ else if(string[i]=='>')
+ {
+ 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);
+}
--- /dev/null
+../doc/INSTALL.txt
\ No newline at end of file
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+# 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]
--- /dev/null
+##
+## 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.
+
+<FilesMatch .*\.pl$>
+ Order deny,allow
+ Deny from all
+</FilesMatch>
--- /dev/null
+#!/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 <http://www.gnu.org/licenses/>.
+#
+
+# 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,"<router.html.$lang");
+ }
+else
+ {
+ open(TEMPLATE,"<router.html");
+ }
+
+# Parse the template and fill in the parameters
+
+print header('text/html');
+
+while(<TEMPLATE>)
+ {
+ if(m%^<BODY.+>%)
+ {
+ 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%<input% && 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);
--- /dev/null
+#!/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 <http://www.gnu.org/licenses/>.
+#
+
+# 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,"<visualiser.html");
+
+# Parse the template and fill in the parameters
+
+print header('text/html');
+
+while(<TEMPLATE>)
+ {
+ if(m%^<BODY.+>%)
+ {
+ 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);
--- /dev/null
+#!/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 <http://www.gnu.org/licenses/>.
+#
+
+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;
+ }
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino redirect web page.
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Route Planner for OpenStreetMap Data</TITLE>
+<META http-equiv="refresh" content="1; URL=router.html">
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="../documentation/style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Route Planner for OpenStreetMap Data</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2><a href="router.html" title="Page Moved">Page Moved</a></h2>
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+/*
+// 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 <http://www.gnu.org/licenses/>.
+*/
+
+
+/*----------------------------------*/
+/* 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%;
+}
--- /dev/null
+/*
+// 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 <http://www.gnu.org/licenses/>.
+*/
+
+
+
+/*-------------*/
+/* 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;
+}
--- /dev/null
+/*
+// 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 <http://www.gnu.org/licenses/>.
+*/
+
+
+/*----------------------------------*/
+/* 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;
+}
--- /dev/null
+#!/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 <http://www.gnu.org/licenses/>.
+#
+
+# 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,"<noscript.template.html");
+
+# Run the router
+
+if($submit eq "shortest" || $submit eq "quickest")
+ {
+ ($router_uuid,$router_time,$router_result,$router_message)=RunRouter($submit,%fullparams);
+
+ $router_type=$submit;
+ $router_Type="Shortest" if($submit eq "shortest");
+ $router_Type="Quickest" if($submit eq "quickest");
+
+ if($format ne "form")
+ {
+ ReturnOutput($router_uuid,$submit,$format);
+ exit;
+ }
+ }
+
+# Generate the form output
+
+print header('text/html');
+
+# Parse the template and fill in the parameters
+
+while(<TEMPLATE>)
+ {
+ if (m%<input% && 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%<!-- custom-url -->%)
+ {
+ s%<!-- custom-url -->%$customurl%;
+
+ print if($submit);
+ }
+ elsif (m%<!-- result-start -->%)
+ {
+ $results_section=1;
+ }
+ elsif (m%<!-- result-finish -->%)
+ {
+ $results_section=0;
+ }
+ elsif ($results_section)
+ {
+ s%<!-- result-Type -->%$router_Type%;
+ s%<!-- result-type -->%$router_type%;
+ s%<!-- result-uuid -->%$router_uuid%;
+ s%<!-- result-time -->%$router_time%;
+ s%<!-- result-result -->%$router_result%;
+ s%<!-- result-message -->%$router_message%;
+
+ print if($router_uuid);
+ }
+ else
+ {
+ print;
+ }
+ }
+
+close(TEMPLATE);
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino non-Javascript redirect web page.
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Route Planner for OpenStreetMap Data (non-JavaScript)</TITLE>
+<META http-equiv="refresh" content="1; URL=noscript.cgi">
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="../documentation/style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Route Planner for OpenStreetMap Data (non-JavaScript)</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2><a href="noscript.cgi" title="Page Moved">Page Moved</a></h2>
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino non-Javascript web page.
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Route Planner for OpenStreetMap Data (non-JavaScript)</TITLE>
+<META name="keywords" content="openstreetmap routing route planner">
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<LINK href="../documentation/style.css" type="text/css" rel="stylesheet">
+</HEAD>
+
+<BODY>
+
+<!-- Header Start -->
+
+<div class="header" align="center">
+
+<h1>Routino : Route Planner for OpenStreetMap Data (non-JavaScript)</h1>
+
+<hr>
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2>Non Javascript Route Finder</h2>
+
+<form name="form" action="noscript.cgi" method="get">
+
+ <h3>Locations</h3>
+
+ 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.
+
+ <p>
+
+ <table class="noborder-left">
+ <tr>
+ <td><b>Waypoint 1:</b>
+ <td><input name="lon1" type="text" size=8 title="Waypoint 1 Longitude" class="right"><!-- lon1 --> E
+ <td><input name="lat1" type="text" size=8 title="Waypoint 1 Latitude" class="right"><!-- lat1 --> N
+ <tr>
+ <td><b>Waypoint 2:</b>
+ <td><input name="lon2" type="text" size=8 title="Waypoint 2 Longitude" class="right"><!-- lon2 --> E
+ <td><input name="lat2" type="text" size=8 title="Waypoint 2 Latitude" class="right"><!-- lat2 --> N
+ <tr>
+ <td><b>Waypoint 3:</b>
+ <td><input name="lon3" type="text" size=8 title="Waypoint 3 Longitude" class="right"><!-- lon3 --> E
+ <td><input name="lat3" type="text" size=8 title="Waypoint 3 Latitude" class="right"><!-- lat3 --> N
+ <tr>
+ <td><b>Waypoint 4:</b>
+ <td><input name="lon4" type="text" size=8 title="Waypoint 4 Longitude" class="right"><!-- lon4 --> E
+ <td><input name="lat4" type="text" size=8 title="Waypoint 4 Latitude" class="right"><!-- lat4 --> N
+ <tr>
+ <td><b>Waypoint 5:</b>
+ <td><input name="lon5" type="text" size=8 title="Waypoint 5 Longitude" class="right"><!-- lon5 --> E
+ <td><input name="lat5" type="text" size=8 title="Waypoint 5 Latitude" class="right"><!-- lat5 --> N
+ <tr>
+ <td><b>Waypoint 6:</b>
+ <td><input name="lon6" type="text" size=8 title="Waypoint 6 Longitude" class="right"><!-- lon6 --> E
+ <td><input name="lat6" type="text" size=8 title="Waypoint 6 Latitude" class="right"><!-- lat6 --> N
+ <tr>
+ <td><b>Waypoint 7:</b>
+ <td><input name="lon7" type="text" size=8 title="Waypoint 7 Longitude" class="right"><!-- lon7 --> E
+ <td><input name="lat7" type="text" size=8 title="Waypoint 7 Latitude" class="right"><!-- lat7 --> N
+ <tr>
+ <td><b>Waypoint 8:</b>
+ <td><input name="lon8" type="text" size=8 title="Waypoint 8 Longitude" class="right"><!-- lon8 --> E
+ <td><input name="lat8" type="text" size=8 title="Waypoint 8 Latitude" class="right"><!-- lat8 --> N
+ <tr>
+ <td><b>Waypoint 9:</b>
+ <td><input name="lon9" type="text" size=8 title="Waypoint 9 Longitude" class="right"><!-- lon9 --> E
+ <td><input name="lat9" type="text" size=8 title="Waypoint 9 Latitude" class="right"><!-- lat9 --> N
+ </table>
+
+ <p>
+
+ <h3>Transport Type</h3>
+
+ 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.
+
+ <p>
+
+ <table class="noborder-left">
+ <tr>
+ <td><a href="noscript.cgi?transport=foot" title="Foot profile" >Foot </a>
+ <td><input name="transport" type="radio" value="foot" ><!-- transport -->
+ <tr>
+ <td><a href="noscript.cgi?transport=horse" title="Horse profile" >Horse </a>
+ <td><input name="transport" type="radio" value="horse" ><!-- transport -->
+ <tr>
+ <td><a href="noscript.cgi?transport=wheelchair" title="Wheelchair profile">Wheelchair</a>
+ <td><input name="transport" type="radio" value="wheelchair"><!-- transport -->
+ <tr>
+ <td><a href="noscript.cgi?transport=bicycle" title="Bicycle profile" >Bicycle </a>
+ <td><input name="transport" type="radio" value="bicycle" ><!-- transport -->
+ <tr>
+ <td><a href="noscript.cgi?transport=moped" title="Moped profile" >Moped </a>
+ <td><input name="transport" type="radio" value="moped" ><!-- transport -->
+ <tr>
+ <td><a href="noscript.cgi?transport=motorbike" title="Motorbike profile" >Motorbike </a>
+ <td><input name="transport" type="radio" value="motorbike" ><!-- transport -->
+ <tr>
+ <td><a href="noscript.cgi?transport=motorcar" title="Motorcar profile" >Motorcar </a>
+ <td><input name="transport" type="radio" value="motorcar" ><!-- transport -->
+ <tr>
+ <td><a href="noscript.cgi?transport=goods" title="Goods profile" >Goods </a>
+ <td><input name="transport" type="radio" value="goods" ><!-- transport -->
+ <tr>
+ <td><a href="noscript.cgi?transport=hgv" title="HGV profile" >HGV </a>
+ <td><input name="transport" type="radio" value="hgv" ><!-- transport -->
+ <tr>
+ <td><a href="noscript.cgi?transport=psv" title="PSV profile" >PSV </a>
+ <td><input name="transport" type="radio" value="psv" ><!-- transport -->
+ </table>
+
+ <p>
+
+ <h3>Highway Preferences</h3>
+
+ 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.
+
+ <h3>Speed Limits</h3>
+
+ 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.
+
+ <p>
+
+ <table class="noborder-left">
+ <tr>
+ <th class="left">
+ <th class="left" colspan=2><b>Preference</b>
+ <th class="left" colspan=2><b>Speed Limit</b>
+ <tr>
+ <td class="left" >Motorway:
+ <td class="right" ><input name="highway-motorway" type="text" size=3 class="right"><!-- highway-motorway -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-motorway" type="text" size=3 class="right"><!-- speed-motorway -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Trunk:
+ <td class="right" ><input name="highway-trunk" type="text" size=3 class="right"><!-- highway-trunk -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-trunk" type="text" size=3 class="right"><!-- speed-trunk -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Primary:
+ <td class="right" ><input name="highway-primary" type="text" size=3 class="right"><!-- highway-primary -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-primary" type="text" size=3 class="right"><!-- speed-primary -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Secondary:
+ <td class="right" ><input name="highway-secondary" type="text" size=3 class="right"><!-- highway-secondary -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-secondary" type="text" size=3 class="right"><!-- speed-secondary -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Tertiary:
+ <td class="right" ><input name="highway-tertiary" type="text" size=3 class="right"><!-- highway-tertiary -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-tertiary" type="text" size=3 class="right"><!-- speed-tertiary -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Unclassified:
+ <td class="right" ><input name="highway-unclassified" type="text" size=3 class="right"><!-- highway-unclassified -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-unclassified" type="text" size=3 class="right"><!-- speed-unclassified -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Residential:
+ <td class="right" ><input name="highway-residential" type="text" size=3 class="right"><!-- highway-residential -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-residential" type="text" size=3 class="right"><!-- speed-residential -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Service:
+ <td class="right" ><input name="highway-service" type="text" size=3 class="right"><!-- highway-service -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-service" type="text" size=3 class="right"><!-- speed-service -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Track:
+ <td class="right" ><input name="highway-track" type="text" size=3 class="right"><!-- highway-track -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-track" type="text" size=3 class="right"><!-- speed-track -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Cycleway:
+ <td class="right" ><input name="highway-cycleway" type="text" size=3 class="right"><!-- highway-cycleway -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-cycleway" type="text" size=3 class="right"><!-- speed-cycleway -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Path:
+ <td class="right" ><input name="highway-path" type="text" size=3 class="right"><!-- highway-path -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-path" type="text" size=3 class="right"><!-- speed-path -->
+ <td class="left" >km/hr
+ <tr>
+ <td class="left" >Steps:
+ <td class="right" ><input name="highway-steps" type="text" size=3 class="right"><!-- highway-steps -->
+ <td class="left" >%
+ <td class="right" ><input name="speed-steps" type="text" size=3 class="right"><!-- speed-steps -->
+ <td class="left" >km/hr
+ </table>
+
+ <p>
+
+ <h3>Property Preferences</h3>
+
+ 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.
+
+ <p>
+
+ <table class="noborder-left">
+ <tr>
+ <th class="left">
+ <th class="left" colspan=2><b>Preference</b><br>
+ <tr>
+ <td class="left" >Paved:
+ <td class="right" ><input name="paved" type="text" size=3 class="right"><!-- property-paved -->
+ <td class="left" >%
+ <tr>
+ <td class="left" >Multiple Lanes:
+ <td class="right" ><input name="multilane" type="text" size=3 class="right"><!-- property-multilane -->
+ <td class="left" >%
+ <tr>
+ <td class="left" >Bridge:
+ <td class="right" ><input name="bridge" type="text" size=3 class="right"><!-- property-bridge -->
+ <td class="left" >%
+ <tr>
+ <td class="left" >Tunnel:
+ <td class="right" ><input name="tunnel" type="text" size=3 class="right"><!-- property-tunnel -->
+ <td class="left" >%
+ </table>
+
+ <p>
+
+ <h3>Other Restrictions</h3>
+
+ 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).
+
+ <p>
+
+ <table class="noborder-left">
+ <tr>
+ <td class="left" >Obey oneway:
+ <td class="right" ><input name="oneway" type="checkbox"><!-- oneway -->
+ <td class="left" >
+ <tr>
+ <td class="left" >Weight:
+ <td class="right" ><input name="weight" type="text" size=3 class="right"><!-- weight -->
+ <td class="left" >tonnes
+ <tr>
+ <td class="left" >Height:
+ <td class="right" ><input name="height" type="text" size=3 class="right"><!-- height -->
+ <td class="left" >metres
+ <tr>
+ <td class="left" >Width:
+ <td class="right" ><input name="width" type="text" size=3 class="right"><!-- width -->
+ <td class="left" >metres
+ <tr>
+ <td class="left" >Length:
+ <td class="right" ><input name="length" type="text" size=3 class="right"><!-- length -->
+ <td class="left" >metres
+ </table>
+
+ <p>
+
+<h3>Output Format</h3>
+
+ This allows for selection of the language of the generated output.
+
+ <p>
+
+ <table class="noborder-left">
+ <tr>
+ <td class="left">English (en)
+ <td class="left"><input name="language" type="radio" value="en" checked><!-- language -->
+ <tr>
+ <td class="left">German (de)
+ <td class="left"><input name="language" type="radio" value="de"><!-- language -->
+ </table>
+
+ <p>
+
+ This allows for selection of the format of the generated output.
+
+ <p>
+
+ <table class="noborder-left">
+ <tr>
+ <td class="left"><input name="format" type="radio" value="form" checked>This HTML format
+ <tr>
+ <td class="left"><input name="format" type="radio" value="html">HTML route instructions
+ <tr>
+ <td class="left"><input name="format" type="radio" value="gpx-track">GPX track file
+ <tr>
+ <td class="left"><input name="format" type="radio" value="gpx-route">GPX route file
+ <tr>
+ <td class="left"><input name="format" type="radio" value="text">Text file
+ <tr>
+ <td class="left"><input name="format" type="radio" value="text-all">Full text file
+ </table>
+
+ <p>
+
+ <h3>Calculate Route</h3>
+
+ <button type="submit" name="submit" value="shortest">Shortest</button>
+ <button type="submit" name="submit" value="quickest">Quickest</button>
+
+ <p>
+
+ <!-- result-start -->
+
+ <hr>
+
+ <p>
+
+ <table class="noborder-left">
+ <tr>
+ <th class="left" colspan=2><u><b><!-- result-Type --> Result</b></u>
+ <tr>
+ <td class="left" colspan=2><b><!-- result-message --></b>
+ <tr>
+ <td class="left" colspan=2><b><!-- result-result --></b>
+ <tr>
+ <td class="left">HTML file:
+ <td class="left"><a title="" target="new" href="results.cgi?uuid=<!-- result-uuid -->;type=<!-- result-type -->;format=html">Open</a>
+ <tr>
+ <td class="left">GPX track file:
+ <td class="left"><a title="" target="new" href="results.cgi?uuid=<!-- result-uuid -->;type=<!-- result-type -->;format=gpx-track">Open</a>
+ <tr>
+ <td class="left">GPX route file:
+ <td class="left"><a title="" target="new" href="results.cgi?uuid=<!-- result-uuid -->;type=<!-- result-type -->;format=gpx-route">Open</a>
+ <tr>
+ <td class="left">Text file:
+ <td class="left"><a title="" target="new" href="results.cgi?uuid=<!-- result-uuid -->;type=<!-- result-type -->;format=text">Open</a>
+ <tr>
+ <td class="left">Full text file:
+ <td class="left"><a title="" target="new" href="results.cgi?uuid=<!-- result-uuid -->;type=<!-- result-type -->;format=text-all">Open</a>
+ <tr>
+ <td class="left" colspan=2><i><!-- result-time --></i>
+ </table>
+
+ <p>
+
+ <!-- result-finish -->
+
+ <hr>
+
+ <p>
+
+ <h3>Create Link</h3>
+
+ <button type="submit" name="submit" value="link">Create Link</button>
+ <a title="" href="<!-- custom-url -->">Bookmarkable link with customised parameters</a>
+
+</form>
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+© Andrew M. Bishop = <amb "at" gedanken.demon.co.uk>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
--- /dev/null
+/*
+// 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 <http://www.gnu.org/licenses/>.
+*/
+
+
+/*-------------*/
+/* 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;
+}
--- /dev/null
+//
+// 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 <http://www.gnu.org/licenses/>.
+//
+
+
+//
+// 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";
+}
--- /dev/null
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+# 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;
--- /dev/null
+#!/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 <http://www.gnu.org/licenses/>.
+#
+
+# 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);
--- /dev/null
+#!/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 <http://www.gnu.org/licenses/>.
+#
+
+# 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";
+ }
--- /dev/null
+/*
+// 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 <http://www.gnu.org/licenses/>.
+*/
+
+
+/*--------------------------------*/
+/* 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 */
--- /dev/null
+router.html.en
\ No newline at end of file
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino router web page.
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Route Planner for OpenStreetMap Data</TITLE>
+<META name="keywords" content="openstreetmap routing route planner">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+
+<!-- OpenLayers Javascript library -->
+<script src="../openlayers/OpenLayers.js" type="text/javascript"></script>
+
+<!-- Page elements -->
+<script src="page-elements.js" type="text/javascript"></script>
+<link href="page-elements.css" type="text/css" rel="stylesheet">
+
+<!-- Router and visualiser shared features -->
+<link href="maplayout.css" type="text/css" rel="stylesheet">
+<!--[if IE 6]>
+ <link href="maplayout-ie6-bugfixes.css" type="text/css" rel="stylesheet">
+<![endif]-->
+<!--[if IE 7]>
+ <link href="maplayout-ie7-bugfixes.css" type="text/css" rel="stylesheet">
+<![endif]-->
+
+<!-- Router specific features -->
+<script src="router.js" type="text/javascript"></script>
+<link href="router.css" type="text/css" rel="stylesheet">
+
+</HEAD>
+<BODY onload="map_init('lat','lon','zoom');form_init();block_return_key();">
+
+<!-- Left hand side of window - data panel -->
+
+<div class="left_panel">
+
+ <div class="tab_box">
+ <span id="tab_options" onclick="tab_select('options');" class="tab_selected" title="Set routing options">Options</span>
+ <span id="tab_results" onclick="tab_select('results');" class="tab_unselected" title="See routing results">Results</span>
+ <span id="tab_data" onclick="tab_select('data');" class="tab_unselected" title="View database information">Data</span>
+ </div>
+
+ <div class="tab_content" id="tab_options_div">
+
+ <form name="form" id="form" action="router.cgi" method="get">
+ <div class="hideshow_box">
+ <span class="hideshow_title">Routino OpenStreetMap Router</span>
+ 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.
+ <div align="center">
+ <a target="other" href="http://www.routino.org/">Routino Website</a>
+ |
+ <a target="other" href="documentation/">Documentation</a>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_language_show" onclick="hideshow_show('language');" class="hideshow_show">Show</span>
+ <span id="hideshow_language_hide" onclick="hideshow_hide('language');" class="hideshow_hide">Hide</span>
+ <span class="hideshow_title">Language</span>
+
+ <!-- Note for translations: Only this HTML file needs to be translated, the Javascript has
+ no language specific information in it. Only the body text and title attributes should
+ be changed, the values passed to the JavaScript and the element names must not be changed.
+ The selection below changes the language option passed to the router and selects the
+ output language not the web page language, the links are for that. The router itself uses
+ the translations.xml file for the translated versions of the output. -->
+
+ <div id="hideshow_language_div" style="display: none;">
+ <table>
+ <tr>
+ <td><a href="router.html.en" title="English language web page">English</a> (en)
+ <td><input name="language" type="radio" value="en" onchange="formSetLanguage('en')" checked><!-- language -->
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_waypoint_show" onclick="hideshow_show('waypoint');" class="hideshow_hide">Show</span>
+ <span id="hideshow_waypoint_hide" onclick="hideshow_hide('waypoint');" class="hideshow_show">Hide</span>
+ <span class="hideshow_title">Waypoints</span>
+ <div id="hideshow_waypoint_div">
+ <table>
+ <tr id="point1">
+ <td>
+ <img name="waypoint1" src="icons/marker-1-grey.png" title="Waypoint 1 Position - (click to add/remove on map)" alt="Waypoint 1" onmousedown="markerToggleMap(1)">
+ <td>
+ <input name="lon1" type="text" size=7 title="Waypoint 1 Longitude" onchange="formSetCoords(1);"><!-- lon1 --> E
+ <td>
+ <input name="lat1" type="text" size=7 title="Waypoint 1 Latitude" onchange="formSetCoords(1);"><!-- lat1 --> N
+ <td>
+ <img alt="o" src="icons/waypoint-centre.png" title="Centre this waypoint on map" onmousedown="markerCentre(1);" >
+ <img alt="^" src="icons/waypoint-up.png" title="Move this waypoint up" onmousedown="markerMoveUp(1);" >
+ <img alt="+" src="icons/waypoint-add.png" title="Add waypoint after this one" onmousedown="markerAddAfter(1);"><br>
+ <img alt="~" src="icons/waypoint-home.png" title="Toggle as home location" onmousedown="markerHome(1);" >
+ <img alt="v" src="icons/waypoint-down.png" title="Move this waypoint down" onmousedown="markerMoveDown(1);">
+ <img alt="-" src="icons/waypoint-remove.png" title="Remove this waypoint" onmousedown="markerRemove(1);" >
+ <tr id="point2">
+ <td>
+ <img name="waypoint2" src="icons/marker-2-grey.png" title="Waypoint 2 Position - (click to add/remove on map)" alt="Waypoint 2" onmousedown="markerToggleMap(2)">
+ <td>
+ <input name="lon2" type="text" size=7 title="Waypoint 2 Longitude" onchange="formSetCoords(2);"><!-- lon2 --> E
+ <td>
+ <input name="lat2" type="text" size=7 title="Waypoint 2 Latitude" onchange="formSetCoords(2);"><!-- lat2 --> N
+ <td>
+ <img alt="o" src="icons/waypoint-centre.png" title="Centre this waypoint on map" onmousedown="markerCentre(2);">
+ <img alt="^" src="icons/waypoint-up.png" title="Move this waypoint up" onmousedown="markerMoveUp(2);" >
+ <img alt="+" src="icons/waypoint-add.png" title="Add waypoint after this one" onmousedown="markerAddAfter(2);"><br>
+ <img alt="~" src="icons/waypoint-home.png" title="Toggle as home location" onmousedown="markerHome(2);" >
+ <img alt="v" src="icons/waypoint-down.png" title="Move this waypoint down" onmousedown="markerMoveDown(2);">
+ <img alt="-" src="icons/waypoint-remove.png" title="Remove this waypoint" onmousedown="markerRemove(2);" >
+ <tr id="point3">
+ <td>
+ <img name="waypoint3" src="icons/marker-3-grey.png" title="Waypoint 3 Position - (click to add/remove on map)" alt="Waypoint 3" onmousedown="markerToggleMap(3)">
+ <td>
+ <input name="lon3" type="text" size=7 title="Waypoint 3 Longitude" onchange="formSetCoords(3);"><!-- lon3 --> E
+ <td>
+ <input name="lat3" type="text" size=7 title="Waypoint 3 Latitude" onchange="formSetCoords(3);"><!-- lat3 --> N
+ <td>
+ <img alt="o" src="icons/waypoint-centre.png" title="Centre this waypoint on map" onmousedown="markerCentre(3);">
+ <img alt="^" src="icons/waypoint-up.png" title="Move this waypoint up" onmousedown="markerMoveUp(3);" >
+ <img alt="+" src="icons/waypoint-add.png" title="Add waypoint after this one" onmousedown="markerAddAfter(3);"><br>
+ <img alt="~" src="icons/waypoint-home.png" title="Toggle as home location" onmousedown="markerHome(3);" >
+ <img alt="v" src="icons/waypoint-down.png" title="Move this waypoint down" onmousedown="markerMoveDown(3);">
+ <img alt="-" src="icons/waypoint-remove.png" title="Remove this waypoint" onmousedown="markerRemove(3);" >
+ <tr id="point4">
+ <td>
+ <img name="waypoint4" src="icons/marker-4-grey.png" title="Waypoint 4 Position - (click to add/remove on map)" alt="Waypoint 4" onmousedown="markerToggleMap(4)">
+ <td>
+ <input name="lon4" type="text" size=7 title="Waypoint 4 Longitude" onchange="formSetCoords(4);"><!-- lon4 --> E
+ <td>
+ <input name="lat4" type="text" size=7 title="Waypoint 4 Latitude" onchange="formSetCoords(4);"><!-- lat4 --> N
+ <td>
+ <img alt="o" src="icons/waypoint-centre.png" title="Centre this waypoint on map" onmousedown="markerCentre(4);">
+ <img alt="^" src="icons/waypoint-up.png" title="Move this waypoint up" onmousedown="markerMoveUp(4);" >
+ <img alt="+" src="icons/waypoint-add.png" title="Add waypoint after this one" onmousedown="markerAddAfter(4);"><br>
+ <img alt="~" src="icons/waypoint-home.png" title="Toggle as home location" onmousedown="markerHome(4);" >
+ <img alt="v" src="icons/waypoint-down.png" title="Move this waypoint down" onmousedown="markerMoveDown(4);">
+ <img alt="-" src="icons/waypoint-remove.png" title="Remove this waypoint" onmousedown="markerRemove(4);" >
+ <tr id="point5">
+ <td>
+ <img name="waypoint5" src="icons/marker-5-grey.png" title="Waypoint 5 Position - (click to add/remove on map)" alt="Waypoint 5" onmousedown="markerToggleMap(5)">
+ <td>
+ <input name="lon5" type="text" size=7 title="Waypoint 5 Longitude" onchange="formSetCoords(5);"><!-- lon5 --> E
+ <td>
+ <input name="lat5" type="text" size=7 title="Waypoint 5 Latitude" onchange="formSetCoords(5);"><!-- lat5 --> N
+ <td>
+ <img alt="o" src="icons/waypoint-centre.png" title="Centre this waypoint on map" onmousedown="markerCentre(5);">
+ <img alt="^" src="icons/waypoint-up.png" title="Move this waypoint up" onmousedown="markerMoveUp(5);" >
+ <img alt="+" src="icons/waypoint-add.png" title="Add waypoint after this one" onmousedown="markerAddAfter(5);"><br>
+ <img alt="~" src="icons/waypoint-home.png" title="Toggle as home location" onmousedown="markerHome(5);" >
+ <img alt="v" src="icons/waypoint-down.png" title="Move this waypoint down" onmousedown="markerMoveDown(5);">
+ <img alt="-" src="icons/waypoint-remove.png" title="Remove this waypoint" onmousedown="markerRemove(5);" >
+ <tr id="point6">
+ <td>
+ <img name="waypoint6" src="icons/marker-6-grey.png" title="Waypoint 6 Position - (click to add/remove on map)" alt="Waypoint 6" onmousedown="markerToggleMap(6)">
+ <td>
+ <input name="lon6" type="text" size=7 title="Waypoint 6 Longitude" onchange="formSetCoords(6);"><!-- lon6 --> E
+ <td>
+ <input name="lat6" type="text" size=7 title="Waypoint 6 Latitude" onchange="formSetCoords(6);"><!-- lat6 --> N
+ <td>
+ <img alt="o" src="icons/waypoint-centre.png" title="Centre this waypoint on map" onmousedown="markerCentre(6);">
+ <img alt="^" src="icons/waypoint-up.png" title="Move this waypoint up" onmousedown="markerMoveUp(6);" >
+ <img alt="+" src="icons/waypoint-add.png" title="Add waypoint after this one" onmousedown="markerAddAfter(6);"><br>
+ <img alt="~" src="icons/waypoint-home.png" title="Toggle as home location" onmousedown="markerHome(6);" >
+ <img alt="v" src="icons/waypoint-down.png" title="Move this waypoint down" onmousedown="markerMoveDown(6);">
+ <img alt="-" src="icons/waypoint-remove.png" title="Remove this waypoint" onmousedown="markerRemove(6);" >
+ <tr id="point7">
+ <td>
+ <img name="waypoint7" src="icons/marker-7-grey.png" title="Waypoint 7 Position - (click to add/remove on map)" alt="Waypoint 7" onmousedown="markerToggleMap(7)">
+ <td>
+ <input name="lon7" type="text" size=7 title="Waypoint 7 Longitude" onchange="formSetCoords(7);"><!-- lon7 --> E
+ <td>
+ <input name="lat7" type="text" size=7 title="Waypoint 7 Latitude" onchange="formSetCoords(7);"><!-- lat7 --> N
+ <td>
+ <img alt="o" src="icons/waypoint-centre.png" title="Centre this waypoint on map" onmousedown="markerCentre(7);">
+ <img alt="^" src="icons/waypoint-up.png" title="Move this waypoint up" onmousedown="markerMoveUp(7);" >
+ <img alt="+" src="icons/waypoint-add.png" title="Add waypoint after this one" onmousedown="markerAddAfter(7);"><br>
+ <img alt="~" src="icons/waypoint-home.png" title="Toggle as home location" onmousedown="markerHome(7);" >
+ <img alt="v" src="icons/waypoint-down.png" title="Move this waypoint down" onmousedown="markerMoveDown(7);">
+ <img alt="-" src="icons/waypoint-remove.png" title="Remove this waypoint" onmousedown="markerRemove(7);" >
+ <tr id="point8">
+ <td>
+ <img name="waypoint8" src="icons/marker-8-grey.png" title="Waypoint 8 Position - (click to add/remove on map)" alt="Waypoint 8" onmousedown="markerToggleMap(8)">
+ <td>
+ <input name="lon8" type="text" size=7 title="Waypoint 8 Longitude" onchange="formSetCoords(8);"><!-- lon8 --> E
+ <td>
+ <input name="lat8" type="text" size=7 title="Waypoint 8 Latitude" onchange="formSetCoords(8);"><!-- lat8 --> N
+ <td>
+ <img alt="o" src="icons/waypoint-centre.png" title="Centre this waypoint on map" onmousedown="markerCentre(8);">
+ <img alt="^" src="icons/waypoint-up.png" title="Move this waypoint up" onmousedown="markerMoveUp(8);" >
+ <img alt="+" src="icons/waypoint-add.png" title="Add waypoint after this one" onmousedown="markerAddAfter(8);"><br>
+ <img alt="~" src="icons/waypoint-home.png" title="Toggle as home location" onmousedown="markerHome(8);" >
+ <img alt="v" src="icons/waypoint-down.png" title="Move this waypoint down" onmousedown="markerMoveDown(8);">
+ <img alt="-" src="icons/waypoint-remove.png" title="Remove this waypoint" onmousedown="markerRemove(8);" >
+ <tr id="point9">
+ <td>
+ <img name="waypoint9" src="icons/marker-9-grey.png" title="Waypoint 9 Position - (click to add/remove on map)" alt="Waypoint 9" onmousedown="markerToggleMap(9)">
+ <td>
+ <input name="lon9" type="text" size=7 title="Waypoint 9 Longitude" onchange="formSetCoords(9);"><!-- lon9 --> E
+ <td>
+ <input name="lat9" type="text" size=7 title="Waypoint 9 Latitude" onchange="formSetCoords(9);"><!-- lat9 --> N
+ <td>
+ <img alt="o" src="icons/waypoint-centre.png" title="Centre this waypoint on map" onmousedown="markerCentre(9);">
+ <img alt="^" src="icons/waypoint-up.png" title="Move this waypoint up" onmousedown="markerMoveUp(9);" >
+ <img alt="+" src="icons/waypoint-add.png" title="Add waypoint after this one" onmousedown="markerAddAfter(9);"><br>
+ <img alt="~" src="icons/waypoint-home.png" title="Toggle as home location" onmousedown="markerHome(9);" >
+ <img alt="v" src="icons/waypoint-down.png" title="Move this waypoint down" onmousedown="markerMoveDown(9);">
+ <img alt="-" src="icons/waypoint-remove.png" title="Remove this waypoint" onmousedown="markerRemove(9);" >
+ <!-- Up to 99 markers can be included here in the HTML -->
+ <tr>
+ <td colspan="4" align="center"><input type="button" title="Reverse order of waypoints" value="Reverse waypoint order" onmousedown="markersReverse();">
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_transport_show" onclick="hideshow_show('transport');" class="hideshow_hide">Show</span>
+ <span id="hideshow_transport_hide" onclick="hideshow_hide('transport');" class="hideshow_show">Hide</span>
+ <span class="hideshow_title">Transport Type</span>
+ <div id="hideshow_transport_div">
+ <table>
+ <tr><td>Foot <td><input name="transport" type="radio" value="foot" onchange="formSetTransport('foot' )"><!-- transport -->
+ <tr><td>Horse <td><input name="transport" type="radio" value="horse" onchange="formSetTransport('horse' )"><!-- transport -->
+ <tr><td>Wheelchair<td><input name="transport" type="radio" value="wheelchair" onchange="formSetTransport('wheelchair')"><!-- transport -->
+ <tr><td>Bicycle <td><input name="transport" type="radio" value="bicycle" onchange="formSetTransport('bicycle' )"><!-- transport -->
+ <tr><td>Moped <td><input name="transport" type="radio" value="moped" onchange="formSetTransport('moped' )"><!-- transport -->
+ <tr><td>Motorbike <td><input name="transport" type="radio" value="motorbike" onchange="formSetTransport('motorbike' )"><!-- transport -->
+ <tr><td>Motorcar <td><input name="transport" type="radio" value="motorcar" onchange="formSetTransport('motorcar' )"><!-- transport -->
+ <tr><td>Goods <td><input name="transport" type="radio" value="goods" onchange="formSetTransport('goods' )"><!-- transport -->
+ <tr><td>HGV <td><input name="transport" type="radio" value="hgv" onchange="formSetTransport('hgv' )"><!-- transport -->
+ <tr><td>PSV <td><input name="transport" type="radio" value="psv" onchange="formSetTransport('psv' )"><!-- transport -->
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_highway_show" onclick="hideshow_show('highway');" class="hideshow_show">Show</span>
+ <span id="hideshow_highway_hide" onclick="hideshow_hide('highway');" class="hideshow_hide">Hide</span>
+ <span class="hideshow_title">Highway Preferences</span>
+ <div id="hideshow_highway_div" style="display: none;">
+ <table>
+ <tr><td>Motorway: <td><input name="highway-motorway" type="text" size=3 onchange="formSetHighway('motorway' )"><!-- highway-motorway --><td>%
+ <tr><td>Trunk: <td><input name="highway-trunk" type="text" size=3 onchange="formSetHighway('trunk' )"><!-- highway-trunk --><td>%
+ <tr><td>Primary: <td><input name="highway-primary" type="text" size=3 onchange="formSetHighway('primary' )"><!-- highway-primary --><td>%
+ <tr><td>Secondary: <td><input name="highway-secondary" type="text" size=3 onchange="formSetHighway('secondary' )"><!-- highway-secondary --><td>%
+ <tr><td>Tertiary: <td><input name="highway-tertiary" type="text" size=3 onchange="formSetHighway('tertiary' )"><!-- highway-tertiary --><td>%
+ <tr><td>Unclassified:<td><input name="highway-unclassified" type="text" size=3 onchange="formSetHighway('unclassified')"><!-- highway-unclassified --><td>%
+ <tr><td>Residential: <td><input name="highway-residential" type="text" size=3 onchange="formSetHighway('residential' )"><!-- highway-residential --><td>%
+ <tr><td>Service: <td><input name="highway-service" type="text" size=3 onchange="formSetHighway('service' )"><!-- highway-service --><td>%
+ <tr><td>Track: <td><input name="highway-track" type="text" size=3 onchange="formSetHighway('track' )"><!-- highway-track --><td>%
+ <tr><td>Cycleway: <td><input name="highway-cycleway" type="text" size=3 onchange="formSetHighway('cycleway' )"><!-- highway-cycleway --><td>%
+ <tr><td>Path: <td><input name="highway-path" type="text" size=3 onchange="formSetHighway('path' )"><!-- highway-path --><td>%
+ <tr><td>Steps: <td><input name="highway-steps" type="text" size=3 onchange="formSetHighway('steps' )"><!-- highway-steps --><td>%
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_speed_show" onclick="hideshow_show('speed');" class="hideshow_show">Show</span>
+ <span id="hideshow_speed_hide" onclick="hideshow_hide('speed');" class="hideshow_hide">Hide</span>
+ <span class="hideshow_title">Speed Limits</span>
+ <div id="hideshow_speed_div" style="display: none;">
+ <table>
+ <tr><td>Motorway: <td><input name="speed-motorway" type="text" size=3 onchange="formSetSpeed('motorway' )"><!-- speed-motorway --><td>km/hr
+ <tr><td>Trunk: <td><input name="speed-trunk" type="text" size=3 onchange="formSetSpeed('trunk' )"><!-- speed-trunk --><td>km/hr
+ <tr><td>Primary: <td><input name="speed-primary" type="text" size=3 onchange="formSetSpeed('primary' )"><!-- speed-primary --><td>km/hr
+ <tr><td>Secondary: <td><input name="speed-secondary" type="text" size=3 onchange="formSetSpeed('secondary' )"><!-- speed-secondary --><td>km/hr
+ <tr><td>Tertiary: <td><input name="speed-tertiary" type="text" size=3 onchange="formSetSpeed('tertiary' )"><!-- speed-tertiary --><td>km/hr
+ <tr><td>Unclassified:<td><input name="speed-unclassified" type="text" size=3 onchange="formSetSpeed('unclassified')"><!-- speed-unclassified --><td>km/hr
+ <tr><td>Residential: <td><input name="speed-residential" type="text" size=3 onchange="formSetSpeed('residential' )"><!-- speed-residential --><td>km/hr
+ <tr><td>Service: <td><input name="speed-service" type="text" size=3 onchange="formSetSpeed('service' )"><!-- speed-service --><td>km/hr
+ <tr><td>Track: <td><input name="speed-track" type="text" size=3 onchange="formSetSpeed('track' )"><!-- speed-track --><td>km/hr
+ <tr><td>Cycleway: <td><input name="speed-cycleway" type="text" size=3 onchange="formSetSpeed('cycleway' )"><!-- speed-cycleway --><td>km/hr
+ <tr><td>Path: <td><input name="speed-path" type="text" size=3 onchange="formSetSpeed('path' )"><!-- speed-path --><td>km/hr
+ <tr><td>Steps: <td><input name="speed-steps" type="text" size=3 onchange="formSetSpeed('steps' )"><!-- speed-steps --><td>km/hr
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_property_show" onclick="hideshow_show('property');" class="hideshow_show">Show</span>
+ <span id="hideshow_property_hide" onclick="hideshow_hide('property');" class="hideshow_hide">Hide</span>
+ <span class="hideshow_title">Property Preferences</span>
+ <div id="hideshow_property_div" style="display: none;">
+ <table>
+ <tr><td>Paved: <td><input name="property-paved" type="text" size=3 onchange="formSetProperty('paved' )"><!-- property-paved --><td>%
+ <tr><td>Multiple Lanes: <td><input name="property-multilane" type="text" size=3 onchange="formSetProperty('multilane')"><!-- property-multilane --><td>%
+ <tr><td>Bridge: <td><input name="property-bridge" type="text" size=3 onchange="formSetProperty('bridge' )"><!-- property-bridge --><td>%
+ <tr><td>Tunnel: <td><input name="property-tunnel" type="text" size=3 onchange="formSetProperty('tunnel' )"><!-- property-tunnel --><td>%
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_restriction_show" onclick="hideshow_show('restriction');" class="hideshow_show">Show</span>
+ <span id="hideshow_restriction_hide" onclick="hideshow_hide('restriction');" class="hideshow_hide">Hide</span>
+ <span class="hideshow_title">Other Restrictions</span>
+ <div id="hideshow_restriction_div" style="display: none;">
+ <table>
+ <tr><td>Obey oneway:<td><input name="restrict-oneway" type="checkbox" onchange="formSetRestriction('oneway')"><!-- oneway --><td>
+ <tr><td>Weight: <td><input name="restrict-weight" type="text" size=3 onchange="formSetRestriction('weight')"><!-- weight --><td>tonnes
+ <tr><td>Height: <td><input name="restrict-height" type="text" size=3 onchange="formSetRestriction('height')"><!-- height --><td>metres
+ <tr><td>Width: <td><input name="restrict-width" type="text" size=3 onchange="formSetRestriction('width' )"><!-- width --><td>metres
+ <tr><td>Length: <td><input name="restrict-length" type="text" size=3 onchange="formSetRestriction('length')"><!-- length --><td>metres
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span class="hideshow_title">Find</span>
+ <input type="button" title="Find shortest route" id="shortest" value="Shortest" onclick="findRoute('shortest');">
+ <input type="button" title="Find quickest route" id="quickest" value="Quickest" onclick="findRoute('quickest');">
+ </div>
+
+ <div class="hideshow_box">
+ <span class="hideshow_title">Links</span>
+ <a id="link_url" href="router.html">Permanent link to these parameters</a>
+ <br>
+ <a id="edit_url" target="other" href="http://www.openstreetmap.org/">Edit OSM data in Potlatch</a>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_help_options_show" onclick="hideshow_show('help_options');" class="hideshow_hide">Show</span>
+ <span id="hideshow_help_options_hide" onclick="hideshow_hide('help_options');" class="hideshow_show">Hide</span>
+ <span class="hideshow_title">Help</span>
+ <div id="hideshow_help_options_div">
+ <div class="scrollable">
+ <p>
+ <b>Quick Start</b>
+ <br>
+ 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.
+ <p>
+ 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.
+ <p>
+ <b>Waypoints</b>
+ <br>
+ 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.
+ <p>
+ <b>Transport Type</b>
+ <br>
+ Selecting a transport type will restrict the chosen route to
+ those on which it is allowed and set default values for the
+ other parameters.
+ <p>
+ <b>Highway Preferences</b>
+ <br>
+ 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.
+ <p>
+ <b>Speed Limits</b>
+ <br>
+ 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.
+ <p>
+ <b>Property Preferences</b>
+ <br>
+ 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.
+ <p>
+ <b>Other Restrictions</b>
+ <br>
+ 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).
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+
+
+ <div class="tab_content" id="tab_results_div" style="display: none;">
+
+ <div class="hideshow_box">
+ <span class="hideshow_title">Status</span>
+ <div id="result_status">
+ <span id="result_status_not_run" ><b><i>Router not run</i></b></span>
+ <span id="result_status_running" style="display: none;"><b>Router running...</b></span>
+ <span id="result_status_complete" style="display: none;"><b>Routing completed</b></span>
+ <span id="result_status_error" style="display: none;"><b>Router error</b></span>
+ <span id="result_status_failed" style="display: none;"><b>Router failed to run</b></span>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_shortest_show" onclick="hideshow_show('shortest');" class="hideshow_show">Show</span>
+ <span id="hideshow_shortest_hide" onclick="hideshow_hide('shortest');" class="hideshow_hide">Hide</span>
+ <span class="hideshow_title">Shortest Route</span>
+ <div id="shortest_status">
+ <span id="shortest_status_no_info" ><b><i>No Information</i></b></span>
+ <span id="shortest_status_info" style="display: none;"></span>
+ </div>
+ <div id="hideshow_shortest_div" style="display: none;">
+ <div id="shortest_links" style="display: none;">
+ <table>
+ <tr><td>HTML directions:<td><a id="shortest_html" target="shortest_html" href="#">Open Popup</a>
+ <tr><td>GPX track file: <td><a id="shortest_gpx_track" target="shortest_gpx_track" href="#">Open Popup</a>
+ <tr><td>GPX route file: <td><a id="shortest_gpx_route" target="shortest_gpx_route" href="#">Open Popup</a>
+ <tr><td>Full text file: <td><a id="shortest_text_all" target="shortest_text_all" href="#">Open Popup</a>
+ <tr><td>Text file: <td><a id="shortest_text" target="shortest_text" href="#">Open Popup</a>
+ </table>
+ <hr>
+ </div>
+ <div id="shortest_route">
+ </div>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_quickest_show" onclick="hideshow_show('quickest');" class="hideshow_show">Show</span>
+ <span id="hideshow_quickest_hide" onclick="hideshow_hide('quickest');" class="hideshow_hide">Hide</span>
+ <span class="hideshow_title">Quickest Route</span>
+ <div id="quickest_status">
+ <span id="quickest_status_no_info" ><b><i>No Information</i></b></span>
+ <span id="quickest_status_info" style="display: none;"></span>
+ </div>
+ <div id="hideshow_quickest_div" style="display: none;">
+ <div id="quickest_links" style="display: none;">
+ <table>
+ <tr><td>HTML directions:<td><a id="quickest_html" target="quickest_html" href="#">Open Popup</a>
+ <tr><td>GPX track file: <td><a id="quickest_gpx_track" target="quickest_gpx_track" href="#">Open Popup</a>
+ <tr><td>GPX route file: <td><a id="quickest_gpx_route" target="quickest_gpx_route" href="#">Open Popup</a>
+ <tr><td>Full text file: <td><a id="quickest_text_all" target="quickest_text_all" href="#">Open Popup</a>
+ <tr><td>Text file: <td><a id="quickest_text" target="quickest_text" href="#">Open Popup</a>
+ </table>
+ <hr>
+ </div>
+ <div id="quickest_route">
+ </div>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_help_route_show" onclick="hideshow_show('help_route');" class="hideshow_hide">Show</span>
+ <span id="hideshow_help_route_hide" onclick="hideshow_hide('help_route');" class="hideshow_show">Hide</span>
+ <span class="hideshow_title">Help</span>
+ <div id="hideshow_help_route_div">
+ <div class="scrollable">
+ <p>
+ <b>Quick Start</b>
+ <br>
+ After calculating a route you can download the GPX file or plain
+ text route description (summary or detailed version). Also you
+ can view the route description and zoom in to selected parts.
+ <p style="margin-bottom: 0px">
+ <b>Problem Solving</b>
+ <br>
+ If the router completes with an error then the most likely cause is
+ that it is not possible to find a route between the selected points.
+ Moving one or more markers or changing the routing options should
+ allow a route to be found.
+ <p style="margin-bottom: 0px">
+ <b>Output Formats</b>
+ <br>
+ <dl style="margin-top: 0px">
+ <dt>HTML instructions
+ <dd>A description of the route to take with directions at each
+ important junction.
+ <dt>GPX track file
+ <dd>The same information that is displayed on the map with points
+ for every node and lines for every segment.
+ <dt>GPX route file
+ <dd>The same information that is displayed in text for the route
+ with a waypoint for each important junction in the route.
+ <dt>Full text file
+ <dd>A list of all of the nodes visited as well as the distance
+ between them and the cumulative distance for each step of the
+ route.
+ <dt>Text file
+ <dd>The same information that is displayed in text for the route.
+ </dl>
+ </div>
+ </div>
+ </div>
+ </div>
+
+
+ <div class="tab_content" id="tab_data_div" style="display: none;">
+ <div class="hideshow_box">
+ <span class="hideshow_title">Statistics</span>
+ <div id="statistics_data"></div>
+ <a id="statistics_link" href="statistics.cgi" onclick="displayStatistics();return(false);">Display data statistics</a>
+ </div>
+
+ <div class="hideshow_box">
+ <span class="hideshow_title">Visualiser</span>
+ To see Routino's view of the data there is a data visualiser that allows
+ displaying of the underlying data in various ways.
+ <br>
+ <a id="visualiser_url" target="other" href="visualiser.html">Custom link to this map view</a>
+ </div>
+ </div>
+
+</div>
+
+<!-- Right hand side of window - map -->
+
+<div class="right_panel">
+ <div class="map" id="map">
+ <noscript>
+ Javascript is <em>required</em> to use this web page because of the
+ interactive map.
+ </noscript>
+ </div>
+ <div class="attribution">
+ <a target="other" href="http://www.routino.org/" title="Routino">Router: Routino</a>
+ |
+ <a target="other" href="http://www.openstreetmap.org/" title="Copyright: OpenStreetMap.org; License: Creative Commons Attribution-Share Alike 2.0">Geo Data: OpenStreetMap</a>
+ </div>
+</div>
+
+</BODY>
+</HTML>
--- /dev/null
+//
+// 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 <http://www.gnu.org/licenses/>.
+//
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////// 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<cookies.length;cookie++)
+ if(cookies[cookie].substr(0,"Routino-home".length)=="Routino-home")
+ {
+ var data=cookies[cookie].split(/[=:;]/);
+
+ if(data[1]=="lon") homelon=Number(data[2]);
+ if(data[3]=="lat") homelat=Number(data[4]);
+ }
+
+ if(homelon!=null && homelat!=null)
+ {
+ 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==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;marker2<vismarkers;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);
+ }
+
+ markerRemoveMap(vismarkers);
+
+ var marker_tr=document.getElementById("point" + vismarkers);
+
+ marker_tr.style.display="none";
+
+ vismarkers--;
+
+ if(vismarkers==1)
+ markerAddAfter(1);
+
+ updateCustomURL();
+}
+
+
+//
+// Add a marker before the current one.
+//
+
+function markerAddBefore(marker)
+{
+ if(vismarkers==nmarkers || marker==1)
+ return false;
+
+ vismarkers++;
+
+ var marker_tr=document.getElementById("point" + vismarkers);
+
+ marker_tr.style.display="";
+
+ for(var marker2=vismarkers;marker2>marker;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],"<table>" + routepoints[type][line].html + "</table>");
+ }
+
+ 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 = "<span></span>";
+
+ 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="<pre>" + response.responseText + "</pre>";
+
+ 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<lines.length;line++)
+ {
+ var thisline=lines[line];
+
+ if(table==0)
+ {
+ if(thisline.match('<table>'))
+ table=1;
+ else
+ continue;
+ }
+
+ if(thisline.match('</table>'))
+ break;
+
+ if(thisline.match('<tr class=\'([a-z])\'>'))
+ {
+ var rowtype=RegExp.$1;
+
+ if(rowtype=='c')
+ {
+ thisline.match('<td class=\'r\'> *([-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('<span class=\'h\'>([^<]+)</span>');
+ points[point-1].highway = RegExp.$1;
+
+ thisline.match('<span class=\'d\'>([^<]+)</span>');
+ points[point-1].distance = RegExp.$1;
+
+ thisline.match('(<span class=\'j\'>[^<]+</span>)');
+ points[point-1].total = RegExp.$1;
+
+ thisline.match('^(.*).<span class=\'j\'>');
+
+ points[point-1].html += RegExp.$1;
+ }
+ else if(rowtype=='t')
+ {
+ points[point-1].html += thisline;
+
+ thisline.match('^(.*<td class=\'r\'>)');
+ total_table = RegExp.$1;
+
+ thisline.match('<td class=\'l\'>([^<]+)<');
+ total_word = RegExp.$1;
+
+ thisline.match('<span class=\'j\'>([^<]+)</span>');
+ points[point-1].total = RegExp.$1;
+ }
+ }
+ }
+
+ var result="<table onmouseout='highlight(\"" + routing_type + "\",-1)'>";
+
+ for(var p=0;p<point-1;p++)
+ {
+ points[p].html += total_table + points[p].total;
+
+ result=result + "<tr onclick='zoomTo(\"" + routing_type + "\"," + p + ")'" +
+ " onmouseover='highlight(\"" + routing_type + "\"," + p + ")'>" +
+ "<td class='distance' title='" + points[p].distance + "'>#" + (p+1) +
+ "<td class='highway'>" + points[p].highway;
+ }
+
+ result=result + "<tr onclick='zoomTo(\"" + routing_type + "\"," + p + ")'" +
+ " onmouseover='highlight(\"" + routing_type + "\"," + p + ")'>" +
+ "<td colspan='2'>" + total_word + " " + points[p].total;
+
+ result=result + "</table>";
+
+ div_route.innerHTML=result;
+}
+
+
+//
+// Failure in getting route.
+//
+
+function getRouteFailure(response)
+{
+ var div_route=document.getElementById(routing_type + "_route");
+ div_route.innerHTML = "";
+}
--- /dev/null
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+# 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;
--- /dev/null
+#!/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 <http://www.gnu.org/licenses/>.
+#
+
+# 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";
--- /dev/null
+#!/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 <http://www.gnu.org/licenses/>.
+#
+
+# 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";
--- /dev/null
+/*
+// 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 <http://www.gnu.org/licenses/>.
+*/
+
+
+/*--------------------------------*/
+/* 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;
+}
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+
+<!--
+ Routino data visualiser web page.
+
+ 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 http://www.gnu.org/licenses/.
+-->
+
+<HEAD>
+<TITLE>Routino : Data Visualiser for Routino OpenStreetMap Data</TITLE>
+<META name="keywords" content="openstreetmap routino verifier">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+
+<!-- OpenLayers Javascript library -->
+<script src="../openlayers/OpenLayers.js" type="text/javascript"></script>
+
+<!-- Page elements -->
+<script src="page-elements.js" type="text/javascript"></script>
+<link href="page-elements.css" type="text/css" rel="stylesheet">
+
+<!-- Router and visualiser shared features -->
+<link href="maplayout.css" type="text/css" rel="stylesheet">
+<!--[if IE 6]>
+ <link href="maplayout-ie6-bugfixes.css" type="text/css" rel="stylesheet">
+<![endif]-->
+<!--[if IE 7]>
+ <link href="maplayout-ie7-bugfixes.css" type="text/css" rel="stylesheet">
+<![endif]-->
+
+<!-- Visualiser specific features -->
+<script src="visualiser.js" type="text/javascript"></script>
+<link href="visualiser.css" type="text/css" rel="stylesheet">
+
+</HEAD>
+<BODY onload="map_init('lat','lon','zoom');">
+
+<!-- Left hand side of window - data panel -->
+
+<div class="left_panel">
+
+ <div class="tab_box">
+ <span id="tab_visualiser" onclick="tab_select('visualiser');" class="tab_selected" title="Select data options">Visualiser</span>
+ <span id="tab_router" onclick="tab_select('router');" class="tab_unselected" title="Plan a route">Router</span>
+ <span id="tab_data" onclick="tab_select('data');" class="tab_unselected" title="View database information">Data</span>
+ </div>
+
+ <div class="tab_content" id="tab_visualiser_div">
+
+ <div class="hideshow_box">
+ <span class="hideshow_title">Routino Data Visualiser</span>
+ 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).
+ <div align="center">
+ <a target="other" href="http://www.routino.org/">Routino Website</a>
+ |
+ <a target="other" href="../documentation/">Documentation</a>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span class="hideshow_title">Instructions</span>
+ 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.
+ </div>
+
+ <div class="hideshow_box">
+ <span class="hideshow_title">Status</span>
+ <div id="result_status" style="font-style: italic;">
+ No data displayed
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_junctions_show" onclick="hideshow_show('junctions');" class="hideshow_show">Show</span>
+ <span id="hideshow_junctions_hide" onclick="hideshow_hide('junctions');" class="hideshow_hide">Hide</span>
+ <input type="button" id="junctions" onclick="displayData('junctions');" value="Display Junctions">
+ <div id="hideshow_junctions_div" style="display: none;">
+ Each node that is a dead-end, a junction of two highways of different
+ types (or different properties) or a junction where more than two segments
+ join are shown colour-coded:
+ <br>
+ <table>
+ <tr><td><img src="icons/ball-1.png" alt="Red" <td>only one highway - a dead-end.
+ <tr><td><img src="icons/ball-2.png" alt="Yellow"<td>two highways of different types meet.
+ <tr><td><img src="icons/ball-3.png" alt="Green" <td>three highways meet.
+ <tr><td><img src="icons/ball-4.png" alt="Brown" <td>four highways meet.
+ <tr><td><img src="icons/ball-5.png" alt="Blue" <td>five highways meet.
+ <tr><td><img src="icons/ball-6.png" alt="Pink" <td>six highways meet.
+ <tr><td><img src="icons/ball-7.png" alt="Black" <td>seven (or more) highways meet.
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_super_show" onclick="hideshow_show('super');" class="hideshow_show">Show</span>
+ <span id="hideshow_super_hide" onclick="hideshow_hide('super');" class="hideshow_hide">Hide</span>
+ <input type="button" id="super" onclick="displayData('super');" value="Display Super Segments">
+ <div id="hideshow_super_div" style="display: none;">
+ Each super-node and the associated super-segments are shown (see algorithm page for description).
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_oneway_show" onclick="hideshow_show('oneway');" class="hideshow_show">Show</span>
+ <span id="hideshow_oneway_hide" onclick="hideshow_hide('oneway');" class="hideshow_hide">Hide</span>
+ <input type="button" id="oneway" onclick="displayData('oneway');" value="Display One-way Segments">
+ <div id="hideshow_oneway_div" style="display: none;">
+ Each one-way segment is shown with a coloured triangle indicating the allowed direction.
+ The colours of the triangles depend on the bearing of the highway segment.
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_speed_show" onclick="hideshow_show('speed');" class="hideshow_show">Show</span>
+ <span id="hideshow_speed_hide" onclick="hideshow_hide('speed');" class="hideshow_hide">Hide</span>
+ <input type="button" id="speed" onclick="displayData('speed');" value="Display Speed Limits">
+ <div id="hideshow_speed_div" style="display: none;">
+ Each node that joins segments with different speed limits is shown
+ along with the speed limit on relevant segments.
+ <br>
+ <table>
+ <tr><td><img src="icons/ball-1.png" alt="Red dot"><td>Change of limit
+ <tr><td><img src="icons/limit-no.png" alt="(no)" ><td>No specified speed limit
+ <tr><td><img src="icons/limit-80.png" alt="(80)" ><td>80 km/hour speed limit
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_weight_show" onclick="hideshow_show('weight');" class="hideshow_show">Show</span>
+ <span id="hideshow_weight_hide" onclick="hideshow_hide('weight');" class="hideshow_hide">Hide</span>
+ <input type="button" id="weight" onclick="displayData('weight');" value="Display Weight Limits">
+ <div id="hideshow_weight_div" style="display: none;">
+ Each node that joins segments with different weight limits is shown
+ along with the weight limit on relevant segments. For example:
+ <br>
+ <table>
+ <tr><td><img src="icons/ball-1.png" alt="Red dot"><td>Change of limit
+ <tr><td><img src="icons/limit-no.png" alt="(no)" ><td>No specified weight limit
+ <tr><td><img src="icons/limit-8.0.png" alt="(8.0)" ><td>8.0 tonnes weight limit
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_height_show" onclick="hideshow_show('height');" class="hideshow_show">Show</span>
+ <span id="hideshow_height_hide" onclick="hideshow_hide('height');" class="hideshow_hide">Hide</span>
+ <input type="button" id="height" onclick="displayData('height');" value="Display Height Limits">
+ <div id="hideshow_height_div" style="display: none;">
+ Each node that joins segments with different height limits is shown
+ along with the height limit on relevant segments. For example:
+ <br>
+ <table>
+ <tr><td><img src="icons/ball-1.png" alt="Red dot"><td>Change of limit
+ <tr><td><img src="icons/limit-no.png" alt="(no)" ><td>No specified height limit
+ <tr><td><img src="icons/limit-4.0.png" alt="(4.0)" ><td>4.0 m height limit
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_width_show" onclick="hideshow_show('width');" class="hideshow_show">Show</span>
+ <span id="hideshow_width_hide" onclick="hideshow_hide('width');" class="hideshow_hide">Hide</span>
+ <input type="button" id="width" onclick="displayData('width');" value="Display Width Limits">
+ <div id="hideshow_width_div" style="display: none;">
+ Each node that joins segments with different width limits is shown
+ along with the width limit on relevant segments. For example:
+ <br>
+ <table>
+ <tr><td><img src="icons/ball-1.png" alt="Red dot"><td>Change of limit
+ <tr><td><img src="icons/limit-no.png" alt="(no)" ><td>No specified width limit
+ <tr><td><img src="icons/limit-3.0.png" alt="(3.0)" ><td>3.0 m width limit
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <span id="hideshow_length_show" onclick="hideshow_show('length');" class="hideshow_show">Show</span>
+ <span id="hideshow_length_hide" onclick="hideshow_hide('length');" class="hideshow_hide">Hide</span>
+ <input type="button" id="length" onclick="displayData('length');" value="Display Length Limits">
+ <div id="hideshow_length_div" style="display: none;">
+ Each node that joins segments with different length limits is shown
+ along with the length limit on relevant segments. For example:
+ <br>
+ <table>
+ <tr><td><img src="icons/ball-1.png" alt="Red dot"><td>Change of limit
+ <tr><td><img src="icons/limit-no.png" alt="(no)" ><td>No specified length limit
+ <tr><td><img src="icons/limit-9.0.png" alt="(9.0)" ><td>9.0 m length limit
+ </table>
+ </div>
+ </div>
+
+ <div class="hideshow_box">
+ <input type="button" id="clear" onclick="displayData('');" value="Clear data">
+ </div>
+
+ <div class="hideshow_box">
+ <span class="hideshow_title">Links</span>
+ <a id="link_url" href="visualiser.html">Permanent link to this view</a>
+ <br>
+ <a id="edit_url" target="other" href="http://www.openstreetmap.org/">Edit OSM data in Potlatch</a>
+ </div>
+ </div>
+
+ <div class="tab_content" id="tab_router_div" style="display: none;">
+ <div class="hideshow_box">
+ <span class="hideshow_title">Router</span>
+ To perform routing on the map use the link below.
+ <br>
+ <a id="router_url" target="other" href="router.html">Custom link to this map view</a>
+ </div>
+ </div>
+
+ <div class="tab_content" id="tab_data_div" style="display: none;">
+ <div class="hideshow_box">
+ <span class="hideshow_title">Statistics</span>
+ <div id="statistics_data"></div>
+ <a id="statistics_link" href="statistics.cgi" onclick="displayStatistics();return(false);">Display data statistics</a>
+ </div>
+ </div>
+
+</div>
+
+<!-- Right hand side of window - map -->
+
+<div class="right_panel">
+ <div class="map" id="map">
+ <noscript>
+ Javascript is <em>required</em> to use this web page because of the
+ interactive map.
+ </noscript>
+ </div>
+ <div class="attribution">
+ <a target="other" href="http://www.routino.org/" title="Routino">Data Manipulation: Routino</a>
+ |
+ <a target="other" href="http://www.openstreetmap.org/" title="Copyright: OpenStreetMap.org; License: Creative Commons Attribution-Share Alike 2.0">Geo Data: OpenStreetMap</a>
+ </div>
+</div>
+
+</BODY>
+</HTML>
--- /dev/null
+//
+// 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 <http://www.gnu.org/licenses/>.
+//
+
+
+//
+// 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="<pre>" + response.responseText + "</pre>";
+
+ 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<lines.length;line++)
+ {
+ var words=lines[line].split(' ');
+
+ if(line == 0)
+ {
+ var lat1=words[0];
+ var lon1=words[1];
+ var lat2=words[2];
+ var lon2=words[3];
+
+ var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,map.getProjectionObject());
+
+ box = new OpenLayers.Marker.Box(bounds);
+
+ layerBoxes.addMarker(box);
+ }
+ else if(words[0] != "")
+ {
+ var lat=words[0];
+ var lon=words[1];
+ var count=words[2];
+
+ var lonlat= new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
+
+ var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
+
+ features.push(new OpenLayers.Feature.Vector(point,{},junction_styles[count]));
+ }
+ }
+
+ layerVectors.addFeatures(features);
+
+ var div_status=document.getElementById("result_status");
+ div_status.innerHTML = "Processed " + (lines.length-2) + " junctions";
+}
+
+
+//
+// Success in getting the super-node and super-segments
+//
+
+function runSuperSuccess(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) + " super-nodes/segments ...";
+
+ var features=[];
+
+ var nodepoint;
+
+ for(var line=0;line<lines.length;line++)
+ {
+ var words=lines[line].split(' ');
+
+ if(line == 0)
+ {
+ var lat1=words[0];
+ var lon1=words[1];
+ var lat2=words[2];
+ var lon2=words[3];
+
+ var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,map.getProjectionObject());
+
+ box = new OpenLayers.Marker.Box(bounds);
+
+ layerBoxes.addMarker(box);
+ }
+ else if(words[0] != "")
+ {
+ var lat=words[0];
+ var lon=words[1];
+ var type=words[2];
+
+ var lonlat= new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
+
+ var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
+
+ if(type == "n")
+ {
+ nodepoint=point;
+
+ features.push(new OpenLayers.Feature.Vector(point,{},super_node_style));
+ }
+ else
+ {
+ var segment = new OpenLayers.Geometry.LineString([nodepoint,point]);
+
+ features.push(new OpenLayers.Feature.Vector(segment,{},super_segment_style));
+ }
+ }
+ }
+
+ layerVectors.addFeatures(features);
+
+ var div_status=document.getElementById("result_status");
+ div_status.innerHTML = "Processed " + (lines.length-2) + " super-nodes/segments";
+}
+
+
+//
+// Success in getting the oneway data
+//
+
+function runOnewaySuccess(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) + " oneway segments ...";
+
+ var features=[];
+
+ for(var line=0;line<lines.length;line++)
+ {
+ var words=lines[line].split(' ');
+
+ if(line == 0)
+ {
+ var lat1=words[0];
+ var lon1=words[1];
+ var lat2=words[2];
+ var lon2=words[3];
+
+ var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,map.getProjectionObject());
+
+ box = new OpenLayers.Marker.Box(bounds);
+
+ layerBoxes.addMarker(box);
+ }
+ else if(words[0] != "")
+ {
+ var lat1=words[0];
+ var lon1=words[1];
+ var lat2=words[2];
+ var lon2=words[3];
+
+ var lonlat1= new OpenLayers.LonLat(lon1,lat1).transform(epsg4326,epsg900913);
+ var lonlat2= new OpenLayers.LonLat(lon2,lat2).transform(epsg4326,epsg900913);
+
+ //var point1 = new OpenLayers.Geometry.Point(lonlat1.lon,lonlat1.lat);
+ var point2 = new OpenLayers.Geometry.Point(lonlat2.lon,lonlat2.lat);
+
+ var dlat = lonlat2.lat-lonlat1.lat;
+ var dlon = lonlat2.lon-lonlat1.lon;
+ var dist = Math.sqrt(dlat*dlat+dlon*dlon)/10;
+ var ang = Math.atan2(dlat,dlon);
+
+ var point3 = new OpenLayers.Geometry.Point(lonlat1.lon+dlat/dist,lonlat1.lat-dlon/dist);
+ var point4 = new OpenLayers.Geometry.Point(lonlat1.lon-dlat/dist,lonlat1.lat+dlon/dist);
+
+ var segment = new OpenLayers.Geometry.LineString([point2,point3,point4,point2]);
+
+ var r=Math.round(7.5+7.9*Math.cos(ang));
+ var g=Math.round(7.5+7.9*Math.cos(ang+2.0943951));
+ var b=Math.round(7.5+7.9*Math.cos(ang-2.0943951));
+ var colour = "#" + hex[r] + hex[g] + hex[b];
+
+ var style=new OpenLayers.Style({},{strokeWidth: 2,strokeColor: colour});
+
+ features.push(new OpenLayers.Feature.Vector(segment,{},style));
+ }
+ }
+
+ layerVectors.addFeatures(features);
+
+ var div_status=document.getElementById("result_status");
+ div_status.innerHTML = "Processed " + (lines.length-2) + " oneway segments";
+}
+
+
+//
+// Success in getting the speed/weight/height/width/length limits
+//
+
+function runLimitSuccess(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) + " limits ...";
+
+ var features=[];
+
+ var nodelonlat;
+
+ for(var line=0;line<lines.length;line++)
+ {
+ var words=lines[line].split(' ');
+
+ if(line == 0)
+ {
+ var lat1=words[0];
+ var lon1=words[1];
+ var lat2=words[2];
+ var lon2=words[3];
+
+ var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,map.getProjectionObject());
+
+ box = new OpenLayers.Marker.Box(bounds);
+
+ layerBoxes.addMarker(box);
+ }
+ else if(words[0] != "")
+ {
+ var lat=words[0];
+ var lon=words[1];
+ var number=words[2];
+
+ var lonlat= new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
+
+ if(number == undefined)
+ {
+ var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
+
+ nodelonlat=lonlat;
+
+ features.push(new OpenLayers.Feature.Vector(point,{},junction_styles[1]));
+ }
+ else
+ {
+ var dlat = lonlat.lat-nodelonlat.lat;
+ var dlon = lonlat.lon-nodelonlat.lon;
+ var dist = Math.sqrt(dlat*dlat+dlon*dlon)/60;
+
+ var point = new OpenLayers.Geometry.Point(nodelonlat.lon+dlon/dist,nodelonlat.lat+dlat/dist);
+
+ features.push(new OpenLayers.Feature.Vector(point,{},
+ new OpenLayers.Style({},{externalGraphic: 'icons/limit-' + number + '.png',
+ graphicYOffset: -9,
+ graphicWidth: 19,
+ graphicHeight: 19})));
+ }
+ }
+ }
+
+ layerVectors.addFeatures(features);
+
+ var div_status=document.getElementById("result_status");
+ div_status.innerHTML = "Processed " + (lines.length-2) + " limits";
+}
+
+
+//
+// Failure in getting data.
+//
+
+function runFailure(response)
+{
+ var div_status=document.getElementById("result_status");
+ div_status.innerHTML = "Failed to get visualiser data!";
+
+ window.alert("Failed to get visualiser data!\n" + response.statusText);
+}
--- /dev/null
+# $Header: /home/amb/routino/xml/RCS/Makefile,v 1.6 2010/07/07 17:25:51 amb Exp $
+#
+# XML 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 <http://www.gnu.org/licenses/>.
+#
+
+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
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- ============================================================
+ $Header: /home/amb/routino/xml/RCS/osm.xsd,v 1.3 2010/05/23 08:24:26 amb Exp $
+
+ An XML Schema Definition for the OSM (JOSM?) XML format
+
+ Created by reverse engineering a JOSM saved file, not used in Routino
+ but a proof-of-concept parser created by xsd-to-xmlparser.
+ ============================================================
+ 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 osm element -->
+
+ <xsd:element name="osm" type="osmType"/>
+
+ <xsd:complexType name="osmType">
+ <xsd:sequence>
+ <xsd:element name="bounds" type="boundsType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="bound" type="boundType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="node" type="nodeType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="way" type="wayType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="version" type="xsd:string"/>
+ <xsd:attribute name="generator" type="xsd:string"/>
+ </xsd:complexType>
+
+ <!-- The second level bounds, node, way and relation elements -->
+
+ <xsd:complexType name="boundsType">
+ <xsd:attribute name="minlat" type="xsd:string"/>
+ <xsd:attribute name="minlon" type="xsd:string"/>
+ <xsd:attribute name="maxlat" type="xsd:string"/>
+ <xsd:attribute name="maxlon" type="xsd:string"/>
+ <xsd:attribute name="origin" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="boundType">
+ <xsd:attribute name="box" type="xsd:string"/>
+ <xsd:attribute name="origin" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="nodeType">
+ <xsd:sequence>
+ <xsd:element name="tag" type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string"/>
+ <xsd:attribute name="lat" type="xsd:string"/>
+ <xsd:attribute name="lon" type="xsd:string"/>
+ <xsd:attribute name="timestamp" type="xsd:string"/>
+ <xsd:attribute name="uid" type="xsd:string"/>
+ <xsd:attribute name="user" type="xsd:string"/>
+ <xsd:attribute name="visible" type="xsd:string"/>
+ <xsd:attribute name="version" type="xsd:string"/>
+ <xsd:attribute name="action" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="wayType">
+ <xsd:sequence>
+ <xsd:element name="nd" type="ndType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="tag" type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string"/>
+ <xsd:attribute name="timestamp" type="xsd:string"/>
+ <xsd:attribute name="uid" type="xsd:string"/>
+ <xsd:attribute name="user" type="xsd:string"/>
+ <xsd:attribute name="visible" type="xsd:string"/>
+ <xsd:attribute name="version" type="xsd:string"/>
+ <xsd:attribute name="action" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="relationType">
+ <xsd:sequence>
+ <xsd:element name="member" type="memberType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="tag" type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string"/>
+ <xsd:attribute name="timestamp" type="xsd:string"/>
+ <xsd:attribute name="uid" type="xsd:string"/>
+ <xsd:attribute name="user" type="xsd:string"/>
+ <xsd:attribute name="visible" type="xsd:string"/>
+ <xsd:attribute name="version" type="xsd:string"/>
+ <xsd:attribute name="action" type="xsd:string"/>
+ </xsd:complexType>
+
+ <!-- The third level elements and their contents -->
+
+ <xsd:complexType name="tagType">
+ <xsd:attribute name="k" type="xsd:string"/>
+ <xsd:attribute name="v" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="ndType">
+ <xsd:attribute name="ref" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="memberType">
+ <xsd:attribute name="type" type="xsd:string"/>
+ <xsd:attribute name="ref" type="xsd:string"/>
+ <xsd:attribute name="role" type="xsd:string"/>
+ </xsd:complexType>
+
+</xsd:schema>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- ============================================================
+ $Header: /home/amb/routino/xml/RCS/routino-osm.xsd,v 1.2 2010/05/23 08:24:26 amb Exp $
+
+ An XML Schema Definition for the part of the OSM XML format read by Routino.
+
+ 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 osm element -->
+
+ <xsd:element name="osm" type="osmType"/>
+
+ <xsd:complexType name="osmType">
+ <xsd:sequence>
+ <xsd:element name="bounds" type="boundsType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="bound" type="boundType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="node" type="nodeType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="way" type="wayType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <!--
+ <xsd:attribute name="version" type="xsd:string"/>
+ <xsd:attribute name="generator" type="xsd:string"/>
+ -->
+ </xsd:complexType>
+
+ <!-- The second level bounds, node, way and relation elements -->
+
+ <xsd:complexType name="boundsType">
+ <!--
+ <xsd:attribute name="minlat" type="xsd:string"/>
+ <xsd:attribute name="minlon" type="xsd:string"/>
+ <xsd:attribute name="maxlat" type="xsd:string"/>
+ <xsd:attribute name="maxlon" type="xsd:string"/>
+ <xsd:attribute name="origin" type="xsd:string"/>
+ -->
+ </xsd:complexType>
+
+ <xsd:complexType name="boundType">
+ <!--
+ <xsd:attribute name="box" type="xsd:string"/>
+ <xsd:attribute name="origin" type="xsd:string"/>
+ -->
+ </xsd:complexType>
+
+ <xsd:complexType name="nodeType">
+ <xsd:sequence>
+ <xsd:element name="tag" type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string"/>
+ <xsd:attribute name="lat" type="xsd:string"/>
+ <xsd:attribute name="lon" type="xsd:string"/>
+ <!--
+ <xsd:attribute name="timestamp" type="xsd:string"/>
+ <xsd:attribute name="uid" type="xsd:string"/>
+ <xsd:attribute name="user" type="xsd:string"/>
+ <xsd:attribute name="visible" type="xsd:string"/>
+ <xsd:attribute name="version" type="xsd:string"/>
+ <xsd:attribute name="action" type="xsd:string"/>
+ -->
+ </xsd:complexType>
+
+ <xsd:complexType name="wayType">
+ <xsd:sequence>
+ <xsd:element name="nd" type="ndType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="tag" type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string"/>
+ <!--
+ <xsd:attribute name="timestamp" type="xsd:string"/>
+ <xsd:attribute name="uid" type="xsd:string"/>
+ <xsd:attribute name="user" type="xsd:string"/>
+ <xsd:attribute name="visible" type="xsd:string"/>
+ <xsd:attribute name="version" type="xsd:string"/>
+ <xsd:attribute name="action" type="xsd:string"/>
+ -->
+ </xsd:complexType>
+
+ <xsd:complexType name="relationType">
+ <xsd:sequence>
+ <xsd:element name="member" type="memberType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="tag" type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string"/>
+ <!--
+ <xsd:attribute name="timestamp" type="xsd:string"/>
+ <xsd:attribute name="uid" type="xsd:string"/>
+ <xsd:attribute name="user" type="xsd:string"/>
+ <xsd:attribute name="visible" type="xsd:string"/>
+ <xsd:attribute name="version" type="xsd:string"/>
+ <xsd:attribute name="action" type="xsd:string"/>
+ -->
+ </xsd:complexType>
+
+ <!-- The third level elements and their contents -->
+
+ <xsd:complexType name="tagType">
+ <xsd:attribute name="k" type="xsd:string"/>
+ <xsd:attribute name="v" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="ndType">
+ <xsd:attribute name="ref" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="memberType">
+ <xsd:attribute name="type" type="xsd:string"/>
+ <xsd:attribute name="ref" type="xsd:string"/>
+ <xsd:attribute name="role" type="xsd:string"/>
+ </xsd:complexType>
+
+</xsd:schema>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- ============================================================
+ $Header: /home/amb/routino/xml/RCS/routino-profiles.xml,v 1.2 2010/06/26 19:26:47 amb Exp $
+
+ An XML format file containing Routino routing profiles
+
+ 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.
+ ============================================================ -->
+
+<routino-profiles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-profiles.xsd">
+
+ <profile name="foot" transport="foot">
+ <speeds>
+ <speed highway="motorway" kph="0" />
+ <speed highway="trunk" kph="4" />
+ <speed highway="primary" kph="4" />
+ <speed highway="secondary" kph="4" />
+ <speed highway="tertiary" kph="4" />
+ <speed highway="unclassified" kph="4" />
+ <speed highway="residential" kph="4" />
+ <speed highway="service" kph="4" />
+ <speed highway="track" kph="4" />
+ <speed highway="cycleway" kph="4" />
+ <speed highway="path" kph="4" />
+ <speed highway="steps" kph="4" />
+ </speeds>
+ <preferences>
+ <preference highway="motorway" percent="0" />
+ <preference highway="trunk" percent="40" />
+ <preference highway="primary" percent="50" />
+ <preference highway="secondary" percent="60" />
+ <preference highway="tertiary" percent="70" />
+ <preference highway="unclassified" percent="80" />
+ <preference highway="residential" percent="90" />
+ <preference highway="service" percent="90" />
+ <preference highway="track" percent="95" />
+ <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">
+ <speeds>
+ <speed highway="motorway" kph="0" />
+ <speed highway="trunk" kph="8" />
+ <speed highway="primary" kph="8" />
+ <speed highway="secondary" kph="8" />
+ <speed highway="tertiary" kph="8" />
+ <speed highway="unclassified" kph="8" />
+ <speed highway="residential" kph="8" />
+ <speed highway="service" kph="8" />
+ <speed highway="track" kph="8" />
+ <speed highway="cycleway" kph="8" />
+ <speed highway="path" kph="8" />
+ <speed highway="steps" kph="0" />
+ </speeds>
+ <preferences>
+ <preference highway="motorway" percent="0" />
+ <preference highway="trunk" percent="25" />
+ <preference highway="primary" percent="50" />
+ <preference highway="secondary" percent="50" />
+ <preference highway="tertiary" percent="75" />
+ <preference highway="unclassified" percent="75" />
+ <preference highway="residential" percent="75" />
+ <preference highway="service" percent="75" />
+ <preference highway="track" percent="100" />
+ <preference highway="cycleway" percent="90" />
+ <preference highway="path" percent="100" />
+ <preference highway="steps" percent="0" />
+ </preferences>
+ <properties>
+ <property type="paved" percent="20" />
+ <property type="multilane" percent="25" />
+ <property type="bridge" percent="50" />
+ <property type="tunnel" percent="50" />
+ </properties>
+ <restrictions>
+ <oneway obey="1" />
+ <weight limit="0.0" />
+ <height limit="0.0" />
+ <width limit="0.0" />
+ <length limit="0.0" />
+ </restrictions>
+ </profile>
+
+ <profile name="wheelchair" transport="wheelchair">
+ <speeds>
+ <speed highway="motorway" kph="0" />
+ <speed highway="trunk" kph="4" />
+ <speed highway="primary" kph="4" />
+ <speed highway="secondary" kph="4" />
+ <speed highway="tertiary" kph="4" />
+ <speed highway="unclassified" kph="4" />
+ <speed highway="residential" kph="4" />
+ <speed highway="service" kph="4" />
+ <speed highway="track" kph="4" />
+ <speed highway="cycleway" kph="4" />
+ <speed highway="path" kph="4" />
+ <speed highway="steps" kph="4" />
+ </speeds>
+ <preferences>
+ <preference highway="motorway" percent="0" />
+ <preference highway="trunk" percent="40" />
+ <preference highway="primary" percent="50" />
+ <preference highway="secondary" percent="60" />
+ <preference highway="tertiary" percent="70" />
+ <preference highway="unclassified" percent="80" />
+ <preference highway="residential" percent="90" />
+ <preference highway="service" percent="90" />
+ <preference highway="track" percent="95" />
+ <preference highway="cycleway" percent="95" />
+ <preference highway="path" percent="100" />
+ <preference highway="steps" percent="0" />
+ </preferences>
+ <properties>
+ <property type="paved" percent="90" />
+ <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="bicycle" transport="bicycle">
+ <speeds>
+ <speed highway="motorway" kph="0" />
+ <speed highway="trunk" kph="20" />
+ <speed highway="primary" kph="20" />
+ <speed highway="secondary" kph="20" />
+ <speed highway="tertiary" kph="20" />
+ <speed highway="unclassified" kph="20" />
+ <speed highway="residential" kph="20" />
+ <speed highway="service" kph="20" />
+ <speed highway="track" kph="20" />
+ <speed highway="cycleway" kph="20" />
+ <speed highway="path" kph="20" />
+ <speed highway="steps" kph="0" />
+ </speeds>
+ <preferences>
+ <preference highway="motorway" percent="0" />
+ <preference highway="trunk" percent="30" />
+ <preference highway="primary" percent="70" />
+ <preference highway="secondary" percent="80" />
+ <preference highway="tertiary" percent="90" />
+ <preference highway="unclassified" percent="90" />
+ <preference highway="residential" percent="90" />
+ <preference highway="service" percent="90" />
+ <preference highway="track" percent="90" />
+ <preference highway="cycleway" percent="100" />
+ <preference highway="path" percent="90" />
+ <preference highway="steps" percent="0" />
+ </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="1" />
+ <weight limit="0.0" />
+ <height limit="0.0" />
+ <width limit="0.0" />
+ <length limit="0.0" />
+ </restrictions>
+ </profile>
+
+ <profile name="moped" transport="moped">
+ <speeds>
+ <speed highway="motorway" kph="48" />
+ <speed highway="trunk" kph="48" />
+ <speed highway="primary" kph="48" />
+ <speed highway="secondary" kph="48" />
+ <speed highway="tertiary" kph="48" />
+ <speed highway="unclassified" kph="48" />
+ <speed highway="residential" kph="48" />
+ <speed highway="service" kph="32" />
+ <speed highway="track" kph="16" />
+ <speed highway="cycleway" kph="0" />
+ <speed highway="path" kph="0" />
+ <speed highway="steps" kph="0" />
+ </speeds>
+ <preferences>
+ <preference highway="motorway" percent="0" />
+ <preference highway="trunk" percent="90" />
+ <preference highway="primary" percent="100" />
+ <preference highway="secondary" percent="90" />
+ <preference highway="tertiary" percent="80" />
+ <preference highway="unclassified" percent="70" />
+ <preference highway="residential" percent="60" />
+ <preference highway="service" percent="80" />
+ <preference highway="track" percent="0" />
+ <preference highway="cycleway" percent="0" />
+ <preference highway="path" percent="0" />
+ <preference highway="steps" percent="0" />
+ </preferences>
+ <properties>
+ <property type="paved" percent="100" />
+ <property type="multilane" percent="25" />
+ <property type="bridge" percent="50" />
+ <property type="tunnel" percent="50" />
+ </properties>
+ <restrictions>
+ <oneway obey="1" />
+ <weight limit="0.0" />
+ <height limit="0.0" />
+ <width limit="0.0" />
+ <length limit="0.0" />
+ </restrictions>
+ </profile>
+
+ <profile name="motorbike" transport="motorbike">
+ <speeds>
+ <speed highway="motorway" kph="112" />
+ <speed highway="trunk" kph="96" />
+ <speed highway="primary" kph="96" />
+ <speed highway="secondary" kph="88" />
+ <speed highway="tertiary" kph="80" />
+ <speed highway="unclassified" kph="64" />
+ <speed highway="residential" kph="48" />
+ <speed highway="service" kph="32" />
+ <speed highway="track" kph="16" />
+ <speed highway="cycleway" kph="0" />
+ <speed highway="path" kph="0" />
+ <speed highway="steps" kph="0" />
+ </speeds>
+ <preferences>
+ <preference highway="motorway" percent="100" />
+ <preference highway="trunk" percent="100" />
+ <preference highway="primary" percent="90" />
+ <preference highway="secondary" percent="80" />
+ <preference highway="tertiary" percent="70" />
+ <preference highway="unclassified" percent="60" />
+ <preference highway="residential" percent="50" />
+ <preference highway="service" percent="80" />
+ <preference highway="track" percent="0" />
+ <preference highway="cycleway" percent="0" />
+ <preference highway="path" percent="0" />
+ <preference highway="steps" percent="0" />
+ </preferences>
+ <properties>
+ <property type="paved" percent="100" />
+ <property type="multilane" percent="75" />
+ <property type="bridge" percent="50" />
+ <property type="tunnel" percent="50" />
+ </properties>
+ <restrictions>
+ <oneway obey="1" />
+ <weight limit="0.0" />
+ <height limit="0.0" />
+ <width limit="0.0" />
+ <length limit="0.0" />
+ </restrictions>
+ </profile>
+
+ <profile name="motorcar" transport="motorcar">
+ <speeds>
+ <speed highway="motorway" kph="112" />
+ <speed highway="trunk" kph="96" />
+ <speed highway="primary" kph="96" />
+ <speed highway="secondary" kph="88" />
+ <speed highway="tertiary" kph="80" />
+ <speed highway="unclassified" kph="64" />
+ <speed highway="residential" kph="48" />
+ <speed highway="service" kph="32" />
+ <speed highway="track" kph="16" />
+ <speed highway="cycleway" kph="0" />
+ <speed highway="path" kph="0" />
+ <speed highway="steps" kph="0" />
+ </speeds>
+ <preferences>
+ <preference highway="motorway" percent="100" />
+ <preference highway="trunk" percent="100" />
+ <preference highway="primary" percent="90" />
+ <preference highway="secondary" percent="80" />
+ <preference highway="tertiary" percent="70" />
+ <preference highway="unclassified" percent="60" />
+ <preference highway="residential" percent="50" />
+ <preference highway="service" percent="80" />
+ <preference highway="track" percent="0" />
+ <preference highway="cycleway" percent="0" />
+ <preference highway="path" percent="0" />
+ <preference highway="steps" percent="0" />
+ </preferences>
+ <properties>
+ <property type="paved" percent="100" />
+ <property type="multilane" percent="75" />
+ <property type="bridge" percent="50" />
+ <property type="tunnel" percent="50" />
+ </properties>
+ <restrictions>
+ <oneway obey="1" />
+ <weight limit="0.0" />
+ <height limit="0.0" />
+ <width limit="0.0" />
+ <length limit="0.0" />
+ </restrictions>
+ </profile>
+
+ <profile name="goods" transport="goods">
+ <speeds>
+ <speed highway="motorway" kph="96" />
+ <speed highway="trunk" kph="96" />
+ <speed highway="primary" kph="96" />
+ <speed highway="secondary" kph="88" />
+ <speed highway="tertiary" kph="80" />
+ <speed highway="unclassified" kph="64" />
+ <speed highway="residential" kph="48" />
+ <speed highway="service" kph="32" />
+ <speed highway="track" kph="16" />
+ <speed highway="cycleway" kph="0" />
+ <speed highway="path" kph="0" />
+ <speed highway="steps" kph="0" />
+ </speeds>
+ <preferences>
+ <preference highway="motorway" percent="100" />
+ <preference highway="trunk" percent="100" />
+ <preference highway="primary" percent="90" />
+ <preference highway="secondary" percent="80" />
+ <preference highway="tertiary" percent="70" />
+ <preference highway="unclassified" percent="60" />
+ <preference highway="residential" percent="50" />
+ <preference highway="service" percent="80" />
+ <preference highway="track" percent="0" />
+ <preference highway="cycleway" percent="0" />
+ <preference highway="path" percent="0" />
+ <preference highway="steps" percent="0" />
+ </preferences>
+ <properties>
+ <property type="paved" percent="100" />
+ <property type="multilane" percent="75" />
+ <property type="bridge" percent="50" />
+ <property type="tunnel" percent="50" />
+ </properties>
+ <restrictions>
+ <oneway obey="1" />
+ <weight limit="5.0" />
+ <height limit="2.5" />
+ <width limit="2.0" />
+ <length limit="5.0" />
+ </restrictions>
+ </profile>
+
+ <profile name="hgv" transport="hgv">
+ <speeds>
+ <speed highway="motorway" kph="89" />
+ <speed highway="trunk" kph="80" />
+ <speed highway="primary" kph="80" />
+ <speed highway="secondary" kph="80" />
+ <speed highway="tertiary" kph="80" />
+ <speed highway="unclassified" kph="64" />
+ <speed highway="residential" kph="48" />
+ <speed highway="service" kph="32" />
+ <speed highway="track" kph="16" />
+ <speed highway="cycleway" kph="0" />
+ <speed highway="path" kph="0" />
+ <speed highway="steps" kph="0" />
+ </speeds>
+ <preferences>
+ <preference highway="motorway" percent="100" />
+ <preference highway="trunk" percent="100" />
+ <preference highway="primary" percent="90" />
+ <preference highway="secondary" percent="80" />
+ <preference highway="tertiary" percent="70" />
+ <preference highway="unclassified" percent="60" />
+ <preference highway="residential" percent="50" />
+ <preference highway="service" percent="80" />
+ <preference highway="track" percent="0" />
+ <preference highway="cycleway" percent="0" />
+ <preference highway="path" percent="0" />
+ <preference highway="steps" percent="0" />
+ </preferences>
+ <properties>
+ <property type="paved" percent="100" />
+ <property type="multilane" percent="75" />
+ <property type="bridge" percent="50" />
+ <property type="tunnel" percent="50" />
+ </properties>
+ <restrictions>
+ <oneway obey="1" />
+ <weight limit="10.0" />
+ <height limit="3.0" />
+ <width limit="2.5" />
+ <length limit="6.0" />
+ </restrictions>
+ </profile>
+
+ <profile name="psv" transport="psv">
+ <speeds>
+ <speed highway="motorway" kph="89" />
+ <speed highway="trunk" kph="80" />
+ <speed highway="primary" kph="80" />
+ <speed highway="secondary" kph="80" />
+ <speed highway="tertiary" kph="80" />
+ <speed highway="unclassified" kph="64" />
+ <speed highway="residential" kph="48" />
+ <speed highway="service" kph="32" />
+ <speed highway="track" kph="16" />
+ <speed highway="cycleway" kph="0" />
+ <speed highway="path" kph="0" />
+ <speed highway="steps" kph="0" />
+ </speeds>
+ <preferences>
+ <preference highway="motorway" percent="100" />
+ <preference highway="trunk" percent="100" />
+ <preference highway="primary" percent="90" />
+ <preference highway="secondary" percent="80" />
+ <preference highway="tertiary" percent="70" />
+ <preference highway="unclassified" percent="60" />
+ <preference highway="residential" percent="50" />
+ <preference highway="service" percent="80" />
+ <preference highway="track" percent="0" />
+ <preference highway="cycleway" percent="0" />
+ <preference highway="path" percent="0" />
+ <preference highway="steps" percent="0" />
+ </preferences>
+ <properties>
+ <property type="paved" percent="100" />
+ <property type="multilane" percent="75" />
+ <property type="bridge" percent="50" />
+ <property type="tunnel" percent="50" />
+ </properties>
+ <restrictions>
+ <oneway obey="1" />
+ <weight limit="15.0" />
+ <height limit="3.0" />
+ <width limit="2.5" />
+ <length limit="6.0" />
+ </restrictions>
+ </profile>
+
+</routino-profiles>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+ $Header$
+
+ An XML Schema Definition for the Routino profile 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 profiles -->
+
+ <xsd:element name="routino-profiles" type="RoutinoProfilesType"/>
+
+ <xsd:complexType name="RoutinoProfilesType">
+ <xsd:sequence>
+ <xsd:element name="profile" type="profileType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="profileType">
+ <xsd:sequence>
+ <xsd:element name="speeds" type="speedsType" />
+ <xsd:element name="preferences" type="preferencesType" />
+ <xsd:element name="properties" type="propertiesType" />
+ <xsd:element name="restrictions" type="restrictionsType"/>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string"/>
+ <xsd:attribute name="transport" type="xsd:string"/>
+ </xsd:complexType>
+
+ <!-- The second level preferences, speed, properties and restrictions -->
+
+ <xsd:complexType name="speedsType">
+ <xsd:sequence>
+ <xsd:element name="speed" type="speedType" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="preferencesType">
+ <xsd:sequence>
+ <xsd:element name="preference" type="preferenceType" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="propertiesType">
+ <xsd:sequence>
+ <xsd:element name="property" type="propertyType" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="restrictionsType">
+ <xsd:sequence>
+ <xsd:element name="oneway" type="onewayType"/>
+ <xsd:element name="weight" type="weightType"/>
+ <xsd:element name="height" type="heightType"/>
+ <xsd:element name="width" type="widthType"/>
+ <xsd:element name="length" type="lengthType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <!-- The lowest level elements containing the real information -->
+
+ <xsd:complexType name="speedType">
+ <xsd:attribute name="highway" type="xsd:string"/>
+ <xsd:attribute name="kph" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="preferenceType">
+ <xsd:attribute name="highway" type="xsd:string"/>
+ <xsd:attribute name="percent" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="propertyType">
+ <xsd:attribute name="type" type="xsd:string"/>
+ <xsd:attribute name="percent" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="onewayType">
+ <xsd:attribute name="obey" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="weightType">
+ <xsd:attribute name="limit" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="heightType">
+ <xsd:attribute name="limit" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="widthType">
+ <xsd:attribute name="limit" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="lengthType">
+ <xsd:attribute name="limit" type="xsd:string"/>
+ </xsd:complexType>
+
+</xsd:schema>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- ============================================================
+ $Header: /home/amb/routino/xml/RCS/routino-tagging-nomodify.xml,v 1.2 2010/06/26 19:26:47 amb Exp $
+
+ An XML format file containing Routino tagging rules - copy the input file
+ directly to the output with no modifications (e.g. importing a file dumped
+ by filedumper).
+
+ 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.
+ ============================================================ -->
+
+<routino-tagging xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-tagging.xsd">
+
+ <!-- Node rules are not currently used -->
+
+ <node>
+ </node>
+
+ <!-- Way rules (copy everything from input to output) -->
+
+ <way>
+
+ <if>
+ <output />
+ </if>
+
+ </way>
+
+ <!-- Relation rules are not currently used -->
+
+ <relation>
+ </relation>
+
+</routino-tagging>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- ============================================================
+ $Header: /home/amb/routino/xml/RCS/routino-tagging.xml,v 1.2 2010/06/26 19:26:47 amb Exp $
+
+ An XML format file containing Routino 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.
+ ============================================================ -->
+
+<routino-tagging xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-tagging.xsd">
+
+ <!-- Node rules are not currently used -->
+
+ <node>
+ </node>
+
+ <!-- Way rules -->
+
+ <way>
+
+ <!-- Highway types (includes default access and default properties) -->
+
+ <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>
+
+ <if k="highway" v="trunk_link">
+ <set v="trunk"/>
+ </if>
+
+ <if k="highway" v="trunk">
+ <output k="highway"/>
+
+ <output k="bicycle" v="yes"/>
+ <output k="moped" v="yes"/>
+ <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"/>
+ </if>
+
+ <if k="highway" v="primary_link">
+ <set v="primary"/>
+ </if>
+
+ <if k="highway" v="primary">
+ <output k="highway"/>
+
+ <output k="foot" v="yes"/>
+ <output k="horse" v="yes"/>
+ <output k="wheelchair" v="no"/>
+ <output k="bicycle" v="yes"/>
+ <output k="moped" v="yes"/>
+ <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"/>
+ </if>
+
+ <if k="highway" v="secondary_link">
+ <set v="secondary"/>
+ </if>
+
+ <if k="highway" v="secondary">
+ <output k="highway"/>
+
+ <output k="foot" v="yes"/>
+ <output k="horse" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ <output k="bicycle" v="yes"/>
+ <output k="moped" v="yes"/>
+ <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"/>
+ </if>
+
+ <if k="highway" v="tertiary">
+ <output k="highway"/>
+
+ <output k="foot" v="yes"/>
+ <output k="horse" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ <output k="bicycle" v="yes"/>
+ <output k="moped" v="yes"/>
+ <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"/>
+ </if>
+
+ <if k="highway" v="minor">
+ <set k="highway" v="unclassified"/>
+ </if>
+
+ <if k="highway" v="road">
+ <set k="highway" v="unclassified"/>
+ </if>
+
+ <if k="highway" v="unclassified">
+ <output k="highway"/>
+
+ <output k="foot" v="yes"/>
+ <output k="horse" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ <output k="bicycle" v="yes"/>
+ <output k="moped" v="yes"/>
+ <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"/>
+ </if>
+
+ <if k="highway" v="living_street">
+ <set k="highway" v="residential"/>
+ </if>
+
+ <if k="highway" v="residential">
+ <output k="highway"/>
+
+ <output k="foot" v="yes"/>
+ <output k="horse" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ <output k="bicycle" v="yes"/>
+ <output k="moped" v="yes"/>
+ <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"/>
+ </if>
+
+ <if k="highway" v="services">
+ <set k="highway" v="service"/>
+ </if>
+
+ <if k="highway" v="service">
+ <output k="highway"/>
+
+ <output k="foot" v="yes"/>
+ <output k="horse" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ <output k="bicycle" v="yes"/>
+ <output k="moped" v="yes"/>
+ <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"/>
+ </if>
+
+ <if k="highway" v="byway">
+ <set k="highway" v="track"/>
+ </if>
+
+ <if k="highway" v="unsurfaced">
+ <set k="highway" v="track"/>
+ </if>
+
+ <if k="highway" v="unpaved">
+ <set k="highway" v="track"/>
+ </if>
+
+ <if k="highway" v="track">
+ <output k="highway"/>
+
+ <output k="foot" v="yes"/>
+ <output k="horse" v="yes"/>
+ <output k="bicycle" v="yes"/>
+ </if>
+
+ <if k="tracktype" v="grade1">
+ <output k="paved" v="yes"/>
+ </if>
+
+ <if k="highway" v="cycleway">
+ <output k="highway"/>
+
+ <output k="foot" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ <output k="bicycle" v="yes"/>
+
+ <output k="paved" v="yes"/>
+ </if>
+
+ <if k="highway" v="footway">
+ <set k="highway" v="path"/>
+ </if>
+
+ <if k="highway" v="bridleway">
+ <set k="highway" v="path"/>
+
+ <output k="horse" v="yes"/>
+ <output k="bicycle" v="yes"/>
+ </if>
+
+ <if k="highway" v="pedestrian">
+ <set k="highway" v="path"/>
+
+ <output k="paved" v="yes"/>
+ </if>
+
+ <if k="highway" v="walkway">
+ <set k="highway" v="path"/>
+
+ <output k="paved" v="yes"/>
+ </if>
+
+ <if k="highway" v="path">
+ <output k="highway"/>
+
+ <output k="foot" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ </if>
+
+ <if k="highway" v="steps">
+ <output k="highway"/>
+
+ <output k="foot" v="yes"/>
+ </if>
+
+ <if k="junction" v="roundabout">
+ <output k="junction" v="roundabout"/>
+ <output k="oneway" v="yes"/>
+ </if>
+
+ <!-- Normalisation of access tags -->
+
+ <if v="designated" ><set v="yes"/></if>
+ <if v="permissive" ><set v="yes"/></if>
+ <if v="destination"><set v="yes"/></if>
+
+ <if v="private"><set v="no"/></if>
+
+ <!-- Generic access permissions for all transport types (to override defaults) -->
+
+ <if k="access">
+ <set k="noaccess" v="yes"/>
+ </if>
+
+ <if k="access" v="true">
+ <set k="noaccess" v="no"/>
+ </if>
+
+ <if k="access" v="yes">
+ <set k="noaccess" v="no"/>
+ </if>
+
+ <if k="noaccess" v="yes">
+ <output k="foot" v="no"/>
+ <output k="horse" v="no"/>
+ <output k="wheelchair" v="no"/>
+ <output k="bicycle" v="no"/>
+ <output k="moped" v="no"/>
+ <output k="motorbike" v="no"/>
+ <output k="motorcar" v="no"/>
+ <output k="goods" v="no"/>
+ <output k="hgv" v="no"/>
+ <output k="psv" v="no"/>
+ </if>
+
+ <!-- Generic access permissions for classes of transport types -->
+
+ <if k="motor_vehicle">
+ <output k="moped"/>
+ <output k="motorbike"/>
+ <output k="motorcar"/>
+ <output k="goods"/>
+ <output k="hgv"/>
+ <output k="psv"/>
+ </if>
+
+ <if k="vehicle">
+ <output k="bicycle"/>
+ <output k="moped"/>
+ <output k="motorbike"/>
+ <output k="motorcar"/>
+ <output k="goods"/>
+ <output k="hgv"/>
+ <output k="psv"/>
+ </if>
+
+ <!-- Other access permissions (UK) -->
+
+ <if k="designation" v="restricted_byway">
+ <output k="foot" v="yes"/>
+ <output k="horse" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ <output k="bicycle" v="yes"/>
+ </if>
+
+ <if k="designation" v="byway">
+ <output k="foot" v="yes"/>
+ <output k="horse" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ <output k="bicycle" v="yes"/>
+ <output k="moped" v="yes"/>
+ <output k="motorbike" v="yes"/>
+ <output k="motorcar" v="yes"/>
+ </if>
+
+ <if k="designation" v="public_bridleway">
+ <set v="bridleway"/>
+ </if>
+
+ <if k="designation" v="bridleway">
+ <output k="foot" v="yes"/>
+ <output k="horse" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ <output k="bicycle" v="yes"/>
+ </if>
+
+ <if k="designation" v="public_footpath">
+ <set v="footpath"/>
+ </if>
+
+ <if k="designation" v="footpath">
+ <output k="foot" v="yes"/>
+ <output k="wheelchair" v="yes"/>
+ </if>
+
+ <!-- Specific access rules (to override the generic ones) -->
+
+ <if k="foot" ><output/></if>
+ <if k="horse" ><output/></if>
+ <if k="wheelchair"><output/></if>
+ <if k="bicycle" ><output/></if>
+ <if k="moped" ><output/></if>
+ <if k="motorbike" ><output/></if>
+ <if k="motorcar" ><output/></if>
+ <if k="goods" ><output/></if>
+ <if k="hgv" ><output/></if>
+ <if k="psv" ><output/></if>
+
+ <!-- Normalisation of property tags -->
+
+ <if k="surface">
+ <set k="paved"/>
+ </if>
+
+ <if k="surface" v="paved">
+ <set k="paved" v="yes"/>
+ </if>
+
+ <if k="surface" v="concrete">
+ <set k="paved" v="yes"/>
+ </if>
+
+ <if k="surface" v="ashphalt">
+ <set k="paved" v="yes"/>
+ </if>
+
+
+ <if k="lanes">
+ <set k="multilane" v="yes"/>
+ </if>
+
+ <if k="lanes" v="1">
+ <set k="multilane" v="no"/>
+ </if>
+
+ <!-- Specific property rules (to override the default ones) -->
+
+ <if k="paved" ><output/></if>
+ <if k="multilane"><output/></if>
+
+ <if k="bridge" ><output/></if>
+ <if k="tunnel" ><output/></if>
+
+ <!-- Output the restriction tags -->
+
+ <if k="oneway"><output/></if>
+
+ <if k="maxspeed"><output/></if>
+
+ <if k="maxweight"><output/></if>
+ <if k="maxheight"><output/></if>
+ <if k="maxwidth" ><output/></if>
+ <if k="maxlength"><output/></if>
+
+ <!-- Output the name and reference tags -->
+
+ <if k="name"><output/></if>
+ <if k="ref" ><output/></if>
+
+ </way>
+
+ <!-- Relation rules are not currently used -->
+
+ <relation>
+ </relation>
+
+</routino-tagging>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+ $Header: /home/amb/routino/xml/RCS/routino-tagging.xsd,v 1.1 2010/05/18 18:35:01 amb Exp $
+
+ An XML Schema Definition for the Routino tagging rules 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 tagging rules -->
+
+ <xsd:element name="routino-tagging" type="RoutinoTaggingType"/>
+
+ <xsd:complexType name="RoutinoTaggingType">
+ <xsd:sequence>
+ <xsd:element name="node" type="NodeType"/>
+ <xsd:element name="way" type="WayType"/>
+ <xsd:element name="relation" type="RelationType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <!-- The second level node, way and relation tagging rules -->
+
+ <xsd:complexType name="NodeType">
+ </xsd:complexType>
+
+ <xsd:complexType name="WayType">
+ <xsd:sequence>
+ <xsd:element name="if" type="IfType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="RelationType">
+ </xsd:complexType>
+
+ <!-- The if tag and its contents -->
+
+ <xsd:complexType name="IfType">
+ <xsd:sequence>
+ <xsd:element name="set" type="SetType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="output" type="OutputType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="k" type="xsd:string"/>
+ <xsd:attribute name="v" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="SetType">
+ <xsd:attribute name="k" type="xsd:string"/>
+ <xsd:attribute name="v" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="OutputType">
+ <xsd:attribute name="k" type="xsd:string"/>
+ <xsd:attribute name="v" type="xsd:string"/>
+ </xsd:complexType>
+
+</xsd:schema>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+ $Header: /home/amb/routino/xml/RCS/routino-translations.xml,v 1.5 2010/07/03 11:27:37 amb Exp $
+
+ An XML format file containing Routino output translations.
+
+ 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.
+ ============================================================ -->
+
+<routino-translations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-translations.xsd">
+
+ <language lang="en">
+
+ <!-- Copyright of the data being routed, not of this file -->
+ <copyright>
+ <creator string="Creator" text="Routino - http://www.routino.org/" />
+ <source string="Source" text="Based on OpenStreetMap data from 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="Very sharp left" />
+ <turn direction="-3" string="Sharp left" />
+ <turn direction="-2" string="Left" />
+ <turn direction="-1" string="Slight left" />
+ <turn direction="0" string="Straight on" />
+ <turn direction="1" string="Slight right" />
+ <turn direction="2" string="Right" />
+ <turn direction="3" string="Sharp right" />
+ <turn direction="4" string="Very sharp right" />
+
+ <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+ <heading direction="-4" string="South" />
+ <heading direction="-3" string="South-West" />
+ <heading direction="-2" string="West" />
+ <heading direction="-1" string="North-West" />
+ <heading direction="0" string="North" />
+ <heading direction="1" string="North-East" />
+ <heading direction="2" string="East" />
+ <heading direction="3" string="South-East" />
+ <heading direction="4" string="South" />
+
+ <!-- Highway names -->
+ <highway type="motorway" string="motorway" />
+ <highway type="trunk" string="trunk road" />
+ <highway type="primary" string="primary road" />
+ <highway type="secondary" string="secondary road" />
+ <highway type="tertiary" string="tertiary road" />
+ <highway type="unclassified" string="unclassified road" />
+ <highway type="residential" string="residential road" />
+ <highway type="service" string="service road" />
+ <highway type="track" string="track" />
+ <highway type="cycleway" string="cycleway" />
+ <highway type="path" string="path" />
+ <highway type="steps" string="steps" />
+
+ <!-- The type of route -->
+ <route type="shortest" string="Shortest" /> <!-- For the description and route name -->
+ <route type="quickest" string="Quickest" /> <!-- For the description and route name -->
+
+ <!-- HTML output -->
+ <output-html>
+ <waypoint type="waypoint" string="Waypoint" /> <!-- For the chosen waypoints -->
+ <waypoint type="junction" string="Junction" /> <!-- For the interesting junctions -->
+
+ <title text="%s Route" /> <!-- %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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>