Imported Upstream version 1.4.1
authorThibaut GRIDEL <tgridel@free.fr>
Mon, 1 Nov 2010 14:50:45 +0000 (15:50 +0100)
committerThibaut GRIDEL <tgridel@free.fr>
Mon, 1 Nov 2010 14:50:45 +0000 (15:50 +0100)
536 files changed:
ChangeLog [new file with mode: 0644]
INSTALL.txt [new symlink]
Makefile [new file with mode: 0644]
NEWS.txt [new symlink]
README.txt [new symlink]
agpl-3.0.txt [new file with mode: 0644]
doc/ALGORITHM.txt [new file with mode: 0644]
doc/CONFIGURATION.txt [new file with mode: 0644]
doc/DATA.txt [new file with mode: 0644]
doc/INSTALL.txt [new file with mode: 0644]
doc/Makefile [new file with mode: 0644]
doc/NEWS.txt [new file with mode: 0644]
doc/OUTPUT.txt [new file with mode: 0644]
doc/README.txt [new file with mode: 0644]
doc/TAGGING.txt [new file with mode: 0644]
doc/USAGE.txt [new file with mode: 0644]
doc/html/algorithm.html [new file with mode: 0644]
doc/html/configuration.html [new file with mode: 0644]
doc/html/data.html [new file with mode: 0644]
doc/html/example0.png [new file with mode: 0644]
doc/html/example1.png [new file with mode: 0644]
doc/html/example2.png [new file with mode: 0644]
doc/html/index.html [new file with mode: 0644]
doc/html/installation.html [new file with mode: 0644]
doc/html/output.html [new file with mode: 0644]
doc/html/style.css [new file with mode: 0644]
doc/html/tagging.html [new file with mode: 0644]
doc/html/usage.html [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/filedumper.c [new file with mode: 0644]
src/files.c [new file with mode: 0644]
src/functions.h [new file with mode: 0644]
src/functionsx.h [new file with mode: 0644]
src/nodes.c [new file with mode: 0644]
src/nodes.h [new file with mode: 0644]
src/nodesx.c [new file with mode: 0644]
src/nodesx.h [new file with mode: 0644]
src/optimiser.c [new file with mode: 0644]
src/osmparser.c [new file with mode: 0644]
src/output.c [new file with mode: 0644]
src/planetsplitter.c [new file with mode: 0644]
src/profiles.c [new file with mode: 0644]
src/profiles.h [new file with mode: 0644]
src/queue.c [new file with mode: 0644]
src/results.c [new file with mode: 0644]
src/results.h [new file with mode: 0644]
src/router.c [new file with mode: 0644]
src/segments.c [new file with mode: 0644]
src/segments.h [new file with mode: 0644]
src/segmentsx.c [new file with mode: 0644]
src/segmentsx.h [new file with mode: 0644]
src/sorting.c [new file with mode: 0644]
src/superx.c [new file with mode: 0644]
src/superx.h [new file with mode: 0644]
src/tagging.c [new file with mode: 0644]
src/tagging.h [new file with mode: 0644]
src/tagmodifier.c [new file with mode: 0644]
src/translations.c [new file with mode: 0644]
src/translations.h [new file with mode: 0644]
src/types.c [new file with mode: 0644]
src/types.h [new file with mode: 0644]
src/typesx.h [new file with mode: 0644]
src/visualiser.c [new file with mode: 0644]
src/visualiser.h [new file with mode: 0644]
src/ways.c [new file with mode: 0644]
src/ways.h [new file with mode: 0644]
src/waysx.c [new file with mode: 0644]
src/waysx.h [new file with mode: 0644]
src/xml/Makefile [new file with mode: 0644]
src/xml/test/bad-attr-character-ref.xml [new file with mode: 0644]
src/xml/test/bad-attr-entity-ref.xml [new file with mode: 0644]
src/xml/test/bad-cdata-start.xml [new file with mode: 0644]
src/xml/test/bad-comment-ends-triple-dash.xml [new file with mode: 0644]
src/xml/test/bad-double-quote-attr-amp.xml [new file with mode: 0644]
src/xml/test/bad-double-quote-attr-left-angle.xml [new file with mode: 0644]
src/xml/test/bad-double-quote-attr-right-angle.xml [new file with mode: 0644]
src/xml/test/bad-early-end-of-file.xml [new file with mode: 0644]
src/xml/test/bad-end-tag-space-at-begin1.xml [new file with mode: 0644]
src/xml/test/bad-end-tag-space-at-begin2.xml [new file with mode: 0644]
src/xml/test/bad-end-tag-space-at-end.xml [new file with mode: 0644]
src/xml/test/bad-end-tag-with-attr.xml [new file with mode: 0644]
src/xml/test/bad-single-quote-attr-amp.xml [new file with mode: 0644]
src/xml/test/bad-single-quote-attr-left-angle.xml [new file with mode: 0644]
src/xml/test/bad-single-quote-attr-right-angle.xml [new file with mode: 0644]
src/xml/test/bad-start-tag-space-at-begin.xml [new file with mode: 0644]
src/xml/test/bad-tag-attr-no-quotes.xml [new file with mode: 0644]
src/xml/test/bad-tag-attr-space-after-equal.xml [new file with mode: 0644]
src/xml/test/bad-tag-attr-space-before-equal.xml [new file with mode: 0644]
src/xml/test/bad-tag-level-nesting.xml [new file with mode: 0644]
src/xml/test/bad-unbalanced-tag-start-end.xml [new file with mode: 0644]
src/xml/test/bad-unexpected-attribute-name.xml [new file with mode: 0644]
src/xml/test/bad-unexpected-end-tag.xml [new file with mode: 0644]
src/xml/test/bad-unexpected-left-angle.xml [new file with mode: 0644]
src/xml/test/bad-unexpected-right-angle.xml [new file with mode: 0644]
src/xml/test/bad-xml-header-at-begin.xml [new file with mode: 0644]
src/xml/test/bad-xml-header-at-end.xml [new file with mode: 0644]
src/xml/test/bad-xml-header-not-first.xml [new file with mode: 0644]
src/xml/test/good.xml [new file with mode: 0644]
src/xml/test/test.xsd [new file with mode: 0644]
src/xml/xsd-to-xmlparser.c [new file with mode: 0644]
src/xmlparse.h [new file with mode: 0644]
src/xmlparse.l [new file with mode: 0644]
web/INSTALL.txt [new symlink]
web/data/create.sh [new file with mode: 0755]
web/www/openlayers/install.sh [new file with mode: 0755]
web/www/openlayers/routino.cfg [new file with mode: 0644]
web/www/routino/.htaccess [new file with mode: 0644]
web/www/routino/customrouter.cgi [new file with mode: 0755]
web/www/routino/customvisualiser.cgi [new file with mode: 0755]
web/www/routino/icons/ball-0.png [new file with mode: 0644]
web/www/routino/icons/ball-1.png [new file with mode: 0644]
web/www/routino/icons/ball-2.png [new file with mode: 0644]
web/www/routino/icons/ball-3.png [new file with mode: 0644]
web/www/routino/icons/ball-4.png [new file with mode: 0644]
web/www/routino/icons/ball-5.png [new file with mode: 0644]
web/www/routino/icons/ball-6.png [new file with mode: 0644]
web/www/routino/icons/ball-7.png [new file with mode: 0644]
web/www/routino/icons/ball-8.png [new file with mode: 0644]
web/www/routino/icons/ball-9.png [new file with mode: 0644]
web/www/routino/icons/create-icons.pl [new file with mode: 0755]
web/www/routino/icons/home.png [new file with mode: 0644]
web/www/routino/icons/limit-0.0.png [new file with mode: 0644]
web/www/routino/icons/limit-0.png [new file with mode: 0644]
web/www/routino/icons/limit-1.0.png [new file with mode: 0644]
web/www/routino/icons/limit-1.1.png [new file with mode: 0644]
web/www/routino/icons/limit-1.2.png [new file with mode: 0644]
web/www/routino/icons/limit-1.3.png [new file with mode: 0644]
web/www/routino/icons/limit-1.4.png [new file with mode: 0644]
web/www/routino/icons/limit-1.5.png [new file with mode: 0644]
web/www/routino/icons/limit-1.6.png [new file with mode: 0644]
web/www/routino/icons/limit-1.7.png [new file with mode: 0644]
web/www/routino/icons/limit-1.8.png [new file with mode: 0644]
web/www/routino/icons/limit-1.9.png [new file with mode: 0644]
web/www/routino/icons/limit-1.png [new file with mode: 0644]
web/www/routino/icons/limit-10.0.png [new file with mode: 0644]
web/www/routino/icons/limit-10.1.png [new file with mode: 0644]
web/www/routino/icons/limit-10.2.png [new file with mode: 0644]
web/www/routino/icons/limit-10.3.png [new file with mode: 0644]
web/www/routino/icons/limit-10.4.png [new file with mode: 0644]
web/www/routino/icons/limit-10.5.png [new file with mode: 0644]
web/www/routino/icons/limit-10.6.png [new file with mode: 0644]
web/www/routino/icons/limit-10.7.png [new file with mode: 0644]
web/www/routino/icons/limit-10.8.png [new file with mode: 0644]
web/www/routino/icons/limit-10.9.png [new file with mode: 0644]
web/www/routino/icons/limit-10.png [new file with mode: 0644]
web/www/routino/icons/limit-100.png [new file with mode: 0644]
web/www/routino/icons/limit-101.png [new file with mode: 0644]
web/www/routino/icons/limit-102.png [new file with mode: 0644]
web/www/routino/icons/limit-103.png [new file with mode: 0644]
web/www/routino/icons/limit-104.png [new file with mode: 0644]
web/www/routino/icons/limit-105.png [new file with mode: 0644]
web/www/routino/icons/limit-106.png [new file with mode: 0644]
web/www/routino/icons/limit-107.png [new file with mode: 0644]
web/www/routino/icons/limit-108.png [new file with mode: 0644]
web/www/routino/icons/limit-109.png [new file with mode: 0644]
web/www/routino/icons/limit-11.0.png [new file with mode: 0644]
web/www/routino/icons/limit-11.1.png [new file with mode: 0644]
web/www/routino/icons/limit-11.2.png [new file with mode: 0644]
web/www/routino/icons/limit-11.3.png [new file with mode: 0644]
web/www/routino/icons/limit-11.4.png [new file with mode: 0644]
web/www/routino/icons/limit-11.5.png [new file with mode: 0644]
web/www/routino/icons/limit-11.6.png [new file with mode: 0644]
web/www/routino/icons/limit-11.7.png [new file with mode: 0644]
web/www/routino/icons/limit-11.8.png [new file with mode: 0644]
web/www/routino/icons/limit-11.9.png [new file with mode: 0644]
web/www/routino/icons/limit-11.png [new file with mode: 0644]
web/www/routino/icons/limit-110.png [new file with mode: 0644]
web/www/routino/icons/limit-111.png [new file with mode: 0644]
web/www/routino/icons/limit-112.png [new file with mode: 0644]
web/www/routino/icons/limit-113.png [new file with mode: 0644]
web/www/routino/icons/limit-114.png [new file with mode: 0644]
web/www/routino/icons/limit-115.png [new file with mode: 0644]
web/www/routino/icons/limit-116.png [new file with mode: 0644]
web/www/routino/icons/limit-117.png [new file with mode: 0644]
web/www/routino/icons/limit-118.png [new file with mode: 0644]
web/www/routino/icons/limit-119.png [new file with mode: 0644]
web/www/routino/icons/limit-12.0.png [new file with mode: 0644]
web/www/routino/icons/limit-12.1.png [new file with mode: 0644]
web/www/routino/icons/limit-12.2.png [new file with mode: 0644]
web/www/routino/icons/limit-12.3.png [new file with mode: 0644]
web/www/routino/icons/limit-12.4.png [new file with mode: 0644]
web/www/routino/icons/limit-12.5.png [new file with mode: 0644]
web/www/routino/icons/limit-12.6.png [new file with mode: 0644]
web/www/routino/icons/limit-12.7.png [new file with mode: 0644]
web/www/routino/icons/limit-12.8.png [new file with mode: 0644]
web/www/routino/icons/limit-12.9.png [new file with mode: 0644]
web/www/routino/icons/limit-12.png [new file with mode: 0644]
web/www/routino/icons/limit-120.png [new file with mode: 0644]
web/www/routino/icons/limit-121.png [new file with mode: 0644]
web/www/routino/icons/limit-122.png [new file with mode: 0644]
web/www/routino/icons/limit-123.png [new file with mode: 0644]
web/www/routino/icons/limit-124.png [new file with mode: 0644]
web/www/routino/icons/limit-125.png [new file with mode: 0644]
web/www/routino/icons/limit-126.png [new file with mode: 0644]
web/www/routino/icons/limit-127.png [new file with mode: 0644]
web/www/routino/icons/limit-128.png [new file with mode: 0644]
web/www/routino/icons/limit-129.png [new file with mode: 0644]
web/www/routino/icons/limit-13.0.png [new file with mode: 0644]
web/www/routino/icons/limit-13.1.png [new file with mode: 0644]
web/www/routino/icons/limit-13.2.png [new file with mode: 0644]
web/www/routino/icons/limit-13.3.png [new file with mode: 0644]
web/www/routino/icons/limit-13.4.png [new file with mode: 0644]
web/www/routino/icons/limit-13.5.png [new file with mode: 0644]
web/www/routino/icons/limit-13.6.png [new file with mode: 0644]
web/www/routino/icons/limit-13.7.png [new file with mode: 0644]
web/www/routino/icons/limit-13.8.png [new file with mode: 0644]
web/www/routino/icons/limit-13.9.png [new file with mode: 0644]
web/www/routino/icons/limit-13.png [new file with mode: 0644]
web/www/routino/icons/limit-130.png [new file with mode: 0644]
web/www/routino/icons/limit-131.png [new file with mode: 0644]
web/www/routino/icons/limit-132.png [new file with mode: 0644]
web/www/routino/icons/limit-133.png [new file with mode: 0644]
web/www/routino/icons/limit-134.png [new file with mode: 0644]
web/www/routino/icons/limit-135.png [new file with mode: 0644]
web/www/routino/icons/limit-136.png [new file with mode: 0644]
web/www/routino/icons/limit-137.png [new file with mode: 0644]
web/www/routino/icons/limit-138.png [new file with mode: 0644]
web/www/routino/icons/limit-139.png [new file with mode: 0644]
web/www/routino/icons/limit-14.0.png [new file with mode: 0644]
web/www/routino/icons/limit-14.1.png [new file with mode: 0644]
web/www/routino/icons/limit-14.2.png [new file with mode: 0644]
web/www/routino/icons/limit-14.3.png [new file with mode: 0644]
web/www/routino/icons/limit-14.4.png [new file with mode: 0644]
web/www/routino/icons/limit-14.5.png [new file with mode: 0644]
web/www/routino/icons/limit-14.6.png [new file with mode: 0644]
web/www/routino/icons/limit-14.7.png [new file with mode: 0644]
web/www/routino/icons/limit-14.8.png [new file with mode: 0644]
web/www/routino/icons/limit-14.9.png [new file with mode: 0644]
web/www/routino/icons/limit-14.png [new file with mode: 0644]
web/www/routino/icons/limit-140.png [new file with mode: 0644]
web/www/routino/icons/limit-141.png [new file with mode: 0644]
web/www/routino/icons/limit-142.png [new file with mode: 0644]
web/www/routino/icons/limit-143.png [new file with mode: 0644]
web/www/routino/icons/limit-144.png [new file with mode: 0644]
web/www/routino/icons/limit-145.png [new file with mode: 0644]
web/www/routino/icons/limit-146.png [new file with mode: 0644]
web/www/routino/icons/limit-147.png [new file with mode: 0644]
web/www/routino/icons/limit-148.png [new file with mode: 0644]
web/www/routino/icons/limit-149.png [new file with mode: 0644]
web/www/routino/icons/limit-15.0.png [new file with mode: 0644]
web/www/routino/icons/limit-15.1.png [new file with mode: 0644]
web/www/routino/icons/limit-15.2.png [new file with mode: 0644]
web/www/routino/icons/limit-15.3.png [new file with mode: 0644]
web/www/routino/icons/limit-15.4.png [new file with mode: 0644]
web/www/routino/icons/limit-15.5.png [new file with mode: 0644]
web/www/routino/icons/limit-15.6.png [new file with mode: 0644]
web/www/routino/icons/limit-15.7.png [new file with mode: 0644]
web/www/routino/icons/limit-15.8.png [new file with mode: 0644]
web/www/routino/icons/limit-15.9.png [new file with mode: 0644]
web/www/routino/icons/limit-15.png [new file with mode: 0644]
web/www/routino/icons/limit-150.png [new file with mode: 0644]
web/www/routino/icons/limit-151.png [new file with mode: 0644]
web/www/routino/icons/limit-152.png [new file with mode: 0644]
web/www/routino/icons/limit-153.png [new file with mode: 0644]
web/www/routino/icons/limit-154.png [new file with mode: 0644]
web/www/routino/icons/limit-155.png [new file with mode: 0644]
web/www/routino/icons/limit-156.png [new file with mode: 0644]
web/www/routino/icons/limit-157.png [new file with mode: 0644]
web/www/routino/icons/limit-158.png [new file with mode: 0644]
web/www/routino/icons/limit-159.png [new file with mode: 0644]
web/www/routino/icons/limit-16.0.png [new file with mode: 0644]
web/www/routino/icons/limit-16.1.png [new file with mode: 0644]
web/www/routino/icons/limit-16.2.png [new file with mode: 0644]
web/www/routino/icons/limit-16.3.png [new file with mode: 0644]
web/www/routino/icons/limit-16.4.png [new file with mode: 0644]
web/www/routino/icons/limit-16.5.png [new file with mode: 0644]
web/www/routino/icons/limit-16.6.png [new file with mode: 0644]
web/www/routino/icons/limit-16.7.png [new file with mode: 0644]
web/www/routino/icons/limit-16.8.png [new file with mode: 0644]
web/www/routino/icons/limit-16.9.png [new file with mode: 0644]
web/www/routino/icons/limit-16.png [new file with mode: 0644]
web/www/routino/icons/limit-160.png [new file with mode: 0644]
web/www/routino/icons/limit-17.0.png [new file with mode: 0644]
web/www/routino/icons/limit-17.1.png [new file with mode: 0644]
web/www/routino/icons/limit-17.2.png [new file with mode: 0644]
web/www/routino/icons/limit-17.3.png [new file with mode: 0644]
web/www/routino/icons/limit-17.4.png [new file with mode: 0644]
web/www/routino/icons/limit-17.5.png [new file with mode: 0644]
web/www/routino/icons/limit-17.6.png [new file with mode: 0644]
web/www/routino/icons/limit-17.7.png [new file with mode: 0644]
web/www/routino/icons/limit-17.8.png [new file with mode: 0644]
web/www/routino/icons/limit-17.9.png [new file with mode: 0644]
web/www/routino/icons/limit-17.png [new file with mode: 0644]
web/www/routino/icons/limit-18.0.png [new file with mode: 0644]
web/www/routino/icons/limit-18.1.png [new file with mode: 0644]
web/www/routino/icons/limit-18.2.png [new file with mode: 0644]
web/www/routino/icons/limit-18.3.png [new file with mode: 0644]
web/www/routino/icons/limit-18.4.png [new file with mode: 0644]
web/www/routino/icons/limit-18.5.png [new file with mode: 0644]
web/www/routino/icons/limit-18.6.png [new file with mode: 0644]
web/www/routino/icons/limit-18.7.png [new file with mode: 0644]
web/www/routino/icons/limit-18.8.png [new file with mode: 0644]
web/www/routino/icons/limit-18.9.png [new file with mode: 0644]
web/www/routino/icons/limit-18.png [new file with mode: 0644]
web/www/routino/icons/limit-19.0.png [new file with mode: 0644]
web/www/routino/icons/limit-19.1.png [new file with mode: 0644]
web/www/routino/icons/limit-19.2.png [new file with mode: 0644]
web/www/routino/icons/limit-19.3.png [new file with mode: 0644]
web/www/routino/icons/limit-19.4.png [new file with mode: 0644]
web/www/routino/icons/limit-19.5.png [new file with mode: 0644]
web/www/routino/icons/limit-19.6.png [new file with mode: 0644]
web/www/routino/icons/limit-19.7.png [new file with mode: 0644]
web/www/routino/icons/limit-19.8.png [new file with mode: 0644]
web/www/routino/icons/limit-19.9.png [new file with mode: 0644]
web/www/routino/icons/limit-19.png [new file with mode: 0644]
web/www/routino/icons/limit-2.0.png [new file with mode: 0644]
web/www/routino/icons/limit-2.1.png [new file with mode: 0644]
web/www/routino/icons/limit-2.2.png [new file with mode: 0644]
web/www/routino/icons/limit-2.3.png [new file with mode: 0644]
web/www/routino/icons/limit-2.4.png [new file with mode: 0644]
web/www/routino/icons/limit-2.5.png [new file with mode: 0644]
web/www/routino/icons/limit-2.6.png [new file with mode: 0644]
web/www/routino/icons/limit-2.7.png [new file with mode: 0644]
web/www/routino/icons/limit-2.8.png [new file with mode: 0644]
web/www/routino/icons/limit-2.9.png [new file with mode: 0644]
web/www/routino/icons/limit-2.png [new file with mode: 0644]
web/www/routino/icons/limit-20.0.png [new file with mode: 0644]
web/www/routino/icons/limit-20.png [new file with mode: 0644]
web/www/routino/icons/limit-21.png [new file with mode: 0644]
web/www/routino/icons/limit-22.png [new file with mode: 0644]
web/www/routino/icons/limit-23.png [new file with mode: 0644]
web/www/routino/icons/limit-24.png [new file with mode: 0644]
web/www/routino/icons/limit-25.png [new file with mode: 0644]
web/www/routino/icons/limit-26.png [new file with mode: 0644]
web/www/routino/icons/limit-27.png [new file with mode: 0644]
web/www/routino/icons/limit-28.png [new file with mode: 0644]
web/www/routino/icons/limit-29.png [new file with mode: 0644]
web/www/routino/icons/limit-3.0.png [new file with mode: 0644]
web/www/routino/icons/limit-3.1.png [new file with mode: 0644]
web/www/routino/icons/limit-3.2.png [new file with mode: 0644]
web/www/routino/icons/limit-3.3.png [new file with mode: 0644]
web/www/routino/icons/limit-3.4.png [new file with mode: 0644]
web/www/routino/icons/limit-3.5.png [new file with mode: 0644]
web/www/routino/icons/limit-3.6.png [new file with mode: 0644]
web/www/routino/icons/limit-3.7.png [new file with mode: 0644]
web/www/routino/icons/limit-3.8.png [new file with mode: 0644]
web/www/routino/icons/limit-3.9.png [new file with mode: 0644]
web/www/routino/icons/limit-3.png [new file with mode: 0644]
web/www/routino/icons/limit-30.png [new file with mode: 0644]
web/www/routino/icons/limit-31.png [new file with mode: 0644]
web/www/routino/icons/limit-32.png [new file with mode: 0644]
web/www/routino/icons/limit-33.png [new file with mode: 0644]
web/www/routino/icons/limit-34.png [new file with mode: 0644]
web/www/routino/icons/limit-35.png [new file with mode: 0644]
web/www/routino/icons/limit-36.png [new file with mode: 0644]
web/www/routino/icons/limit-37.png [new file with mode: 0644]
web/www/routino/icons/limit-38.png [new file with mode: 0644]
web/www/routino/icons/limit-39.png [new file with mode: 0644]
web/www/routino/icons/limit-4.0.png [new file with mode: 0644]
web/www/routino/icons/limit-4.1.png [new file with mode: 0644]
web/www/routino/icons/limit-4.2.png [new file with mode: 0644]
web/www/routino/icons/limit-4.3.png [new file with mode: 0644]
web/www/routino/icons/limit-4.4.png [new file with mode: 0644]
web/www/routino/icons/limit-4.5.png [new file with mode: 0644]
web/www/routino/icons/limit-4.6.png [new file with mode: 0644]
web/www/routino/icons/limit-4.7.png [new file with mode: 0644]
web/www/routino/icons/limit-4.8.png [new file with mode: 0644]
web/www/routino/icons/limit-4.9.png [new file with mode: 0644]
web/www/routino/icons/limit-4.png [new file with mode: 0644]
web/www/routino/icons/limit-40.png [new file with mode: 0644]
web/www/routino/icons/limit-41.png [new file with mode: 0644]
web/www/routino/icons/limit-42.png [new file with mode: 0644]
web/www/routino/icons/limit-43.png [new file with mode: 0644]
web/www/routino/icons/limit-44.png [new file with mode: 0644]
web/www/routino/icons/limit-45.png [new file with mode: 0644]
web/www/routino/icons/limit-46.png [new file with mode: 0644]
web/www/routino/icons/limit-47.png [new file with mode: 0644]
web/www/routino/icons/limit-48.png [new file with mode: 0644]
web/www/routino/icons/limit-49.png [new file with mode: 0644]
web/www/routino/icons/limit-5.0.png [new file with mode: 0644]
web/www/routino/icons/limit-5.1.png [new file with mode: 0644]
web/www/routino/icons/limit-5.2.png [new file with mode: 0644]
web/www/routino/icons/limit-5.3.png [new file with mode: 0644]
web/www/routino/icons/limit-5.4.png [new file with mode: 0644]
web/www/routino/icons/limit-5.5.png [new file with mode: 0644]
web/www/routino/icons/limit-5.6.png [new file with mode: 0644]
web/www/routino/icons/limit-5.7.png [new file with mode: 0644]
web/www/routino/icons/limit-5.8.png [new file with mode: 0644]
web/www/routino/icons/limit-5.9.png [new file with mode: 0644]
web/www/routino/icons/limit-5.png [new file with mode: 0644]
web/www/routino/icons/limit-50.png [new file with mode: 0644]
web/www/routino/icons/limit-51.png [new file with mode: 0644]
web/www/routino/icons/limit-52.png [new file with mode: 0644]
web/www/routino/icons/limit-53.png [new file with mode: 0644]
web/www/routino/icons/limit-54.png [new file with mode: 0644]
web/www/routino/icons/limit-55.png [new file with mode: 0644]
web/www/routino/icons/limit-56.png [new file with mode: 0644]
web/www/routino/icons/limit-57.png [new file with mode: 0644]
web/www/routino/icons/limit-58.png [new file with mode: 0644]
web/www/routino/icons/limit-59.png [new file with mode: 0644]
web/www/routino/icons/limit-6.0.png [new file with mode: 0644]
web/www/routino/icons/limit-6.1.png [new file with mode: 0644]
web/www/routino/icons/limit-6.2.png [new file with mode: 0644]
web/www/routino/icons/limit-6.3.png [new file with mode: 0644]
web/www/routino/icons/limit-6.4.png [new file with mode: 0644]
web/www/routino/icons/limit-6.5.png [new file with mode: 0644]
web/www/routino/icons/limit-6.6.png [new file with mode: 0644]
web/www/routino/icons/limit-6.7.png [new file with mode: 0644]
web/www/routino/icons/limit-6.8.png [new file with mode: 0644]
web/www/routino/icons/limit-6.9.png [new file with mode: 0644]
web/www/routino/icons/limit-6.png [new file with mode: 0644]
web/www/routino/icons/limit-60.png [new file with mode: 0644]
web/www/routino/icons/limit-61.png [new file with mode: 0644]
web/www/routino/icons/limit-62.png [new file with mode: 0644]
web/www/routino/icons/limit-63.png [new file with mode: 0644]
web/www/routino/icons/limit-64.png [new file with mode: 0644]
web/www/routino/icons/limit-65.png [new file with mode: 0644]
web/www/routino/icons/limit-66.png [new file with mode: 0644]
web/www/routino/icons/limit-67.png [new file with mode: 0644]
web/www/routino/icons/limit-68.png [new file with mode: 0644]
web/www/routino/icons/limit-69.png [new file with mode: 0644]
web/www/routino/icons/limit-7.0.png [new file with mode: 0644]
web/www/routino/icons/limit-7.1.png [new file with mode: 0644]
web/www/routino/icons/limit-7.2.png [new file with mode: 0644]
web/www/routino/icons/limit-7.3.png [new file with mode: 0644]
web/www/routino/icons/limit-7.4.png [new file with mode: 0644]
web/www/routino/icons/limit-7.5.png [new file with mode: 0644]
web/www/routino/icons/limit-7.6.png [new file with mode: 0644]
web/www/routino/icons/limit-7.7.png [new file with mode: 0644]
web/www/routino/icons/limit-7.8.png [new file with mode: 0644]
web/www/routino/icons/limit-7.9.png [new file with mode: 0644]
web/www/routino/icons/limit-7.png [new file with mode: 0644]
web/www/routino/icons/limit-70.png [new file with mode: 0644]
web/www/routino/icons/limit-71.png [new file with mode: 0644]
web/www/routino/icons/limit-72.png [new file with mode: 0644]
web/www/routino/icons/limit-73.png [new file with mode: 0644]
web/www/routino/icons/limit-74.png [new file with mode: 0644]
web/www/routino/icons/limit-75.png [new file with mode: 0644]
web/www/routino/icons/limit-76.png [new file with mode: 0644]
web/www/routino/icons/limit-77.png [new file with mode: 0644]
web/www/routino/icons/limit-78.png [new file with mode: 0644]
web/www/routino/icons/limit-79.png [new file with mode: 0644]
web/www/routino/icons/limit-8.0.png [new file with mode: 0644]
web/www/routino/icons/limit-8.1.png [new file with mode: 0644]
web/www/routino/icons/limit-8.2.png [new file with mode: 0644]
web/www/routino/icons/limit-8.3.png [new file with mode: 0644]
web/www/routino/icons/limit-8.4.png [new file with mode: 0644]
web/www/routino/icons/limit-8.5.png [new file with mode: 0644]
web/www/routino/icons/limit-8.6.png [new file with mode: 0644]
web/www/routino/icons/limit-8.7.png [new file with mode: 0644]
web/www/routino/icons/limit-8.8.png [new file with mode: 0644]
web/www/routino/icons/limit-8.9.png [new file with mode: 0644]
web/www/routino/icons/limit-8.png [new file with mode: 0644]
web/www/routino/icons/limit-80.png [new file with mode: 0644]
web/www/routino/icons/limit-81.png [new file with mode: 0644]
web/www/routino/icons/limit-82.png [new file with mode: 0644]
web/www/routino/icons/limit-83.png [new file with mode: 0644]
web/www/routino/icons/limit-84.png [new file with mode: 0644]
web/www/routino/icons/limit-85.png [new file with mode: 0644]
web/www/routino/icons/limit-86.png [new file with mode: 0644]
web/www/routino/icons/limit-87.png [new file with mode: 0644]
web/www/routino/icons/limit-88.png [new file with mode: 0644]
web/www/routino/icons/limit-89.png [new file with mode: 0644]
web/www/routino/icons/limit-9.0.png [new file with mode: 0644]
web/www/routino/icons/limit-9.1.png [new file with mode: 0644]
web/www/routino/icons/limit-9.2.png [new file with mode: 0644]
web/www/routino/icons/limit-9.3.png [new file with mode: 0644]
web/www/routino/icons/limit-9.4.png [new file with mode: 0644]
web/www/routino/icons/limit-9.5.png [new file with mode: 0644]
web/www/routino/icons/limit-9.6.png [new file with mode: 0644]
web/www/routino/icons/limit-9.7.png [new file with mode: 0644]
web/www/routino/icons/limit-9.8.png [new file with mode: 0644]
web/www/routino/icons/limit-9.9.png [new file with mode: 0644]
web/www/routino/icons/limit-9.png [new file with mode: 0644]
web/www/routino/icons/limit-90.png [new file with mode: 0644]
web/www/routino/icons/limit-91.png [new file with mode: 0644]
web/www/routino/icons/limit-92.png [new file with mode: 0644]
web/www/routino/icons/limit-93.png [new file with mode: 0644]
web/www/routino/icons/limit-94.png [new file with mode: 0644]
web/www/routino/icons/limit-95.png [new file with mode: 0644]
web/www/routino/icons/limit-96.png [new file with mode: 0644]
web/www/routino/icons/limit-97.png [new file with mode: 0644]
web/www/routino/icons/limit-98.png [new file with mode: 0644]
web/www/routino/icons/limit-99.png [new file with mode: 0644]
web/www/routino/icons/limit-no.png [new file with mode: 0644]
web/www/routino/icons/marker-0-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-0-red.png [new file with mode: 0644]
web/www/routino/icons/marker-1-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-1-red.png [new file with mode: 0644]
web/www/routino/icons/marker-2-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-2-red.png [new file with mode: 0644]
web/www/routino/icons/marker-3-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-3-red.png [new file with mode: 0644]
web/www/routino/icons/marker-4-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-4-red.png [new file with mode: 0644]
web/www/routino/icons/marker-5-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-5-red.png [new file with mode: 0644]
web/www/routino/icons/marker-6-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-6-red.png [new file with mode: 0644]
web/www/routino/icons/marker-7-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-7-red.png [new file with mode: 0644]
web/www/routino/icons/marker-8-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-8-red.png [new file with mode: 0644]
web/www/routino/icons/marker-9-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-9-red.png [new file with mode: 0644]
web/www/routino/icons/marker-home-grey.png [new file with mode: 0644]
web/www/routino/icons/marker-home-red.png [new file with mode: 0644]
web/www/routino/icons/waypoint-add.png [new file with mode: 0644]
web/www/routino/icons/waypoint-centre.png [new file with mode: 0644]
web/www/routino/icons/waypoint-down.png [new file with mode: 0644]
web/www/routino/icons/waypoint-home.png [new file with mode: 0644]
web/www/routino/icons/waypoint-remove.png [new file with mode: 0644]
web/www/routino/icons/waypoint-up.png [new file with mode: 0644]
web/www/routino/index.html [new file with mode: 0644]
web/www/routino/maplayout-ie6-bugfixes.css [new file with mode: 0644]
web/www/routino/maplayout-ie7-bugfixes.css [new file with mode: 0644]
web/www/routino/maplayout.css [new file with mode: 0644]
web/www/routino/noscript.cgi [new file with mode: 0755]
web/www/routino/noscript.html [new file with mode: 0644]
web/www/routino/noscript.template.html [new file with mode: 0644]
web/www/routino/page-elements.css [new file with mode: 0644]
web/www/routino/page-elements.js [new file with mode: 0644]
web/www/routino/paths.pl [new file with mode: 0644]
web/www/routino/results.cgi [new file with mode: 0755]
web/www/routino/router.cgi [new file with mode: 0755]
web/www/routino/router.css [new file with mode: 0644]
web/www/routino/router.html [new symlink]
web/www/routino/router.html.en [new file with mode: 0644]
web/www/routino/router.js [new file with mode: 0644]
web/www/routino/router.pl [new file with mode: 0644]
web/www/routino/statistics.cgi [new file with mode: 0755]
web/www/routino/visualiser.cgi [new file with mode: 0755]
web/www/routino/visualiser.css [new file with mode: 0644]
web/www/routino/visualiser.html [new file with mode: 0644]
web/www/routino/visualiser.js [new file with mode: 0644]
xml/Makefile [new file with mode: 0644]
xml/osm.xsd [new file with mode: 0644]
xml/routino-osm.xsd [new file with mode: 0644]
xml/routino-profiles.xml [new file with mode: 0644]
xml/routino-profiles.xsd [new file with mode: 0644]
xml/routino-tagging-nomodify.xml [new file with mode: 0644]
xml/routino-tagging.xml [new file with mode: 0644]
xml/routino-tagging.xsd [new file with mode: 0644]
xml/routino-translations.xml [new file with mode: 0644]
xml/routino-translations.xsd [new file with mode: 0644]
xml/xsd.xsd [new file with mode: 0644]

diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..7c79159
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,1732 @@
+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.
+
diff --git a/INSTALL.txt b/INSTALL.txt
new file mode 120000 (symlink)
index 0000000..b0385da
--- /dev/null
@@ -0,0 +1 @@
+doc/INSTALL.txt
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..b6ee933
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,45 @@
+# $Header: /home/amb/routino/RCS/Makefile,v 1.3 2010/05/31 12:44:43 amb Exp $
+#
+# Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2009-2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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
diff --git a/NEWS.txt b/NEWS.txt
new file mode 120000 (symlink)
index 0000000..7a887e7
--- /dev/null
+++ b/NEWS.txt
@@ -0,0 +1 @@
+doc/NEWS.txt
\ No newline at end of file
diff --git a/README.txt b/README.txt
new file mode 120000 (symlink)
index 0000000..253de0c
--- /dev/null
@@ -0,0 +1 @@
+doc/README.txt
\ No newline at end of file
diff --git a/agpl-3.0.txt b/agpl-3.0.txt
new file mode 100644 (file)
index 0000000..dba13ed
--- /dev/null
@@ -0,0 +1,661 @@
+                    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/>.
diff --git a/doc/ALGORITHM.txt b/doc/ALGORITHM.txt
new file mode 100644 (file)
index 0000000..2432a88
--- /dev/null
@@ -0,0 +1,212 @@
+                             Routino : Algorithm
+                             ===================
+
+
+   This page describes the development of the algorithm that is used in
+   Routino for finding routes.
+
+
+Simplest Algorithm
+------------------
+
+   The algorithm to find a route is fundamentally simple: Start at the
+   beginning, follow all possible routes and keep going until you reach
+   the end.
+
+   While this method does work, it isn't fast. To be able to find a route
+   quickly needs a different algorithm, one that can find the correct
+   answer without wasting time on routes that lead nowhere.
+
+
+Improved Algorithm
+------------------
+
+   The simplest way to do this is to follow all possible segments from the
+   starting node to the next nearest node (an intermediate node in the
+   complete journey). For each node that is reached store the shortest
+   route from the starting node and the length of that route. The list of
+   intermediate nodes needs to be maintained in order of shortest overall
+   route on the assumption that there is a straight line route from here
+   to the end node.
+   At each point the intermediate node that has the shortest potential
+   overall journey time is processed before any other node. From the first
+   node in the list follow all possible segments and place the newly
+   discovered nodes into the same list ordered in the same way. This will
+   tend to constrain the list of nodes examined to be the ones that are
+   between the start and end nodes. If at any point you reach a node that
+   has already been reached by a longer route then you can discard that
+   route since the newly discovered route is shorter. Conversely if the
+   previously discovered route is shorter then discard the new route.
+   At some point the end node will be reached and then any routes with
+   potential lengths longer than this actual route can be immediately
+   discarded. The few remaining potential routes must be continued until
+   they are found to be shorter or have no possibility of being shorter.
+   The shortest possible route is then found.
+
+   At all times when looking at a node only those segments that are
+   possible by the chosen means of transport are followed. This allows the
+   type of transport to be handled easily. When finding the quickest route
+   the same rules apply except that criterion for sorting is the shortest
+   potential route (assuming that from each node to the end is the fastest
+   possible type of highway).
+
+   This method also works, but again it isn't very fast. The problem is
+   that the complexity is proportional to the number of nodes or segments
+   in all routes examined between the start and end nodes. Maintaining the
+   list of intermediate nodes in order is the most complex part.
+
+
+Final Algorithm
+---------------
+
+   The final algorithm that is implemented in the router is basically the
+   one above but with an important difference. Instead of finding a long
+   route among a data set of 8,000,000 nodes (number of highway nodes in
+   UK at beginning of 2010) it finds one long route in a data set of
+   1,000,000 nodes and a few hundred very short routes in the full data
+   set. Since the time taken to find a route is proportional to the number
+   of nodes the main route takes 1/10th of the time and the very short
+   routes take almost no time at all.
+
+   The solution to making the algorithm fast is therefore to discard most
+   of the nodes and only keep the interesting ones. In this case a node is
+   deemed to be interesting if it is the junction of two segments with
+   different properties. In the algorithm these are classed as
+   super-nodes. Starting at each super-node a super-segment is generated
+   that finishes on another super-node and contains the shortest path
+   along segments with identical properties (and these properties are
+   inherited by the super-segment). The point of choosing the shortest
+   route is that since all segments considered have identical properties
+   they will be treated identically when properties are taken into
+   account. This decision making process can be repeated until the only
+   the most important and interesting nodes remain.
+
+   To find a route between a start and finish point now comprises the
+   following steps (assuming a shortest route is required):
+
+    1. Find all shortest routes from the start point along normal segments
+       and stopping when super-nodes are reached.
+    2. Find all shortest routes from the end point backwards along normal
+       segments and stopping when super-nodes are reached.
+    3. Find the shortest route along super-segments from the set of
+       super-nodes in step 1 to the set of super-nodes in step 2 (taking
+       into account the lengths found in steps 1 and 2 between the
+       start/finish super-nodes and the ultimate start/finish point).
+    4. For each super-segment in step 3 find the shortest route between
+       the two end-point super-nodes.
+
+   This multi-step process is considerably quicker than using all nodes
+   but gives a result that still contains the full list of nodes that are
+   visited. There are some special cases though, for example very short
+   routes that do not pass through any super-nodes, or routes that start
+   or finish on a super-node. In these cases one or more of the steps
+   listed can be removed or simplified.
+
+Routing Preferences
+
+   One of the important features of Routino is the ability to select a
+   route that is optimum for a set of criteria such as preferences for
+   each type of highway, speed limits and other restrictions and highway
+   properties.
+
+   All of these features are handled by assigning a score to each segment
+   while calculating the route and trying to minimise the score rather
+   than simply minimising the length.
+
+   Segment length
+          When calculating the shortest route the length of the segment is
+          the starting point for the score.
+
+   Speed preference
+          When calculating the quickest route the time taken calculated
+          from the length of the segment and the lower of the highway's
+          own speed limit and the user's speed preference for the type of
+          highway is the starting point for the score.
+
+   Oneway restriction
+          If a highway has the oneway property in the opposite direction
+          to the desired travel and the user's preference is to obey
+          oneway restrictions then the segment is ignored.
+
+   Weight, height, width & length limits
+          If a highway has one of these limits and its value is less than
+          the user's specified requirement then the segment is ignored.
+
+   Highway preference
+          The highway preference specified by the user is a percentage,
+          these are scaled so that the most preferred highway type has a
+          weighted preference of 1.0 (0% always has a weighted preference
+          of 0.0). The calculated score for a segment is divided by this
+          weighted preference.
+
+   Highway properties
+          The other highway properties are specified by the user as a
+          percentage and each highway either has that property or not. The
+          user's property preference is scaled into the range 0.0 (for 0%)
+          to 2.0 (for 100%) to give a weighted preference, a second
+          "non-property" weighted preference is calcuated in the same way
+          after subtracting the user's preference from 100%. If a segment
+          has this property then the calculated score is divided by the
+          weighted preference, if the segment does not have this property
+          then it is divided by the non-property weighted preference.
+
+Implementation
+--------------
+
+   The hardest part of implementing this router is the data organisation.
+   The arrangement of the data to minimise the number of operations
+   required to follow a route from one node to another is much harder than
+   designing the algorithm itself.
+
+   The final implementation uses a separate table for nodes, segments and
+   ways. Each table individually is implemented as a C-language data
+   structure that is written to disk by a program which parses the
+   OpenStreetMap XML data file. In the router these data structures are
+   memory mapped so that the operating system handles the problems of
+   loading the needed data blocks from disk.
+
+   Each node contains a latitude and longitude and they are sorted
+   geographically so that converting a latitude and longitude coordinate
+   to a node is fast as well as looking up the coordinate of a node. The
+   node also contains the location in the array of segments for the first
+   segment that uses that node.
+   Each segment contains the location of the two nodes as well as the way
+   that the segment came from. The location of the next segment that uses
+   one of the two nodes is also stored; the next segment for the other
+   node is the following one in the array. The length of the segment is
+   also pre-computed and stored.
+   Each way has a name, a highway type, a list of allowed types of
+   traffic, a speed limit, any weight, height, width or length
+   restrictions and the highway properties.
+
+   The super-nodes are mixed in with the nodes and the super-segments are
+   mixed in with the segments. For the nodes they are the same as the
+   normal nodes, so just a flag is needed to indicate that they are super.
+   The super-segments are in addition to the normal segments so they
+   increase the database size (by about 10%) and are also marked with a
+   flag.
+
+
+Practicalities
+--------------
+
+   At the time of writing (April 2010) the OpenStreetMap data for Great
+   Britain (taken from GeoFabrik) contains:
+     * 14,675,098 nodes
+          + 8,767,521 are highway nodes
+          + 1,120,297 are super-nodes
+     * 1,876,822 ways
+          + 1,412,898 are highways
+               o 9,316,328 highway segments
+               o 1,641,009 are super-segments
+     * 60,572 relations
+
+   The database files when generated are 41.5 MB for nodes, 121.6 MB for
+   segments and 12.6 MB for ways and are stored uncompressed. By having at
+   least 200 MB or RAM available the routing can be performed with no disk
+   accesses (once the data has been read once).
+
+
+--------
+
+Copyright 2008-2010 Andrew M. Bishop.
diff --git a/doc/CONFIGURATION.txt b/doc/CONFIGURATION.txt
new file mode 100644 (file)
index 0000000..fa6ae48
--- /dev/null
@@ -0,0 +1,177 @@
+                           Routino : Configuration
+                           =======================
+
+
+   New in version 1.4 of Routino is the use of configuration files to
+   allow more information to be provided to the programs at run-time. The
+   configuration files that are used are:
+     * Tagging transformation rules for the planetsplitter program.
+     * Routing profiles for the router program.
+     * Output translations for the router program.
+
+   In keeping with the nature of the input and output files the
+   configuration files are also XML files. Each of the files uses a custom
+   defined XML schema and an XSD file is provided for each of them.
+
+
+Tag Transformation Rules
+------------------------
+
+   The default name of the tagging transformation rules XML configuration
+   file is tagging.xml in the same directory as the generated database
+   files. Other filenames can be specified on the command line using the
+   --tagging option. When processing the input it is possible to have a
+   different set of tagging rules for each file; for example different
+   rules for different countries.
+
+   The tagging rules allow modifying the highway tags in the source file
+   so that the routing can be performed on a simpler set of tags. This
+   removes the special case tagging rules from the source code into the
+   configuration file where they can be easily modified. Part of the
+   provided tagging.xml file showing the rules for motorway_link and
+   motorway highway types.
+
+<?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.
diff --git a/doc/DATA.txt b/doc/DATA.txt
new file mode 100644 (file)
index 0000000..8cd61ed
--- /dev/null
@@ -0,0 +1,115 @@
+                               Routino : Data
+                               ==============
+
+
+   A router relies on data to be able to find a route.
+
+
+OpenStreetMap Data
+------------------
+
+   The data that is collected by the OpenStreetMap project consists of
+   nodes, ways and relations.
+
+   Node
+          A node is a point that has a latitude and longitude and
+          attributes that describe what type of point it is (part of a way
+          or a place of interest for example).
+
+   Way
+          A way is a collection of nodes that when joined together define
+          something (for example a road, a ralway, a boundary, a building,
+          a lake etc). The ways also have attributes that define them
+          (speed limits, type of road and restrictions for example).
+
+   Relation
+          A relation is a collection of items (usually ways) that are
+          related to each other for some reason (highways that make up a
+          route for example).
+
+   The OpenStreetMap Wiki explains the data much better than I can.
+
+
+Router Data
+-----------
+
+   The information that is needed by a routing algorithm is only a subset
+   of the information that is collected by the OpenStreetMap project. For
+   routing what is required is information about the location of roads (or
+   other highways), the connections between the highways and the
+   properties of those highways.
+
+   Location of highways (nodes)
+          The locations of things is provided by the nodes from the
+          OpenStreetMap data. The nodes are the only things that have
+          coordinates in OpenStreetMap and everything else is made up by
+          reference to them. Not all of the nodes are useful, only the
+          ones that are part of highways. The location of the nodes is
+          stored but none of the other attributes are currently used by
+          the router.
+
+   Location of highways (ways)
+          The location of the highways is defined in the OpenStreetMap
+          data by the ways. Only the highway ways are useful and the other
+          ways are discarded. What remains is lists of nodes that join
+          together to form a section of highway. This is further split
+          into segments which are individual parts of a way connected by
+          two nodes.
+
+   Properties of highways (tags)
+          The ways that belong to highways are extracted from the data in
+          the previous step and for each way the useful information for
+          routing is stored. For the router the useful information is the
+          type of highway, the speed limit, the allowed types of transport
+          and other restrictions (one-way, min height, max weight etc).
+
+   Connections between highways
+          The connections between highways are defined in the
+          OpenStreetMap data by ways that share nodes. Since the ways may
+          join in the middle and not just the ends it is the segments
+          defined above that are not part of the OpenStreetMap data that
+          are most important.
+
+   The information that is extracted from the OpenStreetMap data is stored
+   in an optimised way that allows the routing to be performed quickly.
+
+
+Interpreting Data Tags
+----------------------
+
+   The tags are the information that is attached to the nodes and ways in
+   OpenStreetMap. The router needs to interpret these tags and use them
+   when deciding what type of traffic can use a highway (for example).
+
+   There are no well defined rules in OpenStreetMap about tagging, but
+   there is guidance on the OpenStreetMap Wiki "Map_Features" page. This
+   describes a set of recommended tags but these are not universally used
+   so it is up to each application how to interpret them.
+
+   The tagging rules that the router uses are very important in
+   controlling how the router works. With Routino the data tags can be
+   modified when the data is imported to allow customisation of the
+   information used for routing.
+
+
+Problems With OpenStreetMap Data
+--------------------------------
+
+   The route that can be found is only as good as the data that is
+   available. This is not intended as a criticism of the OpenStreetMap
+   data; it is generally good.
+
+   There are some problems that are well known and which affect the
+   router. For example highways might be missing because nobody has mapped
+   them. A highway may be wrongly tagged with incorrect properties, or a
+   highway might be missing important tags for routing (e.g. speed
+   limits). There can also be problems with highways that should join but
+   don't because they do not share nodes.
+
+   A lot of these problems can be found using the interactive data
+   visualiser that uses the same Routino rouing database.
+
+
+--------
+
+Copyright 2008-2010 Andrew M. Bishop.
diff --git a/doc/INSTALL.txt b/doc/INSTALL.txt
new file mode 100644 (file)
index 0000000..123f02c
--- /dev/null
@@ -0,0 +1,158 @@
+                           Routino : Installation
+                           ======================
+
+
+Compilation
+-----------
+
+   This program has been written to run on Linux, no cross-platform
+   compatibility has been specifically included but on the other hand
+   nothing platform specific has been knowingly included either.
+
+   Any information on improving the compilation process on anything other
+   than 32-bit x86 Linux is welcome.
+
+   No external libraries are required and the programs are written in
+   standard C language.
+
+   To compile the programs just type 'make'.
+
+
+Installation
+------------
+
+   After compilation the executable files are copied into the directory
+   web/bin and the default XML configuration files are copied into the
+   directory web/data. This is in preparation for using the supplied
+   example web pages but is also a useful location to copy the files from
+   for normal use.
+
+   The executable files are called 'planetsplitter', 'router' and 'filedumper'
+   (also 'tagmodifier' for debugging tag modifications). They can be copied
+   to any location and need no special installation environment.
+
+   The default configuration files are called 'profiles.xml', 'tagging.xml'
+   and 'translations.xml'. The names of the configuration files can be
+   specified on the command line but by default are also looked for in the
+   directory that contains the routing database.
+
+
+Example Web Page
+----------------
+
+   The directory 'web' contains a set of files that can be used to create a
+   working set of web pages with interfaces to the routing algorithm.
+
+   The files in the 'web' directory will require copying to a location that
+   is accessible by a web server. After copying the files some of them
+   need to be edited; search through the files for lines that contain the
+   words "EDIT THIS" and make appropriate edits. The files that need
+   editing are 'paths.pl' (to set the directory paths) and 'router.js' and
+   'visualiser.js' to limit the range of the visible map (latitude,
+   longitude and zoom).
+
+
+Configuration of web files
+--------------------------
+
+   The assumption in this description is that the whole of the directory
+   called web is copied into a directory that is accessible by an Apache
+   web server.
+
+    **************************************************************************
+    **** This is not a secure configuration but an easy one to configure. ****
+    **** Only the directory 'www' should be accessible by the web server. ****
+    **** Do not use this configuration unmodified in a public web server. ****
+    **************************************************************************
+
+   The directory structure is as follows:
+
+   web/
+    |
+    + /bin/                    <- The Routino executable files (when compiled).
+    |
+    + /data/                   <- The Routino database and default configuration
+    |                             files.
+    |
+    + /results/                <- An empty directory to store the results.
+    |
+    + /www/                    <- The files that must be available to the web
+        |                         server are below this level.
+        |
+        + /openlayers/         <- A directory to hold the OpenLayers scripts.
+        |
+        + /routino/            <- The main HTML, Javascript, CSS and CGI files.
+
+
+   The directory 'bin' will be filled by running the compilation process.
+   For a secure installation the 'bin' directory should be outside of the
+   web server, the file 'www/routino/paths.pl' contains the path to the 'bin'
+   directory.
+
+   The directory 'data' must contain the Routino database and is also the
+   default location for the configuration files. The routing database is
+   created by downloading the OSM files for the region of interest and
+   running the 'planetsplitter' program. There is a script in the directory
+   that will download the OSM files and create the required database. The
+   script should be edited to set the names of the files to be downloaded.
+   For a secure installation the 'data' directory should be outside of the
+   web server, the file 'www/routino/paths.pl' contains the path to the 'data'
+   directory.
+
+   The directory 'results' is a temporary directory that it used to hold the
+   GPX and text files generated by the Routino router. The directory must
+   be writable by the web server process since it is the CGI scripts that
+   are run by the web server that writes the results here. For a secure
+   installation the results directory should be outside of the web server,
+   the file 'www/routino/paths.pl' contains the path to the results
+   directory.
+
+   The directory 'www' and its sub-directories are the only ones that need
+   to be within the web server accessible directory.
+
+   The directory 'www/openlayers' must be filled with the openlayers
+   Javascript library that can be downloaded from
+   http://www.openlayers.org/. (This version of Routino has been tested
+   with OpenLayers library version 2.8). The files must be installed so
+   that the file 'www/openlayers/OpenLayers.js' and the directories
+   'www/openlayers/img/', 'www/openlayers/theme/' all exist. There is a script
+   in the directory that will automatically download and organise the
+   files.
+
+   The directory 'www/routino' contains the main HTML, Javascript and CSS
+   files as well as the CGI scripts that perform the server-side
+   functions. The description below lists all of the files that contain
+   editable information.
+
+   paths.pl
+          This contains the names of the directories that contain the
+          executable files, router database and temporary results.
+
+   router.pl
+          This file contains the filename prefix for the routing database
+          files (only needed if planetsplitter is run with the --prefix
+          option).
+
+   router.js
+          The parameters in this file control the boundary of the visible
+          map (defaults to UK), the minimum and maximum zoom levels
+          (defaults to between 4 and 15 inclusive) and the source of map
+          tiles (defaults to the main OpenStreetMap tile server).
+
+   visualiser.js
+          The same parameters as in router.js are in this file.
+
+
+Configuration of web server
+---------------------------
+
+   The file 'www/routino/.htaccess' contains all of the Apache configuration
+   options that are required to get the example web pages running. The
+   only problem is that because of the way that the "AllowOverride" option
+   works one of the configuration options has been commented out. This
+   must be enabled in the main Apache server configuration file.
+
+
+--------
+
+Copyright 2008-2010 Andrew M. Bishop.
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644 (file)
index 0000000..5bc7047
--- /dev/null
@@ -0,0 +1,48 @@
+# $Header: /home/amb/routino/doc/RCS/Makefile,v 1.2 2010/07/07 17:27:03 amb Exp $
+#
+# Documentation directory Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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)/*
diff --git a/doc/NEWS.txt b/doc/NEWS.txt
new file mode 100644 (file)
index 0000000..a003671
--- /dev/null
@@ -0,0 +1,177 @@
+Version 1.4.1 of Routino released : Sat Jul 10 2010
+---------------------------------------------------
+
+Bug fixes:
+  Don't crash if start and finish are the same point.
+  Don't crash if several translations but --language option not used.
+  Don't crash if middle part of route cannot be found.
+  Don't allocate so much memory for intermediate nodes; routes much faster.
+  Fix problem with finding closest segment to the specified point.
+
+Documentation:
+  Provide HTML versions of the documentation (copy to web directory at install).
+  Change URL for website to http://www.routino.org/.
+
+Configuration Files:
+  Added German translations.
+
+planetsplitter
+  Slight change to algorithm for finding super-nodes.
+
+Web pages:
+  Provide HTML versions of the documentation.
+  Change URL for website to http://www.routino.org/.
+  Provide updated HTML files, the same as on the website.
+  Change to OpenLayers v2.9.1 and build custom version if Python available.
+
+
+Version 1.4 of Routino released : Mon May 31 2010
+-------------------------------------------------
+
+Bug fixes:
+  Speed up start/via/stop point within segment search algorithm.
+  If no segment is found don't try routing but exit with error.
+  Improve the error messages by adding operating system error info to them.
+  Rewrite of tagging rules fixes bug with wheelchair access allow/deny.
+  Files greater than 2GB can be read/written on 32-bit systems.
+  Fix bug with profile preferences when optimising a route.
+  Stricter check on profile validity before starting routing.
+
+planetsplitter
+  Add --parse-only and --process-only options (for incremental parsing).
+  Allow filenames to be specified on command line (default is still stdin).
+  Improved the '--help' information to describe all options.
+  Remove --transport, --not-highway, --not-property options (use config file).
+  Use tag transformation rules in configuration file not hard-coded.
+
+router
+  Removed compiled-in profiles and use profiles loaded from XML file.
+  Improved the '--help' information to describe all options.
+  Change the name of the --profile-json and --profile-perl options.
+  Allow selection of the outputs to generate (or none).
+  Added HTML route instructions output.
+  GPX route file contains instructions at each waypoint.
+  Read in XML file of translated words/phrases for outputs.
+  Added options to specify file of translations and language to use.
+  Remove copyright.txt file and put information into translations file.
+
+filedumper
+  Improved the '--help' information to describe all options.
+  Added the option to dump an OSM file containing database contents.
+
+Web Pages
+  Combined generic map CSS into one file (not copied in two).
+  Much better support for IE6/7/8 with browser detection but not perfect.
+  Re-organised and tidied up the Javascript.
+  Added button next to waypoints to centre it on map.
+  Added button next to waypoints to set as home location (uses browsser cookie).
+  Create shorter URLs for custom map (ignore default values).
+  Reduced and clarified the amount of editing to customise the Javascript.
+  Made it easier to translate by moving text out of Javascript (not visualiser).
+  Prepared for translated versions of web page (Apache Multiviews).
+  Added option to select language of output.
+  Use HTML output from router to get translated instructions.
+
+
+Version 1.3 of Routino released : Thu Jan 21 2010
+-------------------------------------------------
+
+Bug fixes:
+  Ensure output even if the distance between two adjacent route points is small.
+  Correct the determination of waypoints for abbreviated output.
+  Check the command line values for filedumper --dump options.
+  Made the verbose output consistent between different places.
+
+OSM tagging
+  Recognise "designation" tag to determine designated paths.
+  Recognise "steps" tag to determine the highway type.
+  Recognise "wheelchair" tag to determine if wheelchairs are allowed on highway.
+  Recognise "moped" tag to determine if mopeds are allowed on a highway.
+  Recognise "surface" and "paved" tags to determine if a highway is paved.
+  Recognise "lanes" tag to determine if a highway has multiple lanes.
+  Recognise "bridge" tag to determine if a highway is a bridge.
+  Recognise "tunnel" tag to determine if a highway is a tunnel.
+
+New Features
+  Remove "bridleway" and "footway" highway types and use "path" highway instead.
+  Added "steps" as a new highway type separate from the "path" type.
+  Added "wheelchair" and "moped" to the list of possible transports.
+  Added "paved", "multilane", "bridge", "tunnel" to list of highway properties.
+
+Web Pages
+  Updated for new features listed above.
+  Added popup to display instructions for each step in route on mouse-over.
+  Added buttons next to waypoints for: add / remove / move up / move down.
+  Highlight user selectable parts of form in yellow on mouse-over.
+  A few small changes, improved CSS, improved Javascript.
+
+router
+  For each waypoint choose closest point on a segment and not just closest node.
+  Added the ability to set preferences based on highway properties.
+  Changed the text output formats to include bearing and turn information.
+
+
+Version 1.2 of Routino released : Wed Oct 21 2009
+-------------------------------------------------
+
+OSM tagging
+  Recognise tags "vehicle" and "motor_vehicle".
+  Handle duplicate ways in the input OSM file (e.g. concatenation of 2 files).
+
+Database
+  Identical ways are combined to reduce database size (~80% fewer ways stored).
+
+Routing
+  Fix weight, height, width, length restriction routing.
+  Allow up to 99 waypoints to be specified instead of 9.
+
+Visualiser
+  Don't display speed limits for tracks and paths unless a value is set.
+  Draw all super-segments that cross the selected boundary.
+
+Web Pages
+  A few small changes, improved CSS, improved Javascript.
+  Changed marker colour when waypoint not selected.
+
+planetsplitter
+  Optional slim mode uses minimal memory at the expense of temporary files.
+
+router
+  Less CPU time for routing (~30% less).
+
+filedumper
+  Allow dumping individual nodes, segments and ways (for debug).
+
+
+Version 1.1 of Routino released : Sat Jun 13 2009
+-------------------------------------------------
+
+Inputs
+  Improve parsing of OSM file (imperial units).
+  Ignore nodes that are missing from the input OSM file.
+
+Outputs
+  Create GPX route files as well as GPX track files.
+  Read in an optional copyright.txt file and include contents in output.
+  Make better choices about what to output in the abbreviated text file.
+
+Routing
+  Allow generating a route with intermediate waypoints.
+  Use preferences for highway types instead of yes/no choice.
+  Choice of closest node to start/finish points ensures transport allowed.
+
+Visualiser
+  Added data extraction function for viewing routing database data.
+
+Web Pages
+  Include full set of web pages for creating customised online router.
+
+Documentation
+  Included NEWS.txt file.
+  Included documentation for installation of web pages.
+
+
+Version 1.0 of Routino released : Wed Apr 08 2009
+-------------------------------------------------
+
+First version.
diff --git a/doc/OUTPUT.txt b/doc/OUTPUT.txt
new file mode 100644 (file)
index 0000000..4ebd742
--- /dev/null
@@ -0,0 +1,250 @@
+                              Routino : Output
+                              ================
+
+
+   There are three different formats of output from the router, HTML, GPX
+   (GPS eXchange) XML format and plain text with a total of five possible
+   output files:
+     * HTML route instructions for each interesting junction.
+     * GPX track file containing every node.
+     * GPX route file with waypoints at interesting junctions.
+     * Plain text description with the interesting junctions.
+     * Plain text file with every node.
+
+   The "interesting junctions" referred to above are junctions where the
+   route changes to a different type of highway, more than two highways of
+   the same type meet, or where the route meets but does not take a more
+   major highway. When the route follows a major road this definition
+   eliminates all junctions with minor roads.
+
+   The output files are written to the current directory and are named
+   depending on the selection of shortest or quickest route. For the
+   shortest route the file names are "shortest.html",
+   "shortest-track.gpx", "shortest-route.gpx", "shortest.txt" and
+   "shortest-all.txt", for the quickest route the names are
+   "quickest.html", "quickest-track.gpx", "quickest-route.gpx",
+   "quickest.txt" and "quickest-all.txt".
+
+   The HTML file and GPX files are written out according to the selected
+   language using the translations contained in the translations.xml
+   configuration file.
+
+
+HTML Route Instructions
+-----------------------
+
+   The HTML route instructions file contains one line for each of the
+   interesting junctions in the route and one line for the highway that
+   connects them.
+
+   An example HTML file output is below (some parts are missing, for
+   example the style definitions):
+
+<!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.
diff --git a/doc/README.txt b/doc/README.txt
new file mode 100644 (file)
index 0000000..75fe606
--- /dev/null
@@ -0,0 +1,147 @@
+                  Routino : OpenStreetMap Routing Software
+                  ========================================
+
+
+   Routino is an application for finding a route between two points using
+   the dataset of topographical information collected by
+   http://www.OpenStreetMap.org.
+
+   Starting from the raw OpenStreetMap data (in the form of the '.osm' XML
+   files available on the internet) a custom database is generated that
+   contains the information useful for routing. With this database and two
+   points specified by latitude and longitude an optimum route (either
+   shortest or quickest) is determined. The route is calculated for
+   OpenStreetMap highways (roads, paths etc) using one of the common forms
+   of transport defined in OpenStreetMap (foot, bicycle, horse, motorcar,
+   motorbike etc).
+
+   When processing the OpenStreetMap data the types of highways are
+   recorded and these set default limits on the types of traffic allowed.
+   More specific information about permissions for different types of
+   transport are also recorded as are maximum speed limits. Further
+   restrictions like oneway streets, weight, height, width and length
+   limits are also included where specified. Additionally a set of
+   properties of each highway are also recorded. The processing of the
+   input file is controlled by a configuration file which determines the
+   information that is used.
+
+   When calculating a route the type of transport to be used is taken into
+   account to ensure that the known restrictions are followed. Each of the
+   different highway types can further be allowed or disallowed depending
+   on preferences. For each type of highway a default speed limit is
+   defined (although the actual speed used will be the lowest of the
+   default and any specified in the original data). To make use of the
+   information about restrictions the weight, height, width and length of
+   the transport can also be specified. Further preferences about road
+   properties (e.g. paved or not) can also be selected.
+
+   The result of calculating the route can be presented in several
+   different ways. An HTML file can be produced that contains a
+   description of the route to take with instructions for each of the
+   important junctions. The contents of the file are created based on a
+   set of translations specified in a configuration file. The route is
+   also available in a GPX (GPS eXchange) XML format. format file
+   containing either every point and highway segment (a track file) or
+   just a waypoint and translated instructions for the important junctions
+   (a route file). Additionally there are two plain text files that
+   contain all data points or just the important ones (intended for
+   debugging and further processing).
+
+   One of the design aims of Routino was to make the software are flexible
+   as possible in selecting routing preferences but also have a sensible
+   set of default values. Another design aim was that finding the optimum
+   route should be very fast and most of the speed increases come from the
+   carefully chosen and optimised data format.
+
+
+Disclaimer
+----------
+
+   The route that is calculated by this software is only as good as the
+   input data.
+
+   Routino comes with ABSOLUTELY NO WARRANTY for the software itself or
+   the route that is calculated by it.
+
+
+Demonstration
+-------------
+
+   A live demonstration of the router for the UK is available on the
+   internet:
+
+   http://www.routino.org/uk/router.html
+
+   The source code download available also includes a set of files that can
+   be used to create your own interactive map.
+
+   The interactive map is made possible by use of the OpenLayers Javascript
+   library from http://www.openlayers.org/.
+
+
+Documentation
+-------------
+
+   The algorithm used is described in the file ALGORITHM.txt and some
+   notes about the limitations of the data is in DATA.txt.
+
+   The configuration files and in particular the default set of rules for
+   processing the OpenStreetMap data tags are described in detail in
+   CONFIGURATION.txt and TAGGING.txt.  The format of the output files
+   generated are described in OUTPUT.txt.
+
+   Detailed information about how to use the programs is available in the
+   file USAGE.txt and how to install it is in INSTALL.txt.
+
+
+Status
+------
+
+   Version 1.0 of Routino was released on 8th April 2009.
+   Version 1.1 of Routino was released on 13th June 2009.
+   Version 1.2 of Routino was released on 21st October 2009.
+   Version 1.3 of Routino was released on 21st January 2010.
+   Version 1.4 of Routino was released on 31st May 2010.
+
+
+License
+-------
+
+   This program is free software: you can redistribute it and/or modify it
+   under the terms of the GNU Affero General Public License as published
+   by the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   It is important to note that for this program I have decided to use the
+   Affero GPLv3 instead of just using the GPL. This license adds
+   additional requirements to anybody who provides a networked service
+   using this software.
+
+
+Copyright
+---------
+
+   Routino is copyright Andrew M. Bishop 2008-2010.
+
+   Contact amb@gedanken.demon.co.uk for any questions or queries.
+
+
+Homepage
+--------
+
+   The latest information about the program can be found on the homepage:
+
+   http://www.routino.org/
+
+
+Download
+--------
+
+   The program can be downloaded from:
+
+   http://www.routino.org/download/
+
+
+--------
+
+Copyright 2008-2010 Andrew M. Bishop.
diff --git a/doc/TAGGING.txt b/doc/TAGGING.txt
new file mode 100644 (file)
index 0000000..6c23d8c
--- /dev/null
@@ -0,0 +1,352 @@
+                           Routino : Tagging Rules
+                           =======================
+
+
+   The different tags and attributes in the OSM format XML that are used
+   by Routino are described below.
+
+   An important change for version 1.4 of Routino is that the tags in the
+   input file are first processed according to a set of rules defined in a
+   configuration file. This means that the information presented here is
+   in two parts; firstly the tags that are recognised by Routino after
+   pre-processing and secondly the transformations in the default
+   configuration file.
+
+
+Tags Recognised After Processing
+--------------------------------
+
+   This section describes the tags that are recognised by Routino after
+   the tag transformations have been applied. This is therefore a much
+   reduced set of tags compared to the original OSM data and also includes
+   tags which are specific to Routino.
+
+   In all cases of tag processing values of true, yes, 1 are recognised as
+   being affirmative and any other value is ignored.
+
+
+Node Tags And Attributes
+------------------------
+
+   None of the node tags are used but the node attributes id, latitude and
+   longitude of the node. The id atribute is required to associate the
+   node with the ways and the position attributes are required to locate
+   the node.
+
+
+Way Tags And Attributes
+-----------------------
+
+   The tags from the ways in the data are the ones that provide most of
+   the information for routing. The id attribute is used only so that the
+   many segments associated with a way can be share a set of tags taken
+   from the way.
+
+The highway Tag
+- - - - - - - -
+
+   The most important tag that is used from a way is the highway tag. This
+   defines the type of highway that the way represents. Any way that does
+   not have a highway tag is discarded.
+
+   There are more highway types defined than are used by the router. The
+   subset that the router uses are:
+     * motorway
+     * trunk
+     * primary
+     * secondary
+     * tertiary
+     * unclassified
+     * residential
+     * service
+     * track
+     * cycleway
+     * path (1)
+     * steps (2)
+
+   Note 1: This changed in version 1.3 of Routino - the bridleway and
+   footway types were included within the path highway type.
+   Note 2: This changed in version 1.3 of Routino - the steps type was
+   separated from the footway type.
+
+Transport Specific Tags
+- - - - - - - - - - - -
+
+   One tag is recognised for each of the different modes of transport:
+   foot, horse, bicycle, wheelchair, moped, motorbike, motorcar, goods,
+   hgv and psv. These indicate whether the specific type of transport is
+   allowed on the highway or not.
+
+The name Tag
+- - - - - -
+
+   The name tag is used to provide the label for the highway when printing
+   the results.
+
+The ref Tag
+- - - - - -
+
+   The ref tag is used to provide the label for the highway when printing
+   the results.
+
+The junction Tag
+- - - - - - - -
+
+   The junction tag is used to check if a highway is (part of) a
+   roundabout. This tag is used for information to label the highway if no
+   other name is provided.
+
+The multilane Tag
+- - - - - - - - -
+
+   The multilane tag is used to identify whether a highway has multiple
+   lanes for traffic and this sets one of the highway properties. There is
+   not normally a multilane tag but one needs to be added by the tag
+   processing transformations. Values of true, yes, 1 are recognised.
+
+The paved Tag
+- - - - - - -
+
+   The paved tag is used to identify whether a highway is paved or not,
+   this is one of the available highway properties. A paved tag may exist
+   in the original data but normally the surface tag needs to be
+   transformed into the paved tag.
+
+The bridge Tag
+- - - - - - -
+
+   The bridge tag is used to identify whether a highway is a bridge and
+   therefore set one of the available properties.
+
+The tunnel Tag
+- - - - - - -
+
+   The tunnel tag is used to identify whether a highway is a tunnel and
+   therefore set one of the available properties.
+
+The oneway Tag
+- - - - - - -
+
+   The oneway tag is used to specify that traffic is only allowed to
+   travel in one direction.
+
+The maxspeed Tag
+- - - - - - - -
+
+   The maxspeed tag is used to specify the maximum speed limit on the
+   highway; this is always measured in km/hr in OpenStreetMap data. If the
+   tag value contains "mph" then it is assumed to be a value in those
+   units and converted to km/hr.
+
+The maxweight Tag
+- - - - - - - - -
+
+   The maxweight tag is used to specify the maximum weight of any traffic
+   on the way. In other words this must be set to the heaviest weight
+   allowed on the way (for example a bridge) in tonnes. If the tag value
+   contains "kg" then it is assumed that the value is in these units and
+   converted to tonnes.
+
+The maxheight Tag
+- - - - - - - - -
+
+   The maxheight tag is used to specify the maximum height of any traffic
+   on the way. In other words this must be set to the lowest height of
+   anything above the way (like a bridge) in metres. If the tag value
+   contains a measurement in feet or feet and inches then attempts are
+   made to convert this to metres.
+
+The maxwidth Tag
+- - - - - - - -
+
+   The maxwidth tag is used to specify the maximum width of any traffic on
+   the way. This must be set to the minimum width of the contraints at the
+   wayside in metres. If the tag value contains a measurement in feet or
+   feet and inches then attempts are made to convert this to metres.
+
+The maxlength Tag
+- - - - - - - - -
+
+   The maxlength tag is used to specify the maximum length of any traffic
+   on the way (usually from a traffic sign) in metres. If the tag value
+   contains a measurement in feet or feet and inches then attempts are
+   made to convert this to metres.
+
+
+Relation Tags And Attributes
+----------------------------
+
+   Currently no relation tags or attributes are used.
+
+
+Tag Transformations
+-------------------
+
+   This section describes the set of tag transformations that are
+   contained in the default configuration file. The configuration file
+   tagging rules are applied in sequence and this section of the document
+   is arranged in the same order.
+
+
+Node Tag Transformations
+------------------------
+
+   No transformations are applicable since no node tags are recognised.
+
+
+Way Tag Transformations
+-----------------------
+
+Highway Defaults
+- - - - - - - -
+
+   The first part of the tag transformations is to decide on defaults for
+   each type of highway. This uses the highway tag in the OSM file and
+   maps it into one of the highway tags that are recognised by Routino,
+   defining the default allowed transport types and adding a number of
+   properties.
+
+   The first part of the transformation is to convert the highway tag into
+   one that is recognised by Routino.
+
+   Original tag  Transformed tag
+   ------------  ---------------
+   bridleway     path
+   byway         track
+   footway       path
+   living_street residential
+   minor         unclassified
+   pedestrian    path
+   road          unclassified
+   services      service
+   unsurfaced    track
+   unpaved       track
+   walkway       path
+
+   The type of highway also determines the defaults for the types of
+   transport allowed on the highway. The default assumptions are as shown
+   in the table below.
+
+   Highway      foot horse  wheelchair bicycle moped motorbike motorcar goods hgv psv
+   -------      ---- -----  ---------- ------- ----- --------- -------- ----- --- ---
+   motorway     no   no     no         no      no    yes       yes      yes   yes yes
+   trunk        no   no     no         yes     yes   yes       yes      yes   yes yes
+   primary      yes  yes    yes        yes     yes   yes       yes      yes   yes yes
+   secondary    yes  yes    yes        yes     yes   yes       yes      yes   yes yes
+   tertiary     yes  yes    yes        yes     yes   yes       yes      yes   yes yes
+   unclassified yes  yes    yes        yes     yes   yes       yes      yes   yes yes
+   residential  yes  yes    yes        yes     yes   yes       yes      yes   yes yes
+   service      yes  yes    yes        yes     yes   yes       yes      yes   yes yes
+   track        yes  yes    yes        yes     no    no        no       no    no  no
+   cycleway     yes  no     yes        yes     no    no        no       no    no  no
+   path         yes  yes(1) yes        yes(1)  no    no        no       no    no  no
+   steps        yes  no     yes        no      no    no        no       no    no  no
+
+   Note 1: A path allows bicycle or horse access by default only if
+   actually labelled as a highway of type "bridleway" or certain values of
+   the designation tag (described below).
+
+   Finally for the highway tag a number of properties are added depending
+   on the highway type.
+
+   Highway      Properties
+   -------      ----------
+   motorway     paved, oneway, multilane
+   trunk        paved
+   primary      paved
+   secondary    paved
+   tertiary     paved
+   unclassified paved
+   residential  paved
+   service      paved
+   track        paved (1)
+   cycleway     paved
+   path         paved (2)
+   steps
+
+   Note 1: A track is paved only if it is tagged as tracktype=grade1.
+   Note 2: A path is paved only if it was originally tagged as
+   highway=walkway or highway=pedestrian.
+
+Generic Access Permissions
+- - - - - - - - - - - - -
+
+   The access tag is used to specify the default access restrictions on
+   the way. If the tag value is "no" or "private" then all transport types
+   are denied access (later tag transformation rules may add specific
+   transport types back again).
+
+Other Access Permissions
+- - - - - - - - - - - -
+
+   A tag named vehicle means any of the bicycle, moped, motorbike,
+   motorcar, goods, hgv and psv transport types. A tag named motor_vehicle
+   is transformed to mean any vehicle except a bicycle.
+
+   The designation tag is used as an alternative method of identifying the
+   legal right of way on a path (in the UK at least). The tag
+   transformations convert these tags into a set of allowed transport
+   types as shown below.
+
+   Designation tag      Equivalent access permissions
+   ---------------      -----------------------------
+   bridleway or         foot=yes, wheelchair=yes, horse=yes,
+     public_bridleway     bicycle=yes
+   restricted_byway     foot=yes, wheelchair=yes, horse=yes,
+                          bicycle=yes
+   byway                foot=yes, wheelchair=yes, horse=yes,
+                          bicycle=yes, moped=yes, motorbike=yes,
+                          motorcar=yes
+   footpath or          foot=yes, wheelchair=yes
+     public_footpath
+
+Specific Access Permissions
+- - - - - - - - - - - - - -
+
+   The final part of the access permissions is to use the specific
+   transport type tags.
+
+   One tag is recognised for each of the different modes of transport:
+   foot, horse, bicycle, wheelchair, moped, motorbike, motorcar, goods,
+   hgv and psv. These indicate whether the specific type of transport is
+   allowed on the highway or not.
+
+Highway Properties
+- - - - - - - - -
+
+   If there is a surface tag then the highway is assumed to be unpaved
+   unless the tag value matches one of the following: paved, asphalt or
+   concrete.
+
+   Support for the obsolete paved tag is also provided and the highway is
+   paved if this is set to a true value.
+
+   The lanes tag is used to identify whether a highway has multiple lanes
+   for traffic or not (the number of lanes is not important in this case,
+   only whether it is more than one) this sets one of the highway
+   properties.
+
+   The bridge and tunnel tags are copied directly from the input to the
+   output.
+
+Highway Restrictions
+- - - - - - - - - -
+
+   The oneway, maxspeed, maxweight, maxheight, maxwidth and maxlength are
+   copied directly from the input to the output without modification.
+
+Highway Names and References
+- - - - - - - - - - - - - -
+
+   The name and ref tags are copied directly from the input to the output.
+
+
+Relation Tag Transformations
+----------------------------
+
+   No transformations are applicable since no relation tags are recognised.
+
+
+--------
+
+Copyright 2008-2010 Andrew M. Bishop.
diff --git a/doc/USAGE.txt b/doc/USAGE.txt
new file mode 100644 (file)
index 0000000..48721bd
--- /dev/null
@@ -0,0 +1,425 @@
+                               Routino : Usage
+                               ===============
+
+
+   There are four programs that make up this software. The first one takes
+   the planet.osm datafile from OpenStreetMap (or other source of data
+   using the same formats) and converts it into a local database. The
+   second program uses the database to determine an optimum route between
+   two points. The third program allows visualisation of the data and
+   statistics to be extracted. The fourth program is a test program for
+   the tag transformations.
+
+
+planetsplitter
+--------------
+
+   This program reads in the OSM format XML file and splits it up to
+   create the database that is used for routing.
+
+  Usage: planetsplitter [--help]
+                        [--dir=<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.
diff --git a/doc/html/algorithm.html b/doc/html/algorithm.html
new file mode 100644 (file)
index 0000000..cec599f
--- /dev/null
@@ -0,0 +1,266 @@
+<!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 &amp; 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>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/doc/html/configuration.html b/doc/html/configuration.html
new file mode 100644 (file)
index 0000000..98fa009
--- /dev/null
@@ -0,0 +1,256 @@
+<!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">
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;routino-tagging&gt;
+
+  &lt;way&gt;
+
+    &lt;if k="highway" v="motorway_link"&gt;
+      &lt;set v="motorway"/&gt;
+    &lt;/if&gt;
+
+    &lt;if k="highway" v="motorway"&gt;
+      &lt;output k="highway"/&gt;
+
+      &lt;output k="motorbike"  v="yes"/&gt;
+      &lt;output k="motorcar"   v="yes"/&gt;
+      &lt;output k="goods"      v="yes"/&gt;
+      &lt;output k="hgv"        v="yes"/&gt;
+      &lt;output k="psv"        v="yes"/&gt;
+
+      &lt;output k="paved"      v="yes"/&gt;
+      &lt;output k="multilane"  v="yes"/&gt;
+      &lt;output k="oneway"     v="yes"/&gt;
+    &lt;/if&gt;
+...
+  &lt;way&gt;
+
+&lt;/routino-tagging&gt;
+</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">
+&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
+&lt;routino-profiles&gt;
+
+  &lt;profile name="foot" transport="foot"&gt;
+    &lt;speeds&gt;
+...
+      &lt;speed highway="cycleway"      kph="4" /&gt;
+      &lt;speed highway="path"          kph="4" /&gt;
+      &lt;speed highway="steps"         kph="4" /&gt;
+    &lt;/speeds&gt;
+    &lt;preferences&gt;
+...
+      &lt;preference highway="cycleway"      percent="95" /&gt;
+      &lt;preference highway="path"          percent="100" /&gt;
+      &lt;preference highway="steps"         percent="80" /&gt;
+    &lt;/preferences&gt;
+    &lt;properties&gt;
+      &lt;property type="paved"      percent="50" /&gt;
+      &lt;property type="multilane"  percent="25" /&gt;
+      &lt;property type="bridge"     percent="50" /&gt;
+      &lt;property type="tunnel"     percent="50" /&gt;
+    &lt;/properties&gt;
+    &lt;restrictions&gt;
+      &lt;oneway obey="0" /&gt; 
+      &lt;weight limit="0.0" /&gt;
+      &lt;height limit="0.0" /&gt;
+      &lt;width  limit="0.0" /&gt;
+      &lt;length limit="0.0" /&gt;
+    &lt;/restrictions&gt;
+  &lt;/profile&gt;
+  &lt;profile name="horse" transport="horse"&gt;
+...
+  &lt;/profile&gt;
+...
+&lt;/routino-profiles&gt;
+</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">
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;routino-translations&gt;
+
+  &lt;language lang="en"&gt;
+...
+    &lt;turn direction="-4" string="Very sharp left" /&gt;
+    &lt;turn direction="-3" string="Sharp left" /&gt;
+    &lt;turn direction="-2" string="Left" /&gt;
+...
+    &lt;heading direction="-4" string="South" /&gt;
+    &lt;heading direction="-3" string="South-West" /&gt;
+    &lt;heading direction="-2" string="West" /&gt;
+...
+    &lt;route type="shortest" string="Shortest" /&gt;
+    &lt;route type="quickest" string="Quickest" /&gt;
+    &lt;output-html&gt;
+...
+    &lt;/output-html&gt;
+    &lt;output-gpx&gt;
+...
+    &lt;/output-gpx&gt;
+  &lt;/language&gt;
+&lt;/routino-translations&gt;
+</pre>
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer" align="center">
+<hr>
+
+<address>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/doc/html/data.html b/doc/html/data.html
new file mode 100644 (file)
index 0000000..52f74aa
--- /dev/null
@@ -0,0 +1,165 @@
+<!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>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/doc/html/example0.png b/doc/html/example0.png
new file mode 100644 (file)
index 0000000..4401486
Binary files /dev/null and b/doc/html/example0.png differ
diff --git a/doc/html/example1.png b/doc/html/example1.png
new file mode 100644 (file)
index 0000000..be0048c
Binary files /dev/null and b/doc/html/example1.png differ
diff --git a/doc/html/example2.png b/doc/html/example2.png
new file mode 100644 (file)
index 0000000..c4746d8
Binary files /dev/null and b/doc/html/example2.png differ
diff --git a/doc/html/index.html b/doc/html/index.html
new file mode 100644 (file)
index 0000000..2450127
--- /dev/null
@@ -0,0 +1,124 @@
+<!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>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/doc/html/installation.html b/doc/html/installation.html
new file mode 100644 (file)
index 0000000..faa752f
--- /dev/null
@@ -0,0 +1,243 @@
+<!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>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/doc/html/output.html b/doc/html/output.html
new file mode 100644 (file)
index 0000000..566d4ac
--- /dev/null
@@ -0,0 +1,364 @@
+<!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">
+&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
+&lt;HTML&gt;
+&lt;!-- Creator : Routino - http://www.routino.org/ --&gt;
+&lt;!-- Source : Based on OpenStreetMap data from http://www.openstreetmap.org/ --&gt;
+&lt;!-- License : http://creativecommons.org/licenses/by-sa/2.0/ --&gt;
+&lt;HEAD&gt;
+&lt;TITLE&gt;Shortest Route&lt;/TITLE&gt;
+...
+&lt;/HEAD&gt;
+&lt;BODY&gt;
+&lt;H1&gt;Shortest Route&lt;/H1&gt;
+&lt;table&gt;
+&lt;tr class='c'&gt;&lt;td class='l'&gt;&lt;td class='r'&gt;51.524677 -0.127896
+&lt;tr class='n'&gt;&lt;td class='l'&gt;Start:&lt;td class='r'&gt;At &lt;span class='w'&gt;Waypoint&lt;/span&gt;, head &lt;span class='b'&gt;South-East&lt;/span&gt;
+
+&lt;tr class='s'&gt;&lt;td class='l'&gt;Follow:&lt;td class='r'&gt;&lt;span class='h'&gt;Russell Square&lt;/span&gt; for &lt;span class='d'&gt;0.391 km, 0.5 min&lt;/span&gt; [&lt;span class='j'&gt;0.4 km, 0 minutes&lt;/span&gt;]
+...
+&lt;tr class='t'&gt;&lt;td class='l'&gt;Total:&lt;td class='r'&gt;&lt;span class='j'&gt;6.3 km, 5 minutes&lt;/span&gt;
+&lt;tr&gt;&lt;td class='l'&gt;Stop:&lt;td class='r'&gt;&lt;span class='w'&gt;Waypoint&lt;/span&gt;
+&lt;/table&gt;
+&lt;/BODY&gt;
+&lt;/HTML&gt;
+</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">
+&lt;?xml version="1.0" encoding="UTF-8"?&gt;
+&lt;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"&gt;
+&lt;metadata&gt;
+&lt;desc&gt;Creator : Routino - http://www.routino.org/&lt;/desc&gt;
+&lt;copyright author="Based on OpenStreetMap data from http://www.openstreetmap.org/"&gt;
+&lt;license&gt;http://creativecommons.org/licenses/by-sa/2.0/&lt;/license&gt;
+&lt;/copyright&gt;
+&lt;/metadata&gt;
+&lt;trk&gt;
+&lt;name&gt;Shortest route&lt;/name&gt;
+&lt;desc&gt;Shortest route between 'start' and 'finish' waypoints&lt;/desc&gt;
+&lt;trkpt lat="51.524677" lon="-0.127896"/&gt;
+&lt;trkpt lat="51.523830" lon="-0.126993"/&gt;
+...
+&lt;trkpt lat="51.478353" lon="-0.103561"/&gt;
+&lt;trkpt lat="51.478244" lon="-0.103652"/&gt;
+&lt;/trkseg&gt;
+&lt;/trk&gt;
+&lt;/gpx&gt;
+</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">
+&lt;?xml version="1.0" encoding="UTF-8"?&gt;
+&lt;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"&gt;
+&lt;metadata&gt;
+&lt;desc&gt;Creator : Routino - http://www.routino.org/&lt;/desc&gt;
+&lt;copyright author="Based on OpenStreetMap data from http://www.openstreetmap.org/"&gt;
+&lt;license&gt;http://creativecommons.org/licenses/by-sa/2.0/&lt;/license&gt;
+&lt;/copyright&gt;
+&lt;/metadata&gt;
+&lt;rte&gt;
+&lt;name&gt;Shortest route&lt;/name&gt;
+&lt;desc&gt;Shortest route between 'start' and 'finish' waypoints&lt;/desc&gt;
+&lt;rtept lat="51.524677" lon="-0.127896"&gt;&lt;name&gt;START&lt;/name&gt;
+&lt;desc&gt;South-East on 'Russell Square' for 0.391 km, 0.5 min&lt;/desc&gt;&lt;/rtept&gt;
+&lt;rtept lat="51.521815" lon="-0.124577"&gt;&lt;name&gt;TRIP001&lt;/name&gt;
+&lt;desc&gt;South-East on 'Russell Square' for 0.055 km, 0.1 min&lt;/desc&gt;&lt;/rtept&gt;
+...
+&lt;rtept lat="51.478244" lon="-0.103652"&gt;&lt;name&gt;FINISH&lt;/name&gt;
+&lt;desc&gt;Total Journey 6.3 km, 5 minutes&lt;/desc&gt;&lt;/rtept&gt;
+&lt;/rte&gt;
+&lt;/gpx&gt;
+</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>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/doc/html/style.css b/doc/html/style.css
new file mode 100644 (file)
index 0000000..535e062
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+// Routino web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2010 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <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;
+}
diff --git a/doc/html/tagging.html b/doc/html/tagging.html
new file mode 100644 (file)
index 0000000..5af6812
--- /dev/null
@@ -0,0 +1,658 @@
+<!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>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/doc/html/usage.html b/doc/html/usage.html
new file mode 100644 (file)
index 0000000..dc75888
--- /dev/null
@@ -0,0 +1,443 @@
+<!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=&lt;dirname&gt;] [--prefix=&lt;name&gt;]
+                      [--slim] [--sort-ram-size=&lt;size&gt;]
+                      [--tmpdir=&lt;dirname&gt;]
+                      [--parse-only | --process-only]
+                      [--max-iterations=&lt;number&gt;]
+                      [--tagging=&lt;filename&gt;]
+                      [&lt;filename.osm&gt; ...]
+</pre>
+
+<dl>
+  <dt>--help
+  <dd>Prints out the help information.
+  <dt>--dir=&lt;dirname&gt;
+  <dd>Sets the directory name in which to save the results.
+    Defaults to the current directory.
+  <dt>--prefix=&lt;name&gt;
+  <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=&lt;size&gt;
+  <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=&lt;dirname&gt;
+  <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=&lt;number&gt;
+  <dd>The maximum number of iterations to use when generating super-nodes and
+    super-segments.  Defaults to 10 which is normally enough.
+  <dt>--tagging=&lt;filename&gt;
+  <dd>The name of the XML file containing the tagging rules (defaults to
+    'tagging.xml' with '--dirname' and '--prefix' options).
+  <dt>&lt;filename.osm&gt; ...
+  <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=&lt;dirname&gt;] [--prefix=&lt;name&gt;]
+              [--profiles=&lt;filename&gt;] [--translations=&lt;filename&gt;]
+              [--exact-nodes-only]
+              [--quiet]
+              [--output-html]
+              [--output-gpx-track] [--output-gpx-route]
+              [--output-text] [--output-text-all]
+              [--output-none]
+              [--profile=&lt;name&gt;]
+              [--transport=&lt;transport&gt;]
+              [--shortest | --quickest]
+              --lon1=&lt;longitude&gt; --lat1=&lt;latitude&gt;
+              --lon2=&lt;longitude&gt; --lon2=&lt;latitude&gt;
+              [ ... --lon99=&lt;longitude&gt; --lon99=&lt;latitude&gt;]
+              [--highway-&lt;highway&gt;=&lt;preference&gt; ...]
+              [--speed-&lt;highway&gt;=&lt;speed&gt; ...]
+              [--property-&lt;property&gt;=&lt;preference&gt; ...]
+              [--oneway=(0|1)]
+              [--weight=&lt;weight&gt;]
+              [--height=&lt;height&gt;] [--width=&lt;width&gt;] [--length=&lt;length&gt;]
+</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=&lt;dirname&gt;
+  <dd>Sets the directory name in which to read the local database.
+    Defaults to the current directory.
+  <dt>--prefix=&lt;name&gt;
+  <dd>Sets the filename prefix for the files in the local database.
+    Defaults to no prefix.
+  <dt>--profiles=&lt;filename&gt;
+  <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=&lt;filename&gt;
+  <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=&lt;lang&gt;
+  <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=&lt;name&gt;
+  <dd>Specifies the name of the profile to use.
+  <dt>--transport=&lt;transport&gt;
+  <dd>Select the type of transport to use, &lt;transport&gt; 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=&lt;longitude&gt;, --lat1=&lt;latitude&gt;
+  <dt>--lon2=&lt;longitude&gt;, --lat2=&lt;latitude&gt;
+  <dt>... --lon99=&lt;longitude&gt;, --lat99=&lt;latitude&gt;
+  <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-&lt;highway&gt;=&lt;preference&gt;
+  <dd>Selects the percentage preference for using each particular type of
+      highway.  The value of &lt;highway&gt; 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-&lt;highway&gt;=&lt;speed&gt;
+  <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-&lt;property&gt;=&lt;preference&gt;
+  <dd>Selects the percentage preference for using each particular highway
+      property
+    The value of &lt;property&gt; 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=&lt;weight&gt;
+  <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=&lt;height&gt;
+  <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=&lt;width&gt;
+  <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=&lt;length&gt;
+  <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 &lt;preference&gt; 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=&lt;dirname&gt;] [--prefix=&lt;name&gt;]
+                  [--statistics]
+                  [--visualiser --latmin=&lt;latmin&gt; --latmax=&lt;latmax&gt;
+                                --lonmin=&lt;lonmin&gt; --lonmax=&lt;lonmax&gt;
+                                --data=&lt;data-type&gt;]
+                  [--dump [--node=&lt;node&gt; ...]
+                          [--segment=&lt;segment&gt; ...]
+                          [--way=&lt;way&gt; ...]]
+                  [--dump-osm [--no-super]
+                              [--latmin=&lt;latmin&gt; --latmax=&lt;latmax&gt;
+                               --lonmin=&lt;lonmin&gt; --lonmax=&lt;lonmax&gt;]]
+</pre>
+
+<dl>
+  <dt>--help
+  <dd>Prints out the help information.
+  <dt>--dir=&lt;dirname&gt;
+  <dd>Sets the directory name in which to read the local database.
+    Defaults to the current directory.
+  <dt>--prefix=&lt;name&gt;
+  <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=&lt;latmin&gt; --latmax=&lt;latmax&gt;
+      <dd>The range of latitudes to print the data for.
+      <dt>--lonmin=&lt;lonmin&gt; --lonmax=&lt;lonmax&gt;
+      <dd>The range of longitudes to print the data for.
+      <dt>--data=&lt;data-type&gt;
+      <dd>The type of data to output, &lt;data-type&gt; 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=&lt;node&gt;
+      <dd>Prints the information about the selected node number (internal
+        number, not the node id number in the original source file).
+      <dt>--segment=&lt;segment&gt;
+      <dd>Prints the information about the selected segment number.
+      <dt>--way=&lt;way&gt;
+      <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=&lt;latmin&gt; --latmax=&lt;latmax&gt;
+      <dd>The range of latitudes to dump the data for.
+      <dt>--lonmin=&lt;lonmin&gt; --lonmax=&lt;lonmax&gt;
+      <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=&lt;filename&gt;]
+                   [&lt;filename.osm&gt;]
+</pre>
+
+<dl>
+  <dt>--help
+  <dd>Prints out the help information.
+  <dt>--tagging=&lt;filename&gt;
+  <dd>The name of the XML file containing the tagging rules (defaults to
+    'tagging.xml' in the current directory).
+  <dt>&lt;filename.osm&gt; ...
+  <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>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..49e583e
--- /dev/null
@@ -0,0 +1,154 @@
+# $Header: /home/amb/routino/src/RCS/Makefile,v 1.36 2010/07/09 17:43:00 amb Exp $
+#
+# Source code Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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 :
diff --git a/src/filedumper.c b/src/filedumper.c
new file mode 100644 (file)
index 0000000..463ab19
--- /dev/null
@@ -0,0 +1,674 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/filedumper.c,v 1.43 2010/05/30 12:52:16 amb Exp $
+
+ Memory file dumper.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/files.c b/src/files.c
new file mode 100644 (file)
index 0000000..ce595ab
--- /dev/null
@@ -0,0 +1,372 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/files.c,v 1.18 2010/03/29 18:20:06 amb Exp $
+
+ Functions to handle files.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/functions.h b/src/functions.h
new file mode 100644 (file)
index 0000000..1ff10de
--- /dev/null
@@ -0,0 +1,106 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/functions.h,v 1.54 2010/04/24 16:47:56 amb Exp $
+
+ Header file for function prototypes
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/functionsx.h b/src/functionsx.h
new file mode 100644 (file)
index 0000000..bb92183
--- /dev/null
@@ -0,0 +1,39 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/functionsx.h,v 1.5 2010/05/22 18:40:47 amb Exp $
+
+ Header file for function prototypes for extended data types.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/nodes.c b/src/nodes.c
new file mode 100644 (file)
index 0000000..7430d62
--- /dev/null
@@ -0,0 +1,498 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/nodes.c,v 1.39 2010/07/08 17:54:54 amb Exp $
+
+ Node data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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));
+}
diff --git a/src/nodes.h b/src/nodes.h
new file mode 100644 (file)
index 0000000..8bfc2b6
--- /dev/null
@@ -0,0 +1,94 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/nodes.h,v 1.30 2009/11/14 19:39:19 amb Exp $
+
+ A header file for the nodes.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008,2009 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/nodesx.c b/src/nodesx.c
new file mode 100644 (file)
index 0000000..cc1e0a2
--- /dev/null
@@ -0,0 +1,894 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/nodesx.c,v 1.56 2010/04/28 17:27:02 amb Exp $
+
+ Extented Node data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/nodesx.h b/src/nodesx.h
new file mode 100644 (file)
index 0000000..2dc40a4
--- /dev/null
@@ -0,0 +1,100 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/nodesx.h,v 1.23 2010/03/19 19:47:09 amb Exp $
+
+ A header file for the extended nodes.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/optimiser.c b/src/optimiser.c
new file mode 100644 (file)
index 0000000..cdb5986
--- /dev/null
@@ -0,0 +1,922 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/optimiser.c,v 1.87 2010/07/08 17:33:09 amb Exp $
+
+ Routing optimiser.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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;
+}
diff --git a/src/osmparser.c b/src/osmparser.c
new file mode 100644 (file)
index 0000000..3af039d
--- /dev/null
@@ -0,0 +1,748 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/osmparser.c,v 1.69 2010/05/29 13:54:23 amb Exp $
+
+ OSM XML file parser (either JOSM or planet)
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+            }
+         }
+      }
+   }
+}
diff --git a/src/output.c b/src/output.c
new file mode 100644 (file)
index 0000000..e40f750
--- /dev/null
@@ -0,0 +1,816 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/output.c,v 1.33 2010/07/07 17:31:06 amb Exp $
+
+ Routing output generator.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/planetsplitter.c b/src/planetsplitter.c
new file mode 100644 (file)
index 0000000..5380455
--- /dev/null
@@ -0,0 +1,410 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/planetsplitter.c,v 1.73 2010/05/22 18:40:47 amb Exp $
+
+ OSM planet file splitter.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/profiles.c b/src/profiles.c
new file mode 100644 (file)
index 0000000..e27a067
--- /dev/null
@@ -0,0 +1,1018 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/profiles.c,v 1.42 2010/05/29 10:37:12 amb Exp $
+
+ Load the profiles from a file and the functions for handling them.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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");
+}
diff --git a/src/profiles.h b/src/profiles.h
new file mode 100644 (file)
index 0000000..25a933a
--- /dev/null
@@ -0,0 +1,79 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/profiles.h,v 1.16 2010/05/29 10:37:12 amb Exp $
+
+ A header file for the profiles.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/queue.c b/src/queue.c
new file mode 100644 (file)
index 0000000..68c4ccb
--- /dev/null
@@ -0,0 +1,201 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/queue.c,v 1.7 2009/11/13 19:24:11 amb Exp $
+
+ Queue data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008,2009 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/results.c b/src/results.c
new file mode 100644 (file)
index 0000000..b5dec42
--- /dev/null
@@ -0,0 +1,242 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/results.c,v 1.21 2010/07/07 19:04:18 amb Exp $
+
+ Result data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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]);
+}
diff --git a/src/results.h b/src/results.h
new file mode 100644 (file)
index 0000000..a7191f0
--- /dev/null
@@ -0,0 +1,112 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/results.h,v 1.17 2009/11/13 19:24:11 amb Exp $
+
+ A header file for the results.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008,2009 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/router.c b/src/router.c
new file mode 100644 (file)
index 0000000..46ca0b4
--- /dev/null
@@ -0,0 +1,814 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/router.c,v 1.83 2010/06/28 17:56:26 amb Exp $
+
+ OSM router.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/segments.c b/src/segments.c
new file mode 100644 (file)
index 0000000..0557d50
--- /dev/null
@@ -0,0 +1,170 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/segments.c,v 1.45 2010/04/28 17:27:02 amb Exp $
+
+ Segment data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+   }
+}
diff --git a/src/segments.h b/src/segments.h
new file mode 100644 (file)
index 0000000..8b6554f
--- /dev/null
@@ -0,0 +1,101 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/segments.h,v 1.34 2009/11/14 19:39:20 amb Exp $
+
+ A header file for the segments.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008,2009 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/segmentsx.c b/src/segmentsx.c
new file mode 100644 (file)
index 0000000..5a4f03b
--- /dev/null
@@ -0,0 +1,1053 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/segmentsx.c,v 1.51 2010/04/28 17:27:02 amb Exp $
+
+ Extended Segment data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/segmentsx.h b/src/segmentsx.h
new file mode 100644 (file)
index 0000000..ac19a77
--- /dev/null
@@ -0,0 +1,100 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/segmentsx.h,v 1.20 2010/03/19 19:47:09 amb Exp $
+
+ A header file for the extended segments.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/sorting.c b/src/sorting.c
new file mode 100644 (file)
index 0000000..54bfdf0
--- /dev/null
@@ -0,0 +1,650 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/sorting.c,v 1.8 2010/04/09 15:15:02 amb Exp $
+
+ Merge sort functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2009 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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;
+      }
+   }
+}
diff --git a/src/superx.c b/src/superx.c
new file mode 100644 (file)
index 0000000..45b8227
--- /dev/null
@@ -0,0 +1,480 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/superx.c,v 1.38 2010/07/05 19:05:51 amb Exp $
+
+ Super-Segment data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/superx.h b/src/superx.h
new file mode 100644 (file)
index 0000000..cb330df
--- /dev/null
@@ -0,0 +1,38 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/superx.h,v 1.7 2009/09/06 15:51:09 amb Exp $
+
+ Header for super-node and super-segment functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008,2009 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/tagging.c b/src/tagging.c
new file mode 100644 (file)
index 0000000..814580f
--- /dev/null
@@ -0,0 +1,574 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/tagging.c,v 1.2 2010/05/23 10:18:59 amb Exp $
+
+ Load the tagging rules from a file and the functions for handling them.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+   }
+}
diff --git a/src/tagging.h b/src/tagging.h
new file mode 100644 (file)
index 0000000..4dfdbb8
--- /dev/null
@@ -0,0 +1,95 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/tagging.h,v 1.2 2010/05/23 10:18:59 amb Exp $
+
+ The data types for the tagging rules.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/tagmodifier.c b/src/tagmodifier.c
new file mode 100644 (file)
index 0000000..06bcc87
--- /dev/null
@@ -0,0 +1,626 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/tagmodifier.c,v 1.5 2010/05/30 18:18:54 amb Exp $
+
+ Test application for OSM XML file parser / tagging rule testing.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/translations.c b/src/translations.c
new file mode 100644 (file)
index 0000000..c00fdff
--- /dev/null
@@ -0,0 +1,1050 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/translations.c,v 1.10 2010/07/03 10:58:37 amb Exp $
+
+ Load the translations from a file and the functions for handling them.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/translations.h b/src/translations.h
new file mode 100644 (file)
index 0000000..13902ed
--- /dev/null
@@ -0,0 +1,69 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/translations.h,v 1.4 2010/05/29 13:54:23 amb Exp $
+
+ Load the translations from a file and the functions for handling them.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/types.c b/src/types.c
new file mode 100644 (file)
index 0000000..3670992
--- /dev/null
@@ -0,0 +1,488 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/types.c,v 1.3 2010/05/27 17:25:23 amb Exp $
+
+ Functions for handling the data types.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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"
+        ;
+}
diff --git a/src/types.h b/src/types.h
new file mode 100644 (file)
index 0000000..852122f
--- /dev/null
@@ -0,0 +1,350 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/types.h,v 1.40 2010/05/27 17:25:23 amb Exp $
+
+ Type definitions
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/typesx.h b/src/typesx.h
new file mode 100644 (file)
index 0000000..25a350d
--- /dev/null
@@ -0,0 +1,56 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/typesx.h,v 1.3 2009/10/09 18:47:40 amb Exp $
+
+ Type definitions for eXtended types.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008,2009 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/visualiser.c b/src/visualiser.c
new file mode 100644 (file)
index 0000000..c4a5da4
--- /dev/null
@@ -0,0 +1,628 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/visualiser.c,v 1.7 2009/07/09 18:34:38 amb Exp $
+
+ Extract data from Routino.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008,2009 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+         }
+      }
+}
diff --git a/src/visualiser.h b/src/visualiser.h
new file mode 100644 (file)
index 0000000..4ea38c7
--- /dev/null
@@ -0,0 +1,48 @@
+/***************************************
+ $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 */
diff --git a/src/ways.c b/src/ways.c
new file mode 100644 (file)
index 0000000..3142415
--- /dev/null
@@ -0,0 +1,103 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/ways.c,v 1.44 2010/04/28 17:27:02 amb Exp $
+
+ Way data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/ways.h b/src/ways.h
new file mode 100644 (file)
index 0000000..7a5a94a
--- /dev/null
@@ -0,0 +1,96 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/ways.h,v 1.37 2010/05/29 13:54:24 amb Exp $
+
+ A header file for the ways.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/waysx.c b/src/waysx.c
new file mode 100644 (file)
index 0000000..3c4635b
--- /dev/null
@@ -0,0 +1,623 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/waysx.c,v 1.38 2010/05/22 18:40:47 amb Exp $
+
+ Extended Way data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/waysx.h b/src/waysx.h
new file mode 100644 (file)
index 0000000..1aa8b62
--- /dev/null
@@ -0,0 +1,87 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/waysx.h,v 1.21 2010/05/22 18:40:47 amb Exp $
+
+ A header file for the extended Ways structure.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/xml/Makefile b/src/xml/Makefile
new file mode 100644 (file)
index 0000000..81bfd04
--- /dev/null
@@ -0,0 +1,134 @@
+# $Header: /home/amb/routino/src/xml/RCS/Makefile,v 1.10 2010/07/07 17:26:24 amb Exp $
+#
+# XML test programs Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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 :
diff --git a/src/xml/test/bad-attr-character-ref.xml b/src/xml/test/bad-attr-character-ref.xml
new file mode 100644 (file)
index 0000000..6ab951c
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 &amp; value2 &lt; &#320;">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-attr-entity-ref.xml b/src/xml/test/bad-attr-entity-ref.xml
new file mode 100644 (file)
index 0000000..7a3a5ba
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 &amp; value2 &tl; &#32;">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-cdata-start.xml b/src/xml/test/bad-cdata-start.xml
new file mode 100644 (file)
index 0000000..cd9c4ed
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+      <![[CDATA <level1> ]]>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-comment-ends-triple-dash.xml b/src/xml/test/bad-comment-ends-triple-dash.xml
new file mode 100644 (file)
index 0000000..17a105a
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- bad comment --->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-double-quote-attr-amp.xml b/src/xml/test/bad-double-quote-attr-amp.xml
new file mode 100644 (file)
index 0000000..fd58f46
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 & value2">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-double-quote-attr-left-angle.xml b/src/xml/test/bad-double-quote-attr-left-angle.xml
new file mode 100644 (file)
index 0000000..c6dc80b
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 < value2">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-double-quote-attr-right-angle.xml b/src/xml/test/bad-double-quote-attr-right-angle.xml
new file mode 100644 (file)
index 0000000..f4c0428
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 > value2">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-early-end-of-file.xml b/src/xml/test/bad-early-end-of-file.xml
new file mode 100644 (file)
index 0000000..7990b44
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
diff --git a/src/xml/test/bad-end-tag-space-at-begin1.xml b/src/xml/test/bad-end-tag-space-at-begin1.xml
new file mode 100644 (file)
index 0000000..ca9f42a
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </ level1>
+
+</test>
diff --git a/src/xml/test/bad-end-tag-space-at-begin2.xml b/src/xml/test/bad-end-tag-space-at-begin2.xml
new file mode 100644 (file)
index 0000000..aeae822
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  < /level1>
+
+</test>
diff --git a/src/xml/test/bad-end-tag-space-at-end.xml b/src/xml/test/bad-end-tag-space-at-end.xml
new file mode 100644 (file)
index 0000000..b060674
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1 >
+
+</test>
diff --git a/src/xml/test/bad-end-tag-with-attr.xml b/src/xml/test/bad-end-tag-with-attr.xml
new file mode 100644 (file)
index 0000000..dab05b1
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1 attr1="value">
+
+</test>
diff --git a/src/xml/test/bad-single-quote-attr-amp.xml b/src/xml/test/bad-single-quote-attr-amp.xml
new file mode 100644 (file)
index 0000000..30200c5
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1='value1 & value2'>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-single-quote-attr-left-angle.xml b/src/xml/test/bad-single-quote-attr-left-angle.xml
new file mode 100644 (file)
index 0000000..10c8ba0
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1='value1 < value2'>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-single-quote-attr-right-angle.xml b/src/xml/test/bad-single-quote-attr-right-angle.xml
new file mode 100644 (file)
index 0000000..d043b8a
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1='value1 > value2'>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-start-tag-space-at-begin.xml b/src/xml/test/bad-start-tag-space-at-begin.xml
new file mode 100644 (file)
index 0000000..02e81bb
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  < level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-tag-attr-no-quotes.xml b/src/xml/test/bad-tag-attr-no-quotes.xml
new file mode 100644 (file)
index 0000000..bdc476e
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1=value>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-tag-attr-space-after-equal.xml b/src/xml/test/bad-tag-attr-space-after-equal.xml
new file mode 100644 (file)
index 0000000..1ba6847
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1= "value">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-tag-attr-space-before-equal.xml b/src/xml/test/bad-tag-attr-space-before-equal.xml
new file mode 100644 (file)
index 0000000..06236c6
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1 ="value">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-tag-level-nesting.xml b/src/xml/test/bad-tag-level-nesting.xml
new file mode 100644 (file)
index 0000000..dba5592
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level2>
+    <level1>
+    </level1>
+  </level2>
+
+</test>
diff --git a/src/xml/test/bad-unbalanced-tag-start-end.xml b/src/xml/test/bad-unbalanced-tag-start-end.xml
new file mode 100644 (file)
index 0000000..e375475
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level2>
+
+</test>
diff --git a/src/xml/test/bad-unexpected-attribute-name.xml b/src/xml/test/bad-unexpected-attribute-name.xml
new file mode 100644 (file)
index 0000000..9b17fdd
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attribute="value">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-unexpected-end-tag.xml b/src/xml/test/bad-unexpected-end-tag.xml
new file mode 100644 (file)
index 0000000..219d79b
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  </level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-unexpected-left-angle.xml b/src/xml/test/bad-unexpected-left-angle.xml
new file mode 100644 (file)
index 0000000..d8ecbea
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+      <
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-unexpected-right-angle.xml b/src/xml/test/bad-unexpected-right-angle.xml
new file mode 100644 (file)
index 0000000..358524e
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+      >
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-xml-header-at-begin.xml b/src/xml/test/bad-xml-header-at-begin.xml
new file mode 100644 (file)
index 0000000..e19fc5f
--- /dev/null
@@ -0,0 +1,12 @@
+<? xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-xml-header-at-end.xml b/src/xml/test/bad-xml-header-at-end.xml
new file mode 100644 (file)
index 0000000..2a3857d
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" >
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/bad-xml-header-not-first.xml b/src/xml/test/bad-xml-header-not-first.xml
new file mode 100644 (file)
index 0000000..cdabc6b
--- /dev/null
@@ -0,0 +1,12 @@
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
+
+<?xml version="1.0" encoding="utf-8" ?>
diff --git a/src/xml/test/good.xml b/src/xml/test/good.xml
new file mode 100644 (file)
index 0000000..f7e207c
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 &amp; value2 &lt; &#32;">
+    <level2>
+      <![CDATA[ <angle brackets> ]]>
+    </level2>
+  </level1>
+
+</test>
diff --git a/src/xml/test/test.xsd b/src/xml/test/test.xsd
new file mode 100644 (file)
index 0000000..fce04ee
--- /dev/null
@@ -0,0 +1,39 @@
+<?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>
diff --git a/src/xml/xsd-to-xmlparser.c b/src/xml/xsd-to-xmlparser.c
new file mode 100644 (file)
index 0000000..6e15d9d
--- /dev/null
@@ -0,0 +1,514 @@
+/***************************************
+ $Header: /home/amb/routino/src/xml/RCS/xsd-to-xmlparser.c,v 1.10 2010/04/23 18:41:20 amb Exp $
+
+ An XML parser for simplified XML Schema Definitions to create XML parser skeletons.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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);
+}
diff --git a/src/xmlparse.h b/src/xmlparse.h
new file mode 100644 (file)
index 0000000..93ff0c9
--- /dev/null
@@ -0,0 +1,136 @@
+/***************************************
+ $Header: /home/amb/routino/src/RCS/xmlparse.h,v 1.12 2010/05/14 17:55:56 amb Exp $
+
+ A simple XML parser
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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 */
diff --git a/src/xmlparse.l b/src/xmlparse.l
new file mode 100644 (file)
index 0000000..c64fdf0
--- /dev/null
@@ -0,0 +1,784 @@
+%{
+/***************************************
+ $Header: /home/amb/routino/src/RCS/xmlparse.l,v 1.17 2010/05/25 18:24:20 amb Exp $
+
+ A simple generic XML parser where the structure comes from the function parameters.
+ Not intended to be fully conforming to XML staandard or a validating parser but
+ sufficient to parse OSM XML and simple program configuration files.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <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,"&amp;"))  return("&");
+ if(!strcmp(string,"&lt;"))   return("<");
+ if(!strcmp(string,"&gt;"))   return(">");
+ if(!strcmp(string,"&apos;")) return("'");
+ if(!strcmp(string,"&quot;")) 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);
+}
diff --git a/web/INSTALL.txt b/web/INSTALL.txt
new file mode 120000 (symlink)
index 0000000..4c0523b
--- /dev/null
@@ -0,0 +1 @@
+../doc/INSTALL.txt
\ No newline at end of file
diff --git a/web/data/create.sh b/web/data/create.sh
new file mode 100755 (executable)
index 0000000..e1d5a81
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh -x
+
+# This script can download either from GeoFabrik or Cloudmade.
+
+
+# EDIT THIS to set the names of the files to download.
+files="europe/great_britain.osm.bz2 europe/ireland.osm.bz2 europe/isle_of_man.osm.bz2"
+
+# Download the files
+
+for file in $files; do
+   wget -N http://download.geofabrik.de/osm/$file
+done
+
+
+## EDIT THIS to set the names of the files to download.
+#files="europe/united_kingdom/united_kingdom.osm.bz2 europe/ireland/ireland.osm.bz2 europe/isle_of_man/isle_of_man.osm.bz2"
+#
+## Download the files
+#
+#for file in $files; do
+#   wget -N http://downloads.cloudmade.com/$file
+#done
+
+
+# Process the data
+
+bunzip2 *.bz2
+
+../bin/planetsplitter *.osm
diff --git a/web/www/openlayers/install.sh b/web/www/openlayers/install.sh
new file mode 100755 (executable)
index 0000000..60a6eee
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh -x
+
+version=2.9.1
+
+# Download the file.
+
+wget http://openlayers.org/download/OpenLayers-$version.tar.gz
+
+# Uncompress it.
+
+tar -xzf OpenLayers-$version.tar.gz
+
+# Create a custom OpenLayers file
+
+(cd OpenLayers-$version/build && python build.py ../../routino.cfg && cp OpenLayers.js ..)
+
+# Copy the files.
+
+cp -p  OpenLayers-$version/OpenLayers.js .
+cp -pr OpenLayers-$version/img .
+cp -pr OpenLayers-$version/theme .
+
+# Delete the remainder
+
+rm -rf OpenLayers-$version
diff --git a/web/www/openlayers/routino.cfg b/web/www/openlayers/routino.cfg
new file mode 100644 (file)
index 0000000..6f6226e
--- /dev/null
@@ -0,0 +1,44 @@
+# This is a configuration file to allow building an optimised OpenLayers
+# Javascript file that contains all of the features required for Routino.
+
+[first]
+OpenLayers/SingleFile.js
+OpenLayers.js
+OpenLayers/BaseTypes.js
+OpenLayers/BaseTypes/Class.js
+OpenLayers/Util.js
+Rico/Corner.js
+
+[last]
+
+[include]
+OpenLayers/Ajax.js
+OpenLayers/BaseTypes/LonLat.js
+OpenLayers/BaseTypes/Bounds.js
+OpenLayers/Control/DragFeature.js
+OpenLayers/Control/LayerSwitcher.js
+OpenLayers/Control/Navigation.js
+OpenLayers/Control/PanZoomBar.js
+OpenLayers/Control/ScaleLine.js
+OpenLayers/Feature/Vector.js
+OpenLayers/Format/GML.js
+OpenLayers/Format/GPX.js
+OpenLayers/Geometry/LineString.js
+OpenLayers/Geometry/Point.js
+OpenLayers/Geometry/Polygon.js
+OpenLayers/Layer/Boxes.js
+OpenLayers/Layer/GML.js
+OpenLayers/Layer/SphericalMercator.js
+OpenLayers/Layer/TMS.js
+OpenLayers/Layer/Vector.js
+OpenLayers/Map.js
+OpenLayers/Marker/Box.js
+OpenLayers/Projection.js
+OpenLayers/Renderer/Elements.js
+OpenLayers/Renderer/Canvas.js
+OpenLayers/Renderer/SVG.js
+OpenLayers/Renderer/VML.js
+OpenLayers/Rule.js
+OpenLayers/Style.js
+
+[exclude]
diff --git a/web/www/routino/.htaccess b/web/www/routino/.htaccess
new file mode 100644 (file)
index 0000000..29ea962
--- /dev/null
@@ -0,0 +1,40 @@
+##
+## Options for Apache web server for language specific web pages and to run
+## Routino CGI scripts.
+##
+
+# The translated router pages use the MultiViews option to serve up a version of
+# the web page depending on the client language preference.  If the line below
+# is used in a .htaccess file like this one and the "AllowOverride none" option
+# is set in the main Apache configuration file then the entry in the .htaccess
+# file will not work.
+
+#Options +MultiViews
+
+# The English language option will be served if there is no other version
+# present and no errors will be returned to the user in case of problems
+
+LanguagePriority en
+ForceLanguagePriority Prefer Fallback
+
+# The Routino CGI scripts are stored in this directory and use the filename
+# extension ".cgi".  This filename extension needs to be registered with Apache
+# for the scripts to be executed.
+
+AddHandler cgi-script .cgi
+
+# The ExecCGI option must be set for the CGIs in this directory to be executed
+# by Apache.  If the line below is used in a .htaccess file like this one and
+# the "AllowOverride none" option is set in the main Apache configuration file
+# then the entry in the .htaccess file will not work.
+
+#Options +ExecCGI
+
+# The CGI scripts that are used by Routino also call some other Perl scripts, to
+# stop these scripts from being seen by web users they can be denied by the
+# following entry.
+
+<FilesMatch .*\.pl$>
+   Order deny,allow
+   Deny from all
+</FilesMatch>
diff --git a/web/www/routino/customrouter.cgi b/web/www/routino/customrouter.cgi
new file mode 100755 (executable)
index 0000000..454818e
--- /dev/null
@@ -0,0 +1,143 @@
+#!/usr/bin/perl
+#
+# Routino router custom link CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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);
diff --git a/web/www/routino/customvisualiser.cgi b/web/www/routino/customvisualiser.cgi
new file mode 100755 (executable)
index 0000000..4b28e57
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/perl
+#
+# Routino data visualiser custom link CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008,2009 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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);
diff --git a/web/www/routino/icons/ball-0.png b/web/www/routino/icons/ball-0.png
new file mode 100644 (file)
index 0000000..d54adaa
Binary files /dev/null and b/web/www/routino/icons/ball-0.png differ
diff --git a/web/www/routino/icons/ball-1.png b/web/www/routino/icons/ball-1.png
new file mode 100644 (file)
index 0000000..fba4e31
Binary files /dev/null and b/web/www/routino/icons/ball-1.png differ
diff --git a/web/www/routino/icons/ball-2.png b/web/www/routino/icons/ball-2.png
new file mode 100644 (file)
index 0000000..e664ba6
Binary files /dev/null and b/web/www/routino/icons/ball-2.png differ
diff --git a/web/www/routino/icons/ball-3.png b/web/www/routino/icons/ball-3.png
new file mode 100644 (file)
index 0000000..0b8c2bf
Binary files /dev/null and b/web/www/routino/icons/ball-3.png differ
diff --git a/web/www/routino/icons/ball-4.png b/web/www/routino/icons/ball-4.png
new file mode 100644 (file)
index 0000000..e0b46c9
Binary files /dev/null and b/web/www/routino/icons/ball-4.png differ
diff --git a/web/www/routino/icons/ball-5.png b/web/www/routino/icons/ball-5.png
new file mode 100644 (file)
index 0000000..6c2aed0
Binary files /dev/null and b/web/www/routino/icons/ball-5.png differ
diff --git a/web/www/routino/icons/ball-6.png b/web/www/routino/icons/ball-6.png
new file mode 100644 (file)
index 0000000..01c37fe
Binary files /dev/null and b/web/www/routino/icons/ball-6.png differ
diff --git a/web/www/routino/icons/ball-7.png b/web/www/routino/icons/ball-7.png
new file mode 100644 (file)
index 0000000..770ca73
Binary files /dev/null and b/web/www/routino/icons/ball-7.png differ
diff --git a/web/www/routino/icons/ball-8.png b/web/www/routino/icons/ball-8.png
new file mode 100644 (file)
index 0000000..770ca73
Binary files /dev/null and b/web/www/routino/icons/ball-8.png differ
diff --git a/web/www/routino/icons/ball-9.png b/web/www/routino/icons/ball-9.png
new file mode 100644 (file)
index 0000000..770ca73
Binary files /dev/null and b/web/www/routino/icons/ball-9.png differ
diff --git a/web/www/routino/icons/create-icons.pl b/web/www/routino/icons/create-icons.pl
new file mode 100755 (executable)
index 0000000..b90964c
--- /dev/null
@@ -0,0 +1,156 @@
+#!/usr/bin/perl
+#
+# Routino icons Perl script
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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;
+  }
diff --git a/web/www/routino/icons/home.png b/web/www/routino/icons/home.png
new file mode 100644 (file)
index 0000000..1a7c261
Binary files /dev/null and b/web/www/routino/icons/home.png differ
diff --git a/web/www/routino/icons/limit-0.0.png b/web/www/routino/icons/limit-0.0.png
new file mode 100644 (file)
index 0000000..cbcf311
Binary files /dev/null and b/web/www/routino/icons/limit-0.0.png differ
diff --git a/web/www/routino/icons/limit-0.png b/web/www/routino/icons/limit-0.png
new file mode 100644 (file)
index 0000000..cbcf311
Binary files /dev/null and b/web/www/routino/icons/limit-0.png differ
diff --git a/web/www/routino/icons/limit-1.0.png b/web/www/routino/icons/limit-1.0.png
new file mode 100644 (file)
index 0000000..cd4da61
Binary files /dev/null and b/web/www/routino/icons/limit-1.0.png differ
diff --git a/web/www/routino/icons/limit-1.1.png b/web/www/routino/icons/limit-1.1.png
new file mode 100644 (file)
index 0000000..13757fa
Binary files /dev/null and b/web/www/routino/icons/limit-1.1.png differ
diff --git a/web/www/routino/icons/limit-1.2.png b/web/www/routino/icons/limit-1.2.png
new file mode 100644 (file)
index 0000000..0b0b471
Binary files /dev/null and b/web/www/routino/icons/limit-1.2.png differ
diff --git a/web/www/routino/icons/limit-1.3.png b/web/www/routino/icons/limit-1.3.png
new file mode 100644 (file)
index 0000000..a4ea5e4
Binary files /dev/null and b/web/www/routino/icons/limit-1.3.png differ
diff --git a/web/www/routino/icons/limit-1.4.png b/web/www/routino/icons/limit-1.4.png
new file mode 100644 (file)
index 0000000..9a4b268
Binary files /dev/null and b/web/www/routino/icons/limit-1.4.png differ
diff --git a/web/www/routino/icons/limit-1.5.png b/web/www/routino/icons/limit-1.5.png
new file mode 100644 (file)
index 0000000..797e931
Binary files /dev/null and b/web/www/routino/icons/limit-1.5.png differ
diff --git a/web/www/routino/icons/limit-1.6.png b/web/www/routino/icons/limit-1.6.png
new file mode 100644 (file)
index 0000000..1d622a7
Binary files /dev/null and b/web/www/routino/icons/limit-1.6.png differ
diff --git a/web/www/routino/icons/limit-1.7.png b/web/www/routino/icons/limit-1.7.png
new file mode 100644 (file)
index 0000000..80ae411
Binary files /dev/null and b/web/www/routino/icons/limit-1.7.png differ
diff --git a/web/www/routino/icons/limit-1.8.png b/web/www/routino/icons/limit-1.8.png
new file mode 100644 (file)
index 0000000..930e9a7
Binary files /dev/null and b/web/www/routino/icons/limit-1.8.png differ
diff --git a/web/www/routino/icons/limit-1.9.png b/web/www/routino/icons/limit-1.9.png
new file mode 100644 (file)
index 0000000..dd9370a
Binary files /dev/null and b/web/www/routino/icons/limit-1.9.png differ
diff --git a/web/www/routino/icons/limit-1.png b/web/www/routino/icons/limit-1.png
new file mode 100644 (file)
index 0000000..328b063
Binary files /dev/null and b/web/www/routino/icons/limit-1.png differ
diff --git a/web/www/routino/icons/limit-10.0.png b/web/www/routino/icons/limit-10.0.png
new file mode 100644 (file)
index 0000000..e77d2d9
Binary files /dev/null and b/web/www/routino/icons/limit-10.0.png differ
diff --git a/web/www/routino/icons/limit-10.1.png b/web/www/routino/icons/limit-10.1.png
new file mode 100644 (file)
index 0000000..e141d26
Binary files /dev/null and b/web/www/routino/icons/limit-10.1.png differ
diff --git a/web/www/routino/icons/limit-10.2.png b/web/www/routino/icons/limit-10.2.png
new file mode 100644 (file)
index 0000000..e4dde28
Binary files /dev/null and b/web/www/routino/icons/limit-10.2.png differ
diff --git a/web/www/routino/icons/limit-10.3.png b/web/www/routino/icons/limit-10.3.png
new file mode 100644 (file)
index 0000000..42168af
Binary files /dev/null and b/web/www/routino/icons/limit-10.3.png differ
diff --git a/web/www/routino/icons/limit-10.4.png b/web/www/routino/icons/limit-10.4.png
new file mode 100644 (file)
index 0000000..d1266d1
Binary files /dev/null and b/web/www/routino/icons/limit-10.4.png differ
diff --git a/web/www/routino/icons/limit-10.5.png b/web/www/routino/icons/limit-10.5.png
new file mode 100644 (file)
index 0000000..ad68e70
Binary files /dev/null and b/web/www/routino/icons/limit-10.5.png differ
diff --git a/web/www/routino/icons/limit-10.6.png b/web/www/routino/icons/limit-10.6.png
new file mode 100644 (file)
index 0000000..d720a87
Binary files /dev/null and b/web/www/routino/icons/limit-10.6.png differ
diff --git a/web/www/routino/icons/limit-10.7.png b/web/www/routino/icons/limit-10.7.png
new file mode 100644 (file)
index 0000000..903a30d
Binary files /dev/null and b/web/www/routino/icons/limit-10.7.png differ
diff --git a/web/www/routino/icons/limit-10.8.png b/web/www/routino/icons/limit-10.8.png
new file mode 100644 (file)
index 0000000..8f60285
Binary files /dev/null and b/web/www/routino/icons/limit-10.8.png differ
diff --git a/web/www/routino/icons/limit-10.9.png b/web/www/routino/icons/limit-10.9.png
new file mode 100644 (file)
index 0000000..360625a
Binary files /dev/null and b/web/www/routino/icons/limit-10.9.png differ
diff --git a/web/www/routino/icons/limit-10.png b/web/www/routino/icons/limit-10.png
new file mode 100644 (file)
index 0000000..4acb3b0
Binary files /dev/null and b/web/www/routino/icons/limit-10.png differ
diff --git a/web/www/routino/icons/limit-100.png b/web/www/routino/icons/limit-100.png
new file mode 100644 (file)
index 0000000..6ba354e
Binary files /dev/null and b/web/www/routino/icons/limit-100.png differ
diff --git a/web/www/routino/icons/limit-101.png b/web/www/routino/icons/limit-101.png
new file mode 100644 (file)
index 0000000..c92cc8b
Binary files /dev/null and b/web/www/routino/icons/limit-101.png differ
diff --git a/web/www/routino/icons/limit-102.png b/web/www/routino/icons/limit-102.png
new file mode 100644 (file)
index 0000000..5ab7555
Binary files /dev/null and b/web/www/routino/icons/limit-102.png differ
diff --git a/web/www/routino/icons/limit-103.png b/web/www/routino/icons/limit-103.png
new file mode 100644 (file)
index 0000000..584e55f
Binary files /dev/null and b/web/www/routino/icons/limit-103.png differ
diff --git a/web/www/routino/icons/limit-104.png b/web/www/routino/icons/limit-104.png
new file mode 100644 (file)
index 0000000..5e85bda
Binary files /dev/null and b/web/www/routino/icons/limit-104.png differ
diff --git a/web/www/routino/icons/limit-105.png b/web/www/routino/icons/limit-105.png
new file mode 100644 (file)
index 0000000..272d0a2
Binary files /dev/null and b/web/www/routino/icons/limit-105.png differ
diff --git a/web/www/routino/icons/limit-106.png b/web/www/routino/icons/limit-106.png
new file mode 100644 (file)
index 0000000..7c265c1
Binary files /dev/null and b/web/www/routino/icons/limit-106.png differ
diff --git a/web/www/routino/icons/limit-107.png b/web/www/routino/icons/limit-107.png
new file mode 100644 (file)
index 0000000..df6a87a
Binary files /dev/null and b/web/www/routino/icons/limit-107.png differ
diff --git a/web/www/routino/icons/limit-108.png b/web/www/routino/icons/limit-108.png
new file mode 100644 (file)
index 0000000..a24219f
Binary files /dev/null and b/web/www/routino/icons/limit-108.png differ
diff --git a/web/www/routino/icons/limit-109.png b/web/www/routino/icons/limit-109.png
new file mode 100644 (file)
index 0000000..fea781d
Binary files /dev/null and b/web/www/routino/icons/limit-109.png differ
diff --git a/web/www/routino/icons/limit-11.0.png b/web/www/routino/icons/limit-11.0.png
new file mode 100644 (file)
index 0000000..e1ec5ca
Binary files /dev/null and b/web/www/routino/icons/limit-11.0.png differ
diff --git a/web/www/routino/icons/limit-11.1.png b/web/www/routino/icons/limit-11.1.png
new file mode 100644 (file)
index 0000000..8fa9bec
Binary files /dev/null and b/web/www/routino/icons/limit-11.1.png differ
diff --git a/web/www/routino/icons/limit-11.2.png b/web/www/routino/icons/limit-11.2.png
new file mode 100644 (file)
index 0000000..af940fc
Binary files /dev/null and b/web/www/routino/icons/limit-11.2.png differ
diff --git a/web/www/routino/icons/limit-11.3.png b/web/www/routino/icons/limit-11.3.png
new file mode 100644 (file)
index 0000000..d7af6e9
Binary files /dev/null and b/web/www/routino/icons/limit-11.3.png differ
diff --git a/web/www/routino/icons/limit-11.4.png b/web/www/routino/icons/limit-11.4.png
new file mode 100644 (file)
index 0000000..95a1725
Binary files /dev/null and b/web/www/routino/icons/limit-11.4.png differ
diff --git a/web/www/routino/icons/limit-11.5.png b/web/www/routino/icons/limit-11.5.png
new file mode 100644 (file)
index 0000000..16a06e0
Binary files /dev/null and b/web/www/routino/icons/limit-11.5.png differ
diff --git a/web/www/routino/icons/limit-11.6.png b/web/www/routino/icons/limit-11.6.png
new file mode 100644 (file)
index 0000000..4337fcc
Binary files /dev/null and b/web/www/routino/icons/limit-11.6.png differ
diff --git a/web/www/routino/icons/limit-11.7.png b/web/www/routino/icons/limit-11.7.png
new file mode 100644 (file)
index 0000000..dd7b1fa
Binary files /dev/null and b/web/www/routino/icons/limit-11.7.png differ
diff --git a/web/www/routino/icons/limit-11.8.png b/web/www/routino/icons/limit-11.8.png
new file mode 100644 (file)
index 0000000..3c14aa9
Binary files /dev/null and b/web/www/routino/icons/limit-11.8.png differ
diff --git a/web/www/routino/icons/limit-11.9.png b/web/www/routino/icons/limit-11.9.png
new file mode 100644 (file)
index 0000000..e636cac
Binary files /dev/null and b/web/www/routino/icons/limit-11.9.png differ
diff --git a/web/www/routino/icons/limit-11.png b/web/www/routino/icons/limit-11.png
new file mode 100644 (file)
index 0000000..54d3db0
Binary files /dev/null and b/web/www/routino/icons/limit-11.png differ
diff --git a/web/www/routino/icons/limit-110.png b/web/www/routino/icons/limit-110.png
new file mode 100644 (file)
index 0000000..a711a9f
Binary files /dev/null and b/web/www/routino/icons/limit-110.png differ
diff --git a/web/www/routino/icons/limit-111.png b/web/www/routino/icons/limit-111.png
new file mode 100644 (file)
index 0000000..3c0051d
Binary files /dev/null and b/web/www/routino/icons/limit-111.png differ
diff --git a/web/www/routino/icons/limit-112.png b/web/www/routino/icons/limit-112.png
new file mode 100644 (file)
index 0000000..2f275ca
Binary files /dev/null and b/web/www/routino/icons/limit-112.png differ
diff --git a/web/www/routino/icons/limit-113.png b/web/www/routino/icons/limit-113.png
new file mode 100644 (file)
index 0000000..eef9b1e
Binary files /dev/null and b/web/www/routino/icons/limit-113.png differ
diff --git a/web/www/routino/icons/limit-114.png b/web/www/routino/icons/limit-114.png
new file mode 100644 (file)
index 0000000..2c05910
Binary files /dev/null and b/web/www/routino/icons/limit-114.png differ
diff --git a/web/www/routino/icons/limit-115.png b/web/www/routino/icons/limit-115.png
new file mode 100644 (file)
index 0000000..64930f2
Binary files /dev/null and b/web/www/routino/icons/limit-115.png differ
diff --git a/web/www/routino/icons/limit-116.png b/web/www/routino/icons/limit-116.png
new file mode 100644 (file)
index 0000000..ca9fae9
Binary files /dev/null and b/web/www/routino/icons/limit-116.png differ
diff --git a/web/www/routino/icons/limit-117.png b/web/www/routino/icons/limit-117.png
new file mode 100644 (file)
index 0000000..13700fa
Binary files /dev/null and b/web/www/routino/icons/limit-117.png differ
diff --git a/web/www/routino/icons/limit-118.png b/web/www/routino/icons/limit-118.png
new file mode 100644 (file)
index 0000000..3739a4e
Binary files /dev/null and b/web/www/routino/icons/limit-118.png differ
diff --git a/web/www/routino/icons/limit-119.png b/web/www/routino/icons/limit-119.png
new file mode 100644 (file)
index 0000000..fe6e3f4
Binary files /dev/null and b/web/www/routino/icons/limit-119.png differ
diff --git a/web/www/routino/icons/limit-12.0.png b/web/www/routino/icons/limit-12.0.png
new file mode 100644 (file)
index 0000000..9056c63
Binary files /dev/null and b/web/www/routino/icons/limit-12.0.png differ
diff --git a/web/www/routino/icons/limit-12.1.png b/web/www/routino/icons/limit-12.1.png
new file mode 100644 (file)
index 0000000..77fadc6
Binary files /dev/null and b/web/www/routino/icons/limit-12.1.png differ
diff --git a/web/www/routino/icons/limit-12.2.png b/web/www/routino/icons/limit-12.2.png
new file mode 100644 (file)
index 0000000..82a9870
Binary files /dev/null and b/web/www/routino/icons/limit-12.2.png differ
diff --git a/web/www/routino/icons/limit-12.3.png b/web/www/routino/icons/limit-12.3.png
new file mode 100644 (file)
index 0000000..395f1c5
Binary files /dev/null and b/web/www/routino/icons/limit-12.3.png differ
diff --git a/web/www/routino/icons/limit-12.4.png b/web/www/routino/icons/limit-12.4.png
new file mode 100644 (file)
index 0000000..4ed3146
Binary files /dev/null and b/web/www/routino/icons/limit-12.4.png differ
diff --git a/web/www/routino/icons/limit-12.5.png b/web/www/routino/icons/limit-12.5.png
new file mode 100644 (file)
index 0000000..cc0ebf4
Binary files /dev/null and b/web/www/routino/icons/limit-12.5.png differ
diff --git a/web/www/routino/icons/limit-12.6.png b/web/www/routino/icons/limit-12.6.png
new file mode 100644 (file)
index 0000000..1e1ba98
Binary files /dev/null and b/web/www/routino/icons/limit-12.6.png differ
diff --git a/web/www/routino/icons/limit-12.7.png b/web/www/routino/icons/limit-12.7.png
new file mode 100644 (file)
index 0000000..285c24e
Binary files /dev/null and b/web/www/routino/icons/limit-12.7.png differ
diff --git a/web/www/routino/icons/limit-12.8.png b/web/www/routino/icons/limit-12.8.png
new file mode 100644 (file)
index 0000000..21d392f
Binary files /dev/null and b/web/www/routino/icons/limit-12.8.png differ
diff --git a/web/www/routino/icons/limit-12.9.png b/web/www/routino/icons/limit-12.9.png
new file mode 100644 (file)
index 0000000..ef15df9
Binary files /dev/null and b/web/www/routino/icons/limit-12.9.png differ
diff --git a/web/www/routino/icons/limit-12.png b/web/www/routino/icons/limit-12.png
new file mode 100644 (file)
index 0000000..47e9b77
Binary files /dev/null and b/web/www/routino/icons/limit-12.png differ
diff --git a/web/www/routino/icons/limit-120.png b/web/www/routino/icons/limit-120.png
new file mode 100644 (file)
index 0000000..16cd836
Binary files /dev/null and b/web/www/routino/icons/limit-120.png differ
diff --git a/web/www/routino/icons/limit-121.png b/web/www/routino/icons/limit-121.png
new file mode 100644 (file)
index 0000000..4193181
Binary files /dev/null and b/web/www/routino/icons/limit-121.png differ
diff --git a/web/www/routino/icons/limit-122.png b/web/www/routino/icons/limit-122.png
new file mode 100644 (file)
index 0000000..a7be41d
Binary files /dev/null and b/web/www/routino/icons/limit-122.png differ
diff --git a/web/www/routino/icons/limit-123.png b/web/www/routino/icons/limit-123.png
new file mode 100644 (file)
index 0000000..f2a4f17
Binary files /dev/null and b/web/www/routino/icons/limit-123.png differ
diff --git a/web/www/routino/icons/limit-124.png b/web/www/routino/icons/limit-124.png
new file mode 100644 (file)
index 0000000..ad882d2
Binary files /dev/null and b/web/www/routino/icons/limit-124.png differ
diff --git a/web/www/routino/icons/limit-125.png b/web/www/routino/icons/limit-125.png
new file mode 100644 (file)
index 0000000..4380e3b
Binary files /dev/null and b/web/www/routino/icons/limit-125.png differ
diff --git a/web/www/routino/icons/limit-126.png b/web/www/routino/icons/limit-126.png
new file mode 100644 (file)
index 0000000..794dc21
Binary files /dev/null and b/web/www/routino/icons/limit-126.png differ
diff --git a/web/www/routino/icons/limit-127.png b/web/www/routino/icons/limit-127.png
new file mode 100644 (file)
index 0000000..f99d6e7
Binary files /dev/null and b/web/www/routino/icons/limit-127.png differ
diff --git a/web/www/routino/icons/limit-128.png b/web/www/routino/icons/limit-128.png
new file mode 100644 (file)
index 0000000..89f1522
Binary files /dev/null and b/web/www/routino/icons/limit-128.png differ
diff --git a/web/www/routino/icons/limit-129.png b/web/www/routino/icons/limit-129.png
new file mode 100644 (file)
index 0000000..16b4333
Binary files /dev/null and b/web/www/routino/icons/limit-129.png differ
diff --git a/web/www/routino/icons/limit-13.0.png b/web/www/routino/icons/limit-13.0.png
new file mode 100644 (file)
index 0000000..0007cc5
Binary files /dev/null and b/web/www/routino/icons/limit-13.0.png differ
diff --git a/web/www/routino/icons/limit-13.1.png b/web/www/routino/icons/limit-13.1.png
new file mode 100644 (file)
index 0000000..2638eee
Binary files /dev/null and b/web/www/routino/icons/limit-13.1.png differ
diff --git a/web/www/routino/icons/limit-13.2.png b/web/www/routino/icons/limit-13.2.png
new file mode 100644 (file)
index 0000000..e3e3235
Binary files /dev/null and b/web/www/routino/icons/limit-13.2.png differ
diff --git a/web/www/routino/icons/limit-13.3.png b/web/www/routino/icons/limit-13.3.png
new file mode 100644 (file)
index 0000000..51d365e
Binary files /dev/null and b/web/www/routino/icons/limit-13.3.png differ
diff --git a/web/www/routino/icons/limit-13.4.png b/web/www/routino/icons/limit-13.4.png
new file mode 100644 (file)
index 0000000..fc5bd7f
Binary files /dev/null and b/web/www/routino/icons/limit-13.4.png differ
diff --git a/web/www/routino/icons/limit-13.5.png b/web/www/routino/icons/limit-13.5.png
new file mode 100644 (file)
index 0000000..240f106
Binary files /dev/null and b/web/www/routino/icons/limit-13.5.png differ
diff --git a/web/www/routino/icons/limit-13.6.png b/web/www/routino/icons/limit-13.6.png
new file mode 100644 (file)
index 0000000..cfc242d
Binary files /dev/null and b/web/www/routino/icons/limit-13.6.png differ
diff --git a/web/www/routino/icons/limit-13.7.png b/web/www/routino/icons/limit-13.7.png
new file mode 100644 (file)
index 0000000..cff7b13
Binary files /dev/null and b/web/www/routino/icons/limit-13.7.png differ
diff --git a/web/www/routino/icons/limit-13.8.png b/web/www/routino/icons/limit-13.8.png
new file mode 100644 (file)
index 0000000..ebd5059
Binary files /dev/null and b/web/www/routino/icons/limit-13.8.png differ
diff --git a/web/www/routino/icons/limit-13.9.png b/web/www/routino/icons/limit-13.9.png
new file mode 100644 (file)
index 0000000..66af065
Binary files /dev/null and b/web/www/routino/icons/limit-13.9.png differ
diff --git a/web/www/routino/icons/limit-13.png b/web/www/routino/icons/limit-13.png
new file mode 100644 (file)
index 0000000..aa1e634
Binary files /dev/null and b/web/www/routino/icons/limit-13.png differ
diff --git a/web/www/routino/icons/limit-130.png b/web/www/routino/icons/limit-130.png
new file mode 100644 (file)
index 0000000..dd4d5c0
Binary files /dev/null and b/web/www/routino/icons/limit-130.png differ
diff --git a/web/www/routino/icons/limit-131.png b/web/www/routino/icons/limit-131.png
new file mode 100644 (file)
index 0000000..d322423
Binary files /dev/null and b/web/www/routino/icons/limit-131.png differ
diff --git a/web/www/routino/icons/limit-132.png b/web/www/routino/icons/limit-132.png
new file mode 100644 (file)
index 0000000..8b0450d
Binary files /dev/null and b/web/www/routino/icons/limit-132.png differ
diff --git a/web/www/routino/icons/limit-133.png b/web/www/routino/icons/limit-133.png
new file mode 100644 (file)
index 0000000..b589818
Binary files /dev/null and b/web/www/routino/icons/limit-133.png differ
diff --git a/web/www/routino/icons/limit-134.png b/web/www/routino/icons/limit-134.png
new file mode 100644 (file)
index 0000000..b383a4d
Binary files /dev/null and b/web/www/routino/icons/limit-134.png differ
diff --git a/web/www/routino/icons/limit-135.png b/web/www/routino/icons/limit-135.png
new file mode 100644 (file)
index 0000000..b479683
Binary files /dev/null and b/web/www/routino/icons/limit-135.png differ
diff --git a/web/www/routino/icons/limit-136.png b/web/www/routino/icons/limit-136.png
new file mode 100644 (file)
index 0000000..44ab498
Binary files /dev/null and b/web/www/routino/icons/limit-136.png differ
diff --git a/web/www/routino/icons/limit-137.png b/web/www/routino/icons/limit-137.png
new file mode 100644 (file)
index 0000000..7e0d0ae
Binary files /dev/null and b/web/www/routino/icons/limit-137.png differ
diff --git a/web/www/routino/icons/limit-138.png b/web/www/routino/icons/limit-138.png
new file mode 100644 (file)
index 0000000..fce9d0c
Binary files /dev/null and b/web/www/routino/icons/limit-138.png differ
diff --git a/web/www/routino/icons/limit-139.png b/web/www/routino/icons/limit-139.png
new file mode 100644 (file)
index 0000000..4fa82d9
Binary files /dev/null and b/web/www/routino/icons/limit-139.png differ
diff --git a/web/www/routino/icons/limit-14.0.png b/web/www/routino/icons/limit-14.0.png
new file mode 100644 (file)
index 0000000..7f93fa2
Binary files /dev/null and b/web/www/routino/icons/limit-14.0.png differ
diff --git a/web/www/routino/icons/limit-14.1.png b/web/www/routino/icons/limit-14.1.png
new file mode 100644 (file)
index 0000000..7495eb2
Binary files /dev/null and b/web/www/routino/icons/limit-14.1.png differ
diff --git a/web/www/routino/icons/limit-14.2.png b/web/www/routino/icons/limit-14.2.png
new file mode 100644 (file)
index 0000000..3dfb2ff
Binary files /dev/null and b/web/www/routino/icons/limit-14.2.png differ
diff --git a/web/www/routino/icons/limit-14.3.png b/web/www/routino/icons/limit-14.3.png
new file mode 100644 (file)
index 0000000..8c9986f
Binary files /dev/null and b/web/www/routino/icons/limit-14.3.png differ
diff --git a/web/www/routino/icons/limit-14.4.png b/web/www/routino/icons/limit-14.4.png
new file mode 100644 (file)
index 0000000..f148833
Binary files /dev/null and b/web/www/routino/icons/limit-14.4.png differ
diff --git a/web/www/routino/icons/limit-14.5.png b/web/www/routino/icons/limit-14.5.png
new file mode 100644 (file)
index 0000000..c605734
Binary files /dev/null and b/web/www/routino/icons/limit-14.5.png differ
diff --git a/web/www/routino/icons/limit-14.6.png b/web/www/routino/icons/limit-14.6.png
new file mode 100644 (file)
index 0000000..01b5295
Binary files /dev/null and b/web/www/routino/icons/limit-14.6.png differ
diff --git a/web/www/routino/icons/limit-14.7.png b/web/www/routino/icons/limit-14.7.png
new file mode 100644 (file)
index 0000000..f422d23
Binary files /dev/null and b/web/www/routino/icons/limit-14.7.png differ
diff --git a/web/www/routino/icons/limit-14.8.png b/web/www/routino/icons/limit-14.8.png
new file mode 100644 (file)
index 0000000..934de9a
Binary files /dev/null and b/web/www/routino/icons/limit-14.8.png differ
diff --git a/web/www/routino/icons/limit-14.9.png b/web/www/routino/icons/limit-14.9.png
new file mode 100644 (file)
index 0000000..d95a0c2
Binary files /dev/null and b/web/www/routino/icons/limit-14.9.png differ
diff --git a/web/www/routino/icons/limit-14.png b/web/www/routino/icons/limit-14.png
new file mode 100644 (file)
index 0000000..1c88286
Binary files /dev/null and b/web/www/routino/icons/limit-14.png differ
diff --git a/web/www/routino/icons/limit-140.png b/web/www/routino/icons/limit-140.png
new file mode 100644 (file)
index 0000000..9bce99b
Binary files /dev/null and b/web/www/routino/icons/limit-140.png differ
diff --git a/web/www/routino/icons/limit-141.png b/web/www/routino/icons/limit-141.png
new file mode 100644 (file)
index 0000000..64a0ba6
Binary files /dev/null and b/web/www/routino/icons/limit-141.png differ
diff --git a/web/www/routino/icons/limit-142.png b/web/www/routino/icons/limit-142.png
new file mode 100644 (file)
index 0000000..b1b6249
Binary files /dev/null and b/web/www/routino/icons/limit-142.png differ
diff --git a/web/www/routino/icons/limit-143.png b/web/www/routino/icons/limit-143.png
new file mode 100644 (file)
index 0000000..5b4a58c
Binary files /dev/null and b/web/www/routino/icons/limit-143.png differ
diff --git a/web/www/routino/icons/limit-144.png b/web/www/routino/icons/limit-144.png
new file mode 100644 (file)
index 0000000..d86d6c5
Binary files /dev/null and b/web/www/routino/icons/limit-144.png differ
diff --git a/web/www/routino/icons/limit-145.png b/web/www/routino/icons/limit-145.png
new file mode 100644 (file)
index 0000000..165c92a
Binary files /dev/null and b/web/www/routino/icons/limit-145.png differ
diff --git a/web/www/routino/icons/limit-146.png b/web/www/routino/icons/limit-146.png
new file mode 100644 (file)
index 0000000..70217c0
Binary files /dev/null and b/web/www/routino/icons/limit-146.png differ
diff --git a/web/www/routino/icons/limit-147.png b/web/www/routino/icons/limit-147.png
new file mode 100644 (file)
index 0000000..170edf8
Binary files /dev/null and b/web/www/routino/icons/limit-147.png differ
diff --git a/web/www/routino/icons/limit-148.png b/web/www/routino/icons/limit-148.png
new file mode 100644 (file)
index 0000000..864ce76
Binary files /dev/null and b/web/www/routino/icons/limit-148.png differ
diff --git a/web/www/routino/icons/limit-149.png b/web/www/routino/icons/limit-149.png
new file mode 100644 (file)
index 0000000..8f7df2d
Binary files /dev/null and b/web/www/routino/icons/limit-149.png differ
diff --git a/web/www/routino/icons/limit-15.0.png b/web/www/routino/icons/limit-15.0.png
new file mode 100644 (file)
index 0000000..a243a96
Binary files /dev/null and b/web/www/routino/icons/limit-15.0.png differ
diff --git a/web/www/routino/icons/limit-15.1.png b/web/www/routino/icons/limit-15.1.png
new file mode 100644 (file)
index 0000000..f358757
Binary files /dev/null and b/web/www/routino/icons/limit-15.1.png differ
diff --git a/web/www/routino/icons/limit-15.2.png b/web/www/routino/icons/limit-15.2.png
new file mode 100644 (file)
index 0000000..9011df6
Binary files /dev/null and b/web/www/routino/icons/limit-15.2.png differ
diff --git a/web/www/routino/icons/limit-15.3.png b/web/www/routino/icons/limit-15.3.png
new file mode 100644 (file)
index 0000000..6844ec9
Binary files /dev/null and b/web/www/routino/icons/limit-15.3.png differ
diff --git a/web/www/routino/icons/limit-15.4.png b/web/www/routino/icons/limit-15.4.png
new file mode 100644 (file)
index 0000000..24b88aa
Binary files /dev/null and b/web/www/routino/icons/limit-15.4.png differ
diff --git a/web/www/routino/icons/limit-15.5.png b/web/www/routino/icons/limit-15.5.png
new file mode 100644 (file)
index 0000000..95edb73
Binary files /dev/null and b/web/www/routino/icons/limit-15.5.png differ
diff --git a/web/www/routino/icons/limit-15.6.png b/web/www/routino/icons/limit-15.6.png
new file mode 100644 (file)
index 0000000..d358365
Binary files /dev/null and b/web/www/routino/icons/limit-15.6.png differ
diff --git a/web/www/routino/icons/limit-15.7.png b/web/www/routino/icons/limit-15.7.png
new file mode 100644 (file)
index 0000000..0f37478
Binary files /dev/null and b/web/www/routino/icons/limit-15.7.png differ
diff --git a/web/www/routino/icons/limit-15.8.png b/web/www/routino/icons/limit-15.8.png
new file mode 100644 (file)
index 0000000..09f5330
Binary files /dev/null and b/web/www/routino/icons/limit-15.8.png differ
diff --git a/web/www/routino/icons/limit-15.9.png b/web/www/routino/icons/limit-15.9.png
new file mode 100644 (file)
index 0000000..a8cbf6f
Binary files /dev/null and b/web/www/routino/icons/limit-15.9.png differ
diff --git a/web/www/routino/icons/limit-15.png b/web/www/routino/icons/limit-15.png
new file mode 100644 (file)
index 0000000..3c4446c
Binary files /dev/null and b/web/www/routino/icons/limit-15.png differ
diff --git a/web/www/routino/icons/limit-150.png b/web/www/routino/icons/limit-150.png
new file mode 100644 (file)
index 0000000..9cc5942
Binary files /dev/null and b/web/www/routino/icons/limit-150.png differ
diff --git a/web/www/routino/icons/limit-151.png b/web/www/routino/icons/limit-151.png
new file mode 100644 (file)
index 0000000..5221559
Binary files /dev/null and b/web/www/routino/icons/limit-151.png differ
diff --git a/web/www/routino/icons/limit-152.png b/web/www/routino/icons/limit-152.png
new file mode 100644 (file)
index 0000000..7a553a0
Binary files /dev/null and b/web/www/routino/icons/limit-152.png differ
diff --git a/web/www/routino/icons/limit-153.png b/web/www/routino/icons/limit-153.png
new file mode 100644 (file)
index 0000000..b23a3b2
Binary files /dev/null and b/web/www/routino/icons/limit-153.png differ
diff --git a/web/www/routino/icons/limit-154.png b/web/www/routino/icons/limit-154.png
new file mode 100644 (file)
index 0000000..1650af3
Binary files /dev/null and b/web/www/routino/icons/limit-154.png differ
diff --git a/web/www/routino/icons/limit-155.png b/web/www/routino/icons/limit-155.png
new file mode 100644 (file)
index 0000000..a62c3dc
Binary files /dev/null and b/web/www/routino/icons/limit-155.png differ
diff --git a/web/www/routino/icons/limit-156.png b/web/www/routino/icons/limit-156.png
new file mode 100644 (file)
index 0000000..f39fddc
Binary files /dev/null and b/web/www/routino/icons/limit-156.png differ
diff --git a/web/www/routino/icons/limit-157.png b/web/www/routino/icons/limit-157.png
new file mode 100644 (file)
index 0000000..14168dd
Binary files /dev/null and b/web/www/routino/icons/limit-157.png differ
diff --git a/web/www/routino/icons/limit-158.png b/web/www/routino/icons/limit-158.png
new file mode 100644 (file)
index 0000000..854f737
Binary files /dev/null and b/web/www/routino/icons/limit-158.png differ
diff --git a/web/www/routino/icons/limit-159.png b/web/www/routino/icons/limit-159.png
new file mode 100644 (file)
index 0000000..513314a
Binary files /dev/null and b/web/www/routino/icons/limit-159.png differ
diff --git a/web/www/routino/icons/limit-16.0.png b/web/www/routino/icons/limit-16.0.png
new file mode 100644 (file)
index 0000000..9f1244c
Binary files /dev/null and b/web/www/routino/icons/limit-16.0.png differ
diff --git a/web/www/routino/icons/limit-16.1.png b/web/www/routino/icons/limit-16.1.png
new file mode 100644 (file)
index 0000000..db59558
Binary files /dev/null and b/web/www/routino/icons/limit-16.1.png differ
diff --git a/web/www/routino/icons/limit-16.2.png b/web/www/routino/icons/limit-16.2.png
new file mode 100644 (file)
index 0000000..b3edeed
Binary files /dev/null and b/web/www/routino/icons/limit-16.2.png differ
diff --git a/web/www/routino/icons/limit-16.3.png b/web/www/routino/icons/limit-16.3.png
new file mode 100644 (file)
index 0000000..0d80cd4
Binary files /dev/null and b/web/www/routino/icons/limit-16.3.png differ
diff --git a/web/www/routino/icons/limit-16.4.png b/web/www/routino/icons/limit-16.4.png
new file mode 100644 (file)
index 0000000..c6c0038
Binary files /dev/null and b/web/www/routino/icons/limit-16.4.png differ
diff --git a/web/www/routino/icons/limit-16.5.png b/web/www/routino/icons/limit-16.5.png
new file mode 100644 (file)
index 0000000..b384f77
Binary files /dev/null and b/web/www/routino/icons/limit-16.5.png differ
diff --git a/web/www/routino/icons/limit-16.6.png b/web/www/routino/icons/limit-16.6.png
new file mode 100644 (file)
index 0000000..47a435f
Binary files /dev/null and b/web/www/routino/icons/limit-16.6.png differ
diff --git a/web/www/routino/icons/limit-16.7.png b/web/www/routino/icons/limit-16.7.png
new file mode 100644 (file)
index 0000000..f84dc90
Binary files /dev/null and b/web/www/routino/icons/limit-16.7.png differ
diff --git a/web/www/routino/icons/limit-16.8.png b/web/www/routino/icons/limit-16.8.png
new file mode 100644 (file)
index 0000000..93b0e11
Binary files /dev/null and b/web/www/routino/icons/limit-16.8.png differ
diff --git a/web/www/routino/icons/limit-16.9.png b/web/www/routino/icons/limit-16.9.png
new file mode 100644 (file)
index 0000000..ab44581
Binary files /dev/null and b/web/www/routino/icons/limit-16.9.png differ
diff --git a/web/www/routino/icons/limit-16.png b/web/www/routino/icons/limit-16.png
new file mode 100644 (file)
index 0000000..e0b8fe4
Binary files /dev/null and b/web/www/routino/icons/limit-16.png differ
diff --git a/web/www/routino/icons/limit-160.png b/web/www/routino/icons/limit-160.png
new file mode 100644 (file)
index 0000000..6cc29c8
Binary files /dev/null and b/web/www/routino/icons/limit-160.png differ
diff --git a/web/www/routino/icons/limit-17.0.png b/web/www/routino/icons/limit-17.0.png
new file mode 100644 (file)
index 0000000..40f9c66
Binary files /dev/null and b/web/www/routino/icons/limit-17.0.png differ
diff --git a/web/www/routino/icons/limit-17.1.png b/web/www/routino/icons/limit-17.1.png
new file mode 100644 (file)
index 0000000..9df040e
Binary files /dev/null and b/web/www/routino/icons/limit-17.1.png differ
diff --git a/web/www/routino/icons/limit-17.2.png b/web/www/routino/icons/limit-17.2.png
new file mode 100644 (file)
index 0000000..d005743
Binary files /dev/null and b/web/www/routino/icons/limit-17.2.png differ
diff --git a/web/www/routino/icons/limit-17.3.png b/web/www/routino/icons/limit-17.3.png
new file mode 100644 (file)
index 0000000..9d3e0d5
Binary files /dev/null and b/web/www/routino/icons/limit-17.3.png differ
diff --git a/web/www/routino/icons/limit-17.4.png b/web/www/routino/icons/limit-17.4.png
new file mode 100644 (file)
index 0000000..c21f8fb
Binary files /dev/null and b/web/www/routino/icons/limit-17.4.png differ
diff --git a/web/www/routino/icons/limit-17.5.png b/web/www/routino/icons/limit-17.5.png
new file mode 100644 (file)
index 0000000..d832cc9
Binary files /dev/null and b/web/www/routino/icons/limit-17.5.png differ
diff --git a/web/www/routino/icons/limit-17.6.png b/web/www/routino/icons/limit-17.6.png
new file mode 100644 (file)
index 0000000..44aa02c
Binary files /dev/null and b/web/www/routino/icons/limit-17.6.png differ
diff --git a/web/www/routino/icons/limit-17.7.png b/web/www/routino/icons/limit-17.7.png
new file mode 100644 (file)
index 0000000..59add22
Binary files /dev/null and b/web/www/routino/icons/limit-17.7.png differ
diff --git a/web/www/routino/icons/limit-17.8.png b/web/www/routino/icons/limit-17.8.png
new file mode 100644 (file)
index 0000000..dcb0c80
Binary files /dev/null and b/web/www/routino/icons/limit-17.8.png differ
diff --git a/web/www/routino/icons/limit-17.9.png b/web/www/routino/icons/limit-17.9.png
new file mode 100644 (file)
index 0000000..b9e4b3b
Binary files /dev/null and b/web/www/routino/icons/limit-17.9.png differ
diff --git a/web/www/routino/icons/limit-17.png b/web/www/routino/icons/limit-17.png
new file mode 100644 (file)
index 0000000..7c46a9f
Binary files /dev/null and b/web/www/routino/icons/limit-17.png differ
diff --git a/web/www/routino/icons/limit-18.0.png b/web/www/routino/icons/limit-18.0.png
new file mode 100644 (file)
index 0000000..e98a93c
Binary files /dev/null and b/web/www/routino/icons/limit-18.0.png differ
diff --git a/web/www/routino/icons/limit-18.1.png b/web/www/routino/icons/limit-18.1.png
new file mode 100644 (file)
index 0000000..4fd9f47
Binary files /dev/null and b/web/www/routino/icons/limit-18.1.png differ
diff --git a/web/www/routino/icons/limit-18.2.png b/web/www/routino/icons/limit-18.2.png
new file mode 100644 (file)
index 0000000..00f898d
Binary files /dev/null and b/web/www/routino/icons/limit-18.2.png differ
diff --git a/web/www/routino/icons/limit-18.3.png b/web/www/routino/icons/limit-18.3.png
new file mode 100644 (file)
index 0000000..0cfd866
Binary files /dev/null and b/web/www/routino/icons/limit-18.3.png differ
diff --git a/web/www/routino/icons/limit-18.4.png b/web/www/routino/icons/limit-18.4.png
new file mode 100644 (file)
index 0000000..7cc57c9
Binary files /dev/null and b/web/www/routino/icons/limit-18.4.png differ
diff --git a/web/www/routino/icons/limit-18.5.png b/web/www/routino/icons/limit-18.5.png
new file mode 100644 (file)
index 0000000..fad46e3
Binary files /dev/null and b/web/www/routino/icons/limit-18.5.png differ
diff --git a/web/www/routino/icons/limit-18.6.png b/web/www/routino/icons/limit-18.6.png
new file mode 100644 (file)
index 0000000..5e31c9f
Binary files /dev/null and b/web/www/routino/icons/limit-18.6.png differ
diff --git a/web/www/routino/icons/limit-18.7.png b/web/www/routino/icons/limit-18.7.png
new file mode 100644 (file)
index 0000000..0667779
Binary files /dev/null and b/web/www/routino/icons/limit-18.7.png differ
diff --git a/web/www/routino/icons/limit-18.8.png b/web/www/routino/icons/limit-18.8.png
new file mode 100644 (file)
index 0000000..f1bbcdd
Binary files /dev/null and b/web/www/routino/icons/limit-18.8.png differ
diff --git a/web/www/routino/icons/limit-18.9.png b/web/www/routino/icons/limit-18.9.png
new file mode 100644 (file)
index 0000000..18daefc
Binary files /dev/null and b/web/www/routino/icons/limit-18.9.png differ
diff --git a/web/www/routino/icons/limit-18.png b/web/www/routino/icons/limit-18.png
new file mode 100644 (file)
index 0000000..26caae6
Binary files /dev/null and b/web/www/routino/icons/limit-18.png differ
diff --git a/web/www/routino/icons/limit-19.0.png b/web/www/routino/icons/limit-19.0.png
new file mode 100644 (file)
index 0000000..59c9f41
Binary files /dev/null and b/web/www/routino/icons/limit-19.0.png differ
diff --git a/web/www/routino/icons/limit-19.1.png b/web/www/routino/icons/limit-19.1.png
new file mode 100644 (file)
index 0000000..5b1f015
Binary files /dev/null and b/web/www/routino/icons/limit-19.1.png differ
diff --git a/web/www/routino/icons/limit-19.2.png b/web/www/routino/icons/limit-19.2.png
new file mode 100644 (file)
index 0000000..4b43319
Binary files /dev/null and b/web/www/routino/icons/limit-19.2.png differ
diff --git a/web/www/routino/icons/limit-19.3.png b/web/www/routino/icons/limit-19.3.png
new file mode 100644 (file)
index 0000000..6db46b0
Binary files /dev/null and b/web/www/routino/icons/limit-19.3.png differ
diff --git a/web/www/routino/icons/limit-19.4.png b/web/www/routino/icons/limit-19.4.png
new file mode 100644 (file)
index 0000000..d950112
Binary files /dev/null and b/web/www/routino/icons/limit-19.4.png differ
diff --git a/web/www/routino/icons/limit-19.5.png b/web/www/routino/icons/limit-19.5.png
new file mode 100644 (file)
index 0000000..f661c94
Binary files /dev/null and b/web/www/routino/icons/limit-19.5.png differ
diff --git a/web/www/routino/icons/limit-19.6.png b/web/www/routino/icons/limit-19.6.png
new file mode 100644 (file)
index 0000000..5d18cef
Binary files /dev/null and b/web/www/routino/icons/limit-19.6.png differ
diff --git a/web/www/routino/icons/limit-19.7.png b/web/www/routino/icons/limit-19.7.png
new file mode 100644 (file)
index 0000000..2e4d2d4
Binary files /dev/null and b/web/www/routino/icons/limit-19.7.png differ
diff --git a/web/www/routino/icons/limit-19.8.png b/web/www/routino/icons/limit-19.8.png
new file mode 100644 (file)
index 0000000..720213e
Binary files /dev/null and b/web/www/routino/icons/limit-19.8.png differ
diff --git a/web/www/routino/icons/limit-19.9.png b/web/www/routino/icons/limit-19.9.png
new file mode 100644 (file)
index 0000000..1bb4406
Binary files /dev/null and b/web/www/routino/icons/limit-19.9.png differ
diff --git a/web/www/routino/icons/limit-19.png b/web/www/routino/icons/limit-19.png
new file mode 100644 (file)
index 0000000..01aa718
Binary files /dev/null and b/web/www/routino/icons/limit-19.png differ
diff --git a/web/www/routino/icons/limit-2.0.png b/web/www/routino/icons/limit-2.0.png
new file mode 100644 (file)
index 0000000..475e604
Binary files /dev/null and b/web/www/routino/icons/limit-2.0.png differ
diff --git a/web/www/routino/icons/limit-2.1.png b/web/www/routino/icons/limit-2.1.png
new file mode 100644 (file)
index 0000000..0a544a1
Binary files /dev/null and b/web/www/routino/icons/limit-2.1.png differ
diff --git a/web/www/routino/icons/limit-2.2.png b/web/www/routino/icons/limit-2.2.png
new file mode 100644 (file)
index 0000000..deed784
Binary files /dev/null and b/web/www/routino/icons/limit-2.2.png differ
diff --git a/web/www/routino/icons/limit-2.3.png b/web/www/routino/icons/limit-2.3.png
new file mode 100644 (file)
index 0000000..6087a9b
Binary files /dev/null and b/web/www/routino/icons/limit-2.3.png differ
diff --git a/web/www/routino/icons/limit-2.4.png b/web/www/routino/icons/limit-2.4.png
new file mode 100644 (file)
index 0000000..94ff741
Binary files /dev/null and b/web/www/routino/icons/limit-2.4.png differ
diff --git a/web/www/routino/icons/limit-2.5.png b/web/www/routino/icons/limit-2.5.png
new file mode 100644 (file)
index 0000000..a1bb205
Binary files /dev/null and b/web/www/routino/icons/limit-2.5.png differ
diff --git a/web/www/routino/icons/limit-2.6.png b/web/www/routino/icons/limit-2.6.png
new file mode 100644 (file)
index 0000000..ca434ef
Binary files /dev/null and b/web/www/routino/icons/limit-2.6.png differ
diff --git a/web/www/routino/icons/limit-2.7.png b/web/www/routino/icons/limit-2.7.png
new file mode 100644 (file)
index 0000000..17ae517
Binary files /dev/null and b/web/www/routino/icons/limit-2.7.png differ
diff --git a/web/www/routino/icons/limit-2.8.png b/web/www/routino/icons/limit-2.8.png
new file mode 100644 (file)
index 0000000..d879af5
Binary files /dev/null and b/web/www/routino/icons/limit-2.8.png differ
diff --git a/web/www/routino/icons/limit-2.9.png b/web/www/routino/icons/limit-2.9.png
new file mode 100644 (file)
index 0000000..9ecb9d8
Binary files /dev/null and b/web/www/routino/icons/limit-2.9.png differ
diff --git a/web/www/routino/icons/limit-2.png b/web/www/routino/icons/limit-2.png
new file mode 100644 (file)
index 0000000..b734451
Binary files /dev/null and b/web/www/routino/icons/limit-2.png differ
diff --git a/web/www/routino/icons/limit-20.0.png b/web/www/routino/icons/limit-20.0.png
new file mode 100644 (file)
index 0000000..9ed3ed1
Binary files /dev/null and b/web/www/routino/icons/limit-20.0.png differ
diff --git a/web/www/routino/icons/limit-20.png b/web/www/routino/icons/limit-20.png
new file mode 100644 (file)
index 0000000..675ab62
Binary files /dev/null and b/web/www/routino/icons/limit-20.png differ
diff --git a/web/www/routino/icons/limit-21.png b/web/www/routino/icons/limit-21.png
new file mode 100644 (file)
index 0000000..a373fa7
Binary files /dev/null and b/web/www/routino/icons/limit-21.png differ
diff --git a/web/www/routino/icons/limit-22.png b/web/www/routino/icons/limit-22.png
new file mode 100644 (file)
index 0000000..c94c15d
Binary files /dev/null and b/web/www/routino/icons/limit-22.png differ
diff --git a/web/www/routino/icons/limit-23.png b/web/www/routino/icons/limit-23.png
new file mode 100644 (file)
index 0000000..5f17e29
Binary files /dev/null and b/web/www/routino/icons/limit-23.png differ
diff --git a/web/www/routino/icons/limit-24.png b/web/www/routino/icons/limit-24.png
new file mode 100644 (file)
index 0000000..82e88dc
Binary files /dev/null and b/web/www/routino/icons/limit-24.png differ
diff --git a/web/www/routino/icons/limit-25.png b/web/www/routino/icons/limit-25.png
new file mode 100644 (file)
index 0000000..2c2c46b
Binary files /dev/null and b/web/www/routino/icons/limit-25.png differ
diff --git a/web/www/routino/icons/limit-26.png b/web/www/routino/icons/limit-26.png
new file mode 100644 (file)
index 0000000..80b54de
Binary files /dev/null and b/web/www/routino/icons/limit-26.png differ
diff --git a/web/www/routino/icons/limit-27.png b/web/www/routino/icons/limit-27.png
new file mode 100644 (file)
index 0000000..25bbc40
Binary files /dev/null and b/web/www/routino/icons/limit-27.png differ
diff --git a/web/www/routino/icons/limit-28.png b/web/www/routino/icons/limit-28.png
new file mode 100644 (file)
index 0000000..3c3b4fe
Binary files /dev/null and b/web/www/routino/icons/limit-28.png differ
diff --git a/web/www/routino/icons/limit-29.png b/web/www/routino/icons/limit-29.png
new file mode 100644 (file)
index 0000000..a910f6f
Binary files /dev/null and b/web/www/routino/icons/limit-29.png differ
diff --git a/web/www/routino/icons/limit-3.0.png b/web/www/routino/icons/limit-3.0.png
new file mode 100644 (file)
index 0000000..56022f4
Binary files /dev/null and b/web/www/routino/icons/limit-3.0.png differ
diff --git a/web/www/routino/icons/limit-3.1.png b/web/www/routino/icons/limit-3.1.png
new file mode 100644 (file)
index 0000000..78338dc
Binary files /dev/null and b/web/www/routino/icons/limit-3.1.png differ
diff --git a/web/www/routino/icons/limit-3.2.png b/web/www/routino/icons/limit-3.2.png
new file mode 100644 (file)
index 0000000..500cc94
Binary files /dev/null and b/web/www/routino/icons/limit-3.2.png differ
diff --git a/web/www/routino/icons/limit-3.3.png b/web/www/routino/icons/limit-3.3.png
new file mode 100644 (file)
index 0000000..9dc15ee
Binary files /dev/null and b/web/www/routino/icons/limit-3.3.png differ
diff --git a/web/www/routino/icons/limit-3.4.png b/web/www/routino/icons/limit-3.4.png
new file mode 100644 (file)
index 0000000..cf5583d
Binary files /dev/null and b/web/www/routino/icons/limit-3.4.png differ
diff --git a/web/www/routino/icons/limit-3.5.png b/web/www/routino/icons/limit-3.5.png
new file mode 100644 (file)
index 0000000..d42e247
Binary files /dev/null and b/web/www/routino/icons/limit-3.5.png differ
diff --git a/web/www/routino/icons/limit-3.6.png b/web/www/routino/icons/limit-3.6.png
new file mode 100644 (file)
index 0000000..af8f5be
Binary files /dev/null and b/web/www/routino/icons/limit-3.6.png differ
diff --git a/web/www/routino/icons/limit-3.7.png b/web/www/routino/icons/limit-3.7.png
new file mode 100644 (file)
index 0000000..8956978
Binary files /dev/null and b/web/www/routino/icons/limit-3.7.png differ
diff --git a/web/www/routino/icons/limit-3.8.png b/web/www/routino/icons/limit-3.8.png
new file mode 100644 (file)
index 0000000..22e26fe
Binary files /dev/null and b/web/www/routino/icons/limit-3.8.png differ
diff --git a/web/www/routino/icons/limit-3.9.png b/web/www/routino/icons/limit-3.9.png
new file mode 100644 (file)
index 0000000..6d8f22f
Binary files /dev/null and b/web/www/routino/icons/limit-3.9.png differ
diff --git a/web/www/routino/icons/limit-3.png b/web/www/routino/icons/limit-3.png
new file mode 100644 (file)
index 0000000..8426d15
Binary files /dev/null and b/web/www/routino/icons/limit-3.png differ
diff --git a/web/www/routino/icons/limit-30.png b/web/www/routino/icons/limit-30.png
new file mode 100644 (file)
index 0000000..78ddb4c
Binary files /dev/null and b/web/www/routino/icons/limit-30.png differ
diff --git a/web/www/routino/icons/limit-31.png b/web/www/routino/icons/limit-31.png
new file mode 100644 (file)
index 0000000..868746e
Binary files /dev/null and b/web/www/routino/icons/limit-31.png differ
diff --git a/web/www/routino/icons/limit-32.png b/web/www/routino/icons/limit-32.png
new file mode 100644 (file)
index 0000000..1019b1a
Binary files /dev/null and b/web/www/routino/icons/limit-32.png differ
diff --git a/web/www/routino/icons/limit-33.png b/web/www/routino/icons/limit-33.png
new file mode 100644 (file)
index 0000000..3fbed36
Binary files /dev/null and b/web/www/routino/icons/limit-33.png differ
diff --git a/web/www/routino/icons/limit-34.png b/web/www/routino/icons/limit-34.png
new file mode 100644 (file)
index 0000000..b0e1805
Binary files /dev/null and b/web/www/routino/icons/limit-34.png differ
diff --git a/web/www/routino/icons/limit-35.png b/web/www/routino/icons/limit-35.png
new file mode 100644 (file)
index 0000000..9e1b38a
Binary files /dev/null and b/web/www/routino/icons/limit-35.png differ
diff --git a/web/www/routino/icons/limit-36.png b/web/www/routino/icons/limit-36.png
new file mode 100644 (file)
index 0000000..281595e
Binary files /dev/null and b/web/www/routino/icons/limit-36.png differ
diff --git a/web/www/routino/icons/limit-37.png b/web/www/routino/icons/limit-37.png
new file mode 100644 (file)
index 0000000..f4528e4
Binary files /dev/null and b/web/www/routino/icons/limit-37.png differ
diff --git a/web/www/routino/icons/limit-38.png b/web/www/routino/icons/limit-38.png
new file mode 100644 (file)
index 0000000..6369559
Binary files /dev/null and b/web/www/routino/icons/limit-38.png differ
diff --git a/web/www/routino/icons/limit-39.png b/web/www/routino/icons/limit-39.png
new file mode 100644 (file)
index 0000000..84dd891
Binary files /dev/null and b/web/www/routino/icons/limit-39.png differ
diff --git a/web/www/routino/icons/limit-4.0.png b/web/www/routino/icons/limit-4.0.png
new file mode 100644 (file)
index 0000000..39a2c19
Binary files /dev/null and b/web/www/routino/icons/limit-4.0.png differ
diff --git a/web/www/routino/icons/limit-4.1.png b/web/www/routino/icons/limit-4.1.png
new file mode 100644 (file)
index 0000000..4e8d005
Binary files /dev/null and b/web/www/routino/icons/limit-4.1.png differ
diff --git a/web/www/routino/icons/limit-4.2.png b/web/www/routino/icons/limit-4.2.png
new file mode 100644 (file)
index 0000000..d90c7e3
Binary files /dev/null and b/web/www/routino/icons/limit-4.2.png differ
diff --git a/web/www/routino/icons/limit-4.3.png b/web/www/routino/icons/limit-4.3.png
new file mode 100644 (file)
index 0000000..73f0ba5
Binary files /dev/null and b/web/www/routino/icons/limit-4.3.png differ
diff --git a/web/www/routino/icons/limit-4.4.png b/web/www/routino/icons/limit-4.4.png
new file mode 100644 (file)
index 0000000..d024035
Binary files /dev/null and b/web/www/routino/icons/limit-4.4.png differ
diff --git a/web/www/routino/icons/limit-4.5.png b/web/www/routino/icons/limit-4.5.png
new file mode 100644 (file)
index 0000000..bbbc15e
Binary files /dev/null and b/web/www/routino/icons/limit-4.5.png differ
diff --git a/web/www/routino/icons/limit-4.6.png b/web/www/routino/icons/limit-4.6.png
new file mode 100644 (file)
index 0000000..be0f1d0
Binary files /dev/null and b/web/www/routino/icons/limit-4.6.png differ
diff --git a/web/www/routino/icons/limit-4.7.png b/web/www/routino/icons/limit-4.7.png
new file mode 100644 (file)
index 0000000..2e0ad01
Binary files /dev/null and b/web/www/routino/icons/limit-4.7.png differ
diff --git a/web/www/routino/icons/limit-4.8.png b/web/www/routino/icons/limit-4.8.png
new file mode 100644 (file)
index 0000000..6fdb029
Binary files /dev/null and b/web/www/routino/icons/limit-4.8.png differ
diff --git a/web/www/routino/icons/limit-4.9.png b/web/www/routino/icons/limit-4.9.png
new file mode 100644 (file)
index 0000000..d60a7c8
Binary files /dev/null and b/web/www/routino/icons/limit-4.9.png differ
diff --git a/web/www/routino/icons/limit-4.png b/web/www/routino/icons/limit-4.png
new file mode 100644 (file)
index 0000000..d435712
Binary files /dev/null and b/web/www/routino/icons/limit-4.png differ
diff --git a/web/www/routino/icons/limit-40.png b/web/www/routino/icons/limit-40.png
new file mode 100644 (file)
index 0000000..b774934
Binary files /dev/null and b/web/www/routino/icons/limit-40.png differ
diff --git a/web/www/routino/icons/limit-41.png b/web/www/routino/icons/limit-41.png
new file mode 100644 (file)
index 0000000..d8f9d7a
Binary files /dev/null and b/web/www/routino/icons/limit-41.png differ
diff --git a/web/www/routino/icons/limit-42.png b/web/www/routino/icons/limit-42.png
new file mode 100644 (file)
index 0000000..5ecb683
Binary files /dev/null and b/web/www/routino/icons/limit-42.png differ
diff --git a/web/www/routino/icons/limit-43.png b/web/www/routino/icons/limit-43.png
new file mode 100644 (file)
index 0000000..c7b9e27
Binary files /dev/null and b/web/www/routino/icons/limit-43.png differ
diff --git a/web/www/routino/icons/limit-44.png b/web/www/routino/icons/limit-44.png
new file mode 100644 (file)
index 0000000..4e716ac
Binary files /dev/null and b/web/www/routino/icons/limit-44.png differ
diff --git a/web/www/routino/icons/limit-45.png b/web/www/routino/icons/limit-45.png
new file mode 100644 (file)
index 0000000..a307a9c
Binary files /dev/null and b/web/www/routino/icons/limit-45.png differ
diff --git a/web/www/routino/icons/limit-46.png b/web/www/routino/icons/limit-46.png
new file mode 100644 (file)
index 0000000..07dbc1c
Binary files /dev/null and b/web/www/routino/icons/limit-46.png differ
diff --git a/web/www/routino/icons/limit-47.png b/web/www/routino/icons/limit-47.png
new file mode 100644 (file)
index 0000000..90cd65f
Binary files /dev/null and b/web/www/routino/icons/limit-47.png differ
diff --git a/web/www/routino/icons/limit-48.png b/web/www/routino/icons/limit-48.png
new file mode 100644 (file)
index 0000000..8c60143
Binary files /dev/null and b/web/www/routino/icons/limit-48.png differ
diff --git a/web/www/routino/icons/limit-49.png b/web/www/routino/icons/limit-49.png
new file mode 100644 (file)
index 0000000..24d779c
Binary files /dev/null and b/web/www/routino/icons/limit-49.png differ
diff --git a/web/www/routino/icons/limit-5.0.png b/web/www/routino/icons/limit-5.0.png
new file mode 100644 (file)
index 0000000..a135d28
Binary files /dev/null and b/web/www/routino/icons/limit-5.0.png differ
diff --git a/web/www/routino/icons/limit-5.1.png b/web/www/routino/icons/limit-5.1.png
new file mode 100644 (file)
index 0000000..94a49a0
Binary files /dev/null and b/web/www/routino/icons/limit-5.1.png differ
diff --git a/web/www/routino/icons/limit-5.2.png b/web/www/routino/icons/limit-5.2.png
new file mode 100644 (file)
index 0000000..f693572
Binary files /dev/null and b/web/www/routino/icons/limit-5.2.png differ
diff --git a/web/www/routino/icons/limit-5.3.png b/web/www/routino/icons/limit-5.3.png
new file mode 100644 (file)
index 0000000..9b7e403
Binary files /dev/null and b/web/www/routino/icons/limit-5.3.png differ
diff --git a/web/www/routino/icons/limit-5.4.png b/web/www/routino/icons/limit-5.4.png
new file mode 100644 (file)
index 0000000..7d84188
Binary files /dev/null and b/web/www/routino/icons/limit-5.4.png differ
diff --git a/web/www/routino/icons/limit-5.5.png b/web/www/routino/icons/limit-5.5.png
new file mode 100644 (file)
index 0000000..fa228be
Binary files /dev/null and b/web/www/routino/icons/limit-5.5.png differ
diff --git a/web/www/routino/icons/limit-5.6.png b/web/www/routino/icons/limit-5.6.png
new file mode 100644 (file)
index 0000000..dd217dc
Binary files /dev/null and b/web/www/routino/icons/limit-5.6.png differ
diff --git a/web/www/routino/icons/limit-5.7.png b/web/www/routino/icons/limit-5.7.png
new file mode 100644 (file)
index 0000000..db7a31b
Binary files /dev/null and b/web/www/routino/icons/limit-5.7.png differ
diff --git a/web/www/routino/icons/limit-5.8.png b/web/www/routino/icons/limit-5.8.png
new file mode 100644 (file)
index 0000000..3bdba37
Binary files /dev/null and b/web/www/routino/icons/limit-5.8.png differ
diff --git a/web/www/routino/icons/limit-5.9.png b/web/www/routino/icons/limit-5.9.png
new file mode 100644 (file)
index 0000000..753de97
Binary files /dev/null and b/web/www/routino/icons/limit-5.9.png differ
diff --git a/web/www/routino/icons/limit-5.png b/web/www/routino/icons/limit-5.png
new file mode 100644 (file)
index 0000000..024d141
Binary files /dev/null and b/web/www/routino/icons/limit-5.png differ
diff --git a/web/www/routino/icons/limit-50.png b/web/www/routino/icons/limit-50.png
new file mode 100644 (file)
index 0000000..47f94a9
Binary files /dev/null and b/web/www/routino/icons/limit-50.png differ
diff --git a/web/www/routino/icons/limit-51.png b/web/www/routino/icons/limit-51.png
new file mode 100644 (file)
index 0000000..1e5d55c
Binary files /dev/null and b/web/www/routino/icons/limit-51.png differ
diff --git a/web/www/routino/icons/limit-52.png b/web/www/routino/icons/limit-52.png
new file mode 100644 (file)
index 0000000..57e9b46
Binary files /dev/null and b/web/www/routino/icons/limit-52.png differ
diff --git a/web/www/routino/icons/limit-53.png b/web/www/routino/icons/limit-53.png
new file mode 100644 (file)
index 0000000..cd54063
Binary files /dev/null and b/web/www/routino/icons/limit-53.png differ
diff --git a/web/www/routino/icons/limit-54.png b/web/www/routino/icons/limit-54.png
new file mode 100644 (file)
index 0000000..63d1d85
Binary files /dev/null and b/web/www/routino/icons/limit-54.png differ
diff --git a/web/www/routino/icons/limit-55.png b/web/www/routino/icons/limit-55.png
new file mode 100644 (file)
index 0000000..a6f3787
Binary files /dev/null and b/web/www/routino/icons/limit-55.png differ
diff --git a/web/www/routino/icons/limit-56.png b/web/www/routino/icons/limit-56.png
new file mode 100644 (file)
index 0000000..4253793
Binary files /dev/null and b/web/www/routino/icons/limit-56.png differ
diff --git a/web/www/routino/icons/limit-57.png b/web/www/routino/icons/limit-57.png
new file mode 100644 (file)
index 0000000..97f09e6
Binary files /dev/null and b/web/www/routino/icons/limit-57.png differ
diff --git a/web/www/routino/icons/limit-58.png b/web/www/routino/icons/limit-58.png
new file mode 100644 (file)
index 0000000..b0f127d
Binary files /dev/null and b/web/www/routino/icons/limit-58.png differ
diff --git a/web/www/routino/icons/limit-59.png b/web/www/routino/icons/limit-59.png
new file mode 100644 (file)
index 0000000..91c4a95
Binary files /dev/null and b/web/www/routino/icons/limit-59.png differ
diff --git a/web/www/routino/icons/limit-6.0.png b/web/www/routino/icons/limit-6.0.png
new file mode 100644 (file)
index 0000000..60971c3
Binary files /dev/null and b/web/www/routino/icons/limit-6.0.png differ
diff --git a/web/www/routino/icons/limit-6.1.png b/web/www/routino/icons/limit-6.1.png
new file mode 100644 (file)
index 0000000..188eb62
Binary files /dev/null and b/web/www/routino/icons/limit-6.1.png differ
diff --git a/web/www/routino/icons/limit-6.2.png b/web/www/routino/icons/limit-6.2.png
new file mode 100644 (file)
index 0000000..b492ee8
Binary files /dev/null and b/web/www/routino/icons/limit-6.2.png differ
diff --git a/web/www/routino/icons/limit-6.3.png b/web/www/routino/icons/limit-6.3.png
new file mode 100644 (file)
index 0000000..a76d7ef
Binary files /dev/null and b/web/www/routino/icons/limit-6.3.png differ
diff --git a/web/www/routino/icons/limit-6.4.png b/web/www/routino/icons/limit-6.4.png
new file mode 100644 (file)
index 0000000..73937e6
Binary files /dev/null and b/web/www/routino/icons/limit-6.4.png differ
diff --git a/web/www/routino/icons/limit-6.5.png b/web/www/routino/icons/limit-6.5.png
new file mode 100644 (file)
index 0000000..43c2feb
Binary files /dev/null and b/web/www/routino/icons/limit-6.5.png differ
diff --git a/web/www/routino/icons/limit-6.6.png b/web/www/routino/icons/limit-6.6.png
new file mode 100644 (file)
index 0000000..3bea790
Binary files /dev/null and b/web/www/routino/icons/limit-6.6.png differ
diff --git a/web/www/routino/icons/limit-6.7.png b/web/www/routino/icons/limit-6.7.png
new file mode 100644 (file)
index 0000000..7c9d7f8
Binary files /dev/null and b/web/www/routino/icons/limit-6.7.png differ
diff --git a/web/www/routino/icons/limit-6.8.png b/web/www/routino/icons/limit-6.8.png
new file mode 100644 (file)
index 0000000..f20656c
Binary files /dev/null and b/web/www/routino/icons/limit-6.8.png differ
diff --git a/web/www/routino/icons/limit-6.9.png b/web/www/routino/icons/limit-6.9.png
new file mode 100644 (file)
index 0000000..c401e26
Binary files /dev/null and b/web/www/routino/icons/limit-6.9.png differ
diff --git a/web/www/routino/icons/limit-6.png b/web/www/routino/icons/limit-6.png
new file mode 100644 (file)
index 0000000..a7e7008
Binary files /dev/null and b/web/www/routino/icons/limit-6.png differ
diff --git a/web/www/routino/icons/limit-60.png b/web/www/routino/icons/limit-60.png
new file mode 100644 (file)
index 0000000..f7cba69
Binary files /dev/null and b/web/www/routino/icons/limit-60.png differ
diff --git a/web/www/routino/icons/limit-61.png b/web/www/routino/icons/limit-61.png
new file mode 100644 (file)
index 0000000..610ca73
Binary files /dev/null and b/web/www/routino/icons/limit-61.png differ
diff --git a/web/www/routino/icons/limit-62.png b/web/www/routino/icons/limit-62.png
new file mode 100644 (file)
index 0000000..90bba38
Binary files /dev/null and b/web/www/routino/icons/limit-62.png differ
diff --git a/web/www/routino/icons/limit-63.png b/web/www/routino/icons/limit-63.png
new file mode 100644 (file)
index 0000000..697557e
Binary files /dev/null and b/web/www/routino/icons/limit-63.png differ
diff --git a/web/www/routino/icons/limit-64.png b/web/www/routino/icons/limit-64.png
new file mode 100644 (file)
index 0000000..f20791c
Binary files /dev/null and b/web/www/routino/icons/limit-64.png differ
diff --git a/web/www/routino/icons/limit-65.png b/web/www/routino/icons/limit-65.png
new file mode 100644 (file)
index 0000000..61ec74c
Binary files /dev/null and b/web/www/routino/icons/limit-65.png differ
diff --git a/web/www/routino/icons/limit-66.png b/web/www/routino/icons/limit-66.png
new file mode 100644 (file)
index 0000000..30c6f05
Binary files /dev/null and b/web/www/routino/icons/limit-66.png differ
diff --git a/web/www/routino/icons/limit-67.png b/web/www/routino/icons/limit-67.png
new file mode 100644 (file)
index 0000000..fdd4cb8
Binary files /dev/null and b/web/www/routino/icons/limit-67.png differ
diff --git a/web/www/routino/icons/limit-68.png b/web/www/routino/icons/limit-68.png
new file mode 100644 (file)
index 0000000..2c46581
Binary files /dev/null and b/web/www/routino/icons/limit-68.png differ
diff --git a/web/www/routino/icons/limit-69.png b/web/www/routino/icons/limit-69.png
new file mode 100644 (file)
index 0000000..8fff32c
Binary files /dev/null and b/web/www/routino/icons/limit-69.png differ
diff --git a/web/www/routino/icons/limit-7.0.png b/web/www/routino/icons/limit-7.0.png
new file mode 100644 (file)
index 0000000..3e0feb2
Binary files /dev/null and b/web/www/routino/icons/limit-7.0.png differ
diff --git a/web/www/routino/icons/limit-7.1.png b/web/www/routino/icons/limit-7.1.png
new file mode 100644 (file)
index 0000000..72039ce
Binary files /dev/null and b/web/www/routino/icons/limit-7.1.png differ
diff --git a/web/www/routino/icons/limit-7.2.png b/web/www/routino/icons/limit-7.2.png
new file mode 100644 (file)
index 0000000..8449943
Binary files /dev/null and b/web/www/routino/icons/limit-7.2.png differ
diff --git a/web/www/routino/icons/limit-7.3.png b/web/www/routino/icons/limit-7.3.png
new file mode 100644 (file)
index 0000000..60103fc
Binary files /dev/null and b/web/www/routino/icons/limit-7.3.png differ
diff --git a/web/www/routino/icons/limit-7.4.png b/web/www/routino/icons/limit-7.4.png
new file mode 100644 (file)
index 0000000..ebe4d43
Binary files /dev/null and b/web/www/routino/icons/limit-7.4.png differ
diff --git a/web/www/routino/icons/limit-7.5.png b/web/www/routino/icons/limit-7.5.png
new file mode 100644 (file)
index 0000000..a771332
Binary files /dev/null and b/web/www/routino/icons/limit-7.5.png differ
diff --git a/web/www/routino/icons/limit-7.6.png b/web/www/routino/icons/limit-7.6.png
new file mode 100644 (file)
index 0000000..60ad68f
Binary files /dev/null and b/web/www/routino/icons/limit-7.6.png differ
diff --git a/web/www/routino/icons/limit-7.7.png b/web/www/routino/icons/limit-7.7.png
new file mode 100644 (file)
index 0000000..d4eda2f
Binary files /dev/null and b/web/www/routino/icons/limit-7.7.png differ
diff --git a/web/www/routino/icons/limit-7.8.png b/web/www/routino/icons/limit-7.8.png
new file mode 100644 (file)
index 0000000..c8d78ec
Binary files /dev/null and b/web/www/routino/icons/limit-7.8.png differ
diff --git a/web/www/routino/icons/limit-7.9.png b/web/www/routino/icons/limit-7.9.png
new file mode 100644 (file)
index 0000000..2116759
Binary files /dev/null and b/web/www/routino/icons/limit-7.9.png differ
diff --git a/web/www/routino/icons/limit-7.png b/web/www/routino/icons/limit-7.png
new file mode 100644 (file)
index 0000000..08d7295
Binary files /dev/null and b/web/www/routino/icons/limit-7.png differ
diff --git a/web/www/routino/icons/limit-70.png b/web/www/routino/icons/limit-70.png
new file mode 100644 (file)
index 0000000..2856aa9
Binary files /dev/null and b/web/www/routino/icons/limit-70.png differ
diff --git a/web/www/routino/icons/limit-71.png b/web/www/routino/icons/limit-71.png
new file mode 100644 (file)
index 0000000..2649962
Binary files /dev/null and b/web/www/routino/icons/limit-71.png differ
diff --git a/web/www/routino/icons/limit-72.png b/web/www/routino/icons/limit-72.png
new file mode 100644 (file)
index 0000000..4bc83bf
Binary files /dev/null and b/web/www/routino/icons/limit-72.png differ
diff --git a/web/www/routino/icons/limit-73.png b/web/www/routino/icons/limit-73.png
new file mode 100644 (file)
index 0000000..24ba4e4
Binary files /dev/null and b/web/www/routino/icons/limit-73.png differ
diff --git a/web/www/routino/icons/limit-74.png b/web/www/routino/icons/limit-74.png
new file mode 100644 (file)
index 0000000..f500d8b
Binary files /dev/null and b/web/www/routino/icons/limit-74.png differ
diff --git a/web/www/routino/icons/limit-75.png b/web/www/routino/icons/limit-75.png
new file mode 100644 (file)
index 0000000..1639536
Binary files /dev/null and b/web/www/routino/icons/limit-75.png differ
diff --git a/web/www/routino/icons/limit-76.png b/web/www/routino/icons/limit-76.png
new file mode 100644 (file)
index 0000000..81d97ad
Binary files /dev/null and b/web/www/routino/icons/limit-76.png differ
diff --git a/web/www/routino/icons/limit-77.png b/web/www/routino/icons/limit-77.png
new file mode 100644 (file)
index 0000000..c89d522
Binary files /dev/null and b/web/www/routino/icons/limit-77.png differ
diff --git a/web/www/routino/icons/limit-78.png b/web/www/routino/icons/limit-78.png
new file mode 100644 (file)
index 0000000..d4cc2e5
Binary files /dev/null and b/web/www/routino/icons/limit-78.png differ
diff --git a/web/www/routino/icons/limit-79.png b/web/www/routino/icons/limit-79.png
new file mode 100644 (file)
index 0000000..4ef7479
Binary files /dev/null and b/web/www/routino/icons/limit-79.png differ
diff --git a/web/www/routino/icons/limit-8.0.png b/web/www/routino/icons/limit-8.0.png
new file mode 100644 (file)
index 0000000..06a4f84
Binary files /dev/null and b/web/www/routino/icons/limit-8.0.png differ
diff --git a/web/www/routino/icons/limit-8.1.png b/web/www/routino/icons/limit-8.1.png
new file mode 100644 (file)
index 0000000..c30756e
Binary files /dev/null and b/web/www/routino/icons/limit-8.1.png differ
diff --git a/web/www/routino/icons/limit-8.2.png b/web/www/routino/icons/limit-8.2.png
new file mode 100644 (file)
index 0000000..f0cd413
Binary files /dev/null and b/web/www/routino/icons/limit-8.2.png differ
diff --git a/web/www/routino/icons/limit-8.3.png b/web/www/routino/icons/limit-8.3.png
new file mode 100644 (file)
index 0000000..01a6b36
Binary files /dev/null and b/web/www/routino/icons/limit-8.3.png differ
diff --git a/web/www/routino/icons/limit-8.4.png b/web/www/routino/icons/limit-8.4.png
new file mode 100644 (file)
index 0000000..1ec999b
Binary files /dev/null and b/web/www/routino/icons/limit-8.4.png differ
diff --git a/web/www/routino/icons/limit-8.5.png b/web/www/routino/icons/limit-8.5.png
new file mode 100644 (file)
index 0000000..2ff9460
Binary files /dev/null and b/web/www/routino/icons/limit-8.5.png differ
diff --git a/web/www/routino/icons/limit-8.6.png b/web/www/routino/icons/limit-8.6.png
new file mode 100644 (file)
index 0000000..3397564
Binary files /dev/null and b/web/www/routino/icons/limit-8.6.png differ
diff --git a/web/www/routino/icons/limit-8.7.png b/web/www/routino/icons/limit-8.7.png
new file mode 100644 (file)
index 0000000..71de255
Binary files /dev/null and b/web/www/routino/icons/limit-8.7.png differ
diff --git a/web/www/routino/icons/limit-8.8.png b/web/www/routino/icons/limit-8.8.png
new file mode 100644 (file)
index 0000000..2e449a7
Binary files /dev/null and b/web/www/routino/icons/limit-8.8.png differ
diff --git a/web/www/routino/icons/limit-8.9.png b/web/www/routino/icons/limit-8.9.png
new file mode 100644 (file)
index 0000000..8597ea2
Binary files /dev/null and b/web/www/routino/icons/limit-8.9.png differ
diff --git a/web/www/routino/icons/limit-8.png b/web/www/routino/icons/limit-8.png
new file mode 100644 (file)
index 0000000..1a85ad2
Binary files /dev/null and b/web/www/routino/icons/limit-8.png differ
diff --git a/web/www/routino/icons/limit-80.png b/web/www/routino/icons/limit-80.png
new file mode 100644 (file)
index 0000000..c445928
Binary files /dev/null and b/web/www/routino/icons/limit-80.png differ
diff --git a/web/www/routino/icons/limit-81.png b/web/www/routino/icons/limit-81.png
new file mode 100644 (file)
index 0000000..a13e364
Binary files /dev/null and b/web/www/routino/icons/limit-81.png differ
diff --git a/web/www/routino/icons/limit-82.png b/web/www/routino/icons/limit-82.png
new file mode 100644 (file)
index 0000000..88a0b21
Binary files /dev/null and b/web/www/routino/icons/limit-82.png differ
diff --git a/web/www/routino/icons/limit-83.png b/web/www/routino/icons/limit-83.png
new file mode 100644 (file)
index 0000000..3fc8401
Binary files /dev/null and b/web/www/routino/icons/limit-83.png differ
diff --git a/web/www/routino/icons/limit-84.png b/web/www/routino/icons/limit-84.png
new file mode 100644 (file)
index 0000000..89c4eaa
Binary files /dev/null and b/web/www/routino/icons/limit-84.png differ
diff --git a/web/www/routino/icons/limit-85.png b/web/www/routino/icons/limit-85.png
new file mode 100644 (file)
index 0000000..1fd523e
Binary files /dev/null and b/web/www/routino/icons/limit-85.png differ
diff --git a/web/www/routino/icons/limit-86.png b/web/www/routino/icons/limit-86.png
new file mode 100644 (file)
index 0000000..7b367dd
Binary files /dev/null and b/web/www/routino/icons/limit-86.png differ
diff --git a/web/www/routino/icons/limit-87.png b/web/www/routino/icons/limit-87.png
new file mode 100644 (file)
index 0000000..24c576e
Binary files /dev/null and b/web/www/routino/icons/limit-87.png differ
diff --git a/web/www/routino/icons/limit-88.png b/web/www/routino/icons/limit-88.png
new file mode 100644 (file)
index 0000000..f45d4b1
Binary files /dev/null and b/web/www/routino/icons/limit-88.png differ
diff --git a/web/www/routino/icons/limit-89.png b/web/www/routino/icons/limit-89.png
new file mode 100644 (file)
index 0000000..8190d03
Binary files /dev/null and b/web/www/routino/icons/limit-89.png differ
diff --git a/web/www/routino/icons/limit-9.0.png b/web/www/routino/icons/limit-9.0.png
new file mode 100644 (file)
index 0000000..0e4e1ca
Binary files /dev/null and b/web/www/routino/icons/limit-9.0.png differ
diff --git a/web/www/routino/icons/limit-9.1.png b/web/www/routino/icons/limit-9.1.png
new file mode 100644 (file)
index 0000000..1e72a3d
Binary files /dev/null and b/web/www/routino/icons/limit-9.1.png differ
diff --git a/web/www/routino/icons/limit-9.2.png b/web/www/routino/icons/limit-9.2.png
new file mode 100644 (file)
index 0000000..c874cc0
Binary files /dev/null and b/web/www/routino/icons/limit-9.2.png differ
diff --git a/web/www/routino/icons/limit-9.3.png b/web/www/routino/icons/limit-9.3.png
new file mode 100644 (file)
index 0000000..d203ff6
Binary files /dev/null and b/web/www/routino/icons/limit-9.3.png differ
diff --git a/web/www/routino/icons/limit-9.4.png b/web/www/routino/icons/limit-9.4.png
new file mode 100644 (file)
index 0000000..50e4b93
Binary files /dev/null and b/web/www/routino/icons/limit-9.4.png differ
diff --git a/web/www/routino/icons/limit-9.5.png b/web/www/routino/icons/limit-9.5.png
new file mode 100644 (file)
index 0000000..3175f28
Binary files /dev/null and b/web/www/routino/icons/limit-9.5.png differ
diff --git a/web/www/routino/icons/limit-9.6.png b/web/www/routino/icons/limit-9.6.png
new file mode 100644 (file)
index 0000000..a91d27f
Binary files /dev/null and b/web/www/routino/icons/limit-9.6.png differ
diff --git a/web/www/routino/icons/limit-9.7.png b/web/www/routino/icons/limit-9.7.png
new file mode 100644 (file)
index 0000000..b3904c9
Binary files /dev/null and b/web/www/routino/icons/limit-9.7.png differ
diff --git a/web/www/routino/icons/limit-9.8.png b/web/www/routino/icons/limit-9.8.png
new file mode 100644 (file)
index 0000000..abc116b
Binary files /dev/null and b/web/www/routino/icons/limit-9.8.png differ
diff --git a/web/www/routino/icons/limit-9.9.png b/web/www/routino/icons/limit-9.9.png
new file mode 100644 (file)
index 0000000..10be98c
Binary files /dev/null and b/web/www/routino/icons/limit-9.9.png differ
diff --git a/web/www/routino/icons/limit-9.png b/web/www/routino/icons/limit-9.png
new file mode 100644 (file)
index 0000000..5053dc9
Binary files /dev/null and b/web/www/routino/icons/limit-9.png differ
diff --git a/web/www/routino/icons/limit-90.png b/web/www/routino/icons/limit-90.png
new file mode 100644 (file)
index 0000000..c86c1bc
Binary files /dev/null and b/web/www/routino/icons/limit-90.png differ
diff --git a/web/www/routino/icons/limit-91.png b/web/www/routino/icons/limit-91.png
new file mode 100644 (file)
index 0000000..d235463
Binary files /dev/null and b/web/www/routino/icons/limit-91.png differ
diff --git a/web/www/routino/icons/limit-92.png b/web/www/routino/icons/limit-92.png
new file mode 100644 (file)
index 0000000..7200fbd
Binary files /dev/null and b/web/www/routino/icons/limit-92.png differ
diff --git a/web/www/routino/icons/limit-93.png b/web/www/routino/icons/limit-93.png
new file mode 100644 (file)
index 0000000..d500ab9
Binary files /dev/null and b/web/www/routino/icons/limit-93.png differ
diff --git a/web/www/routino/icons/limit-94.png b/web/www/routino/icons/limit-94.png
new file mode 100644 (file)
index 0000000..975386b
Binary files /dev/null and b/web/www/routino/icons/limit-94.png differ
diff --git a/web/www/routino/icons/limit-95.png b/web/www/routino/icons/limit-95.png
new file mode 100644 (file)
index 0000000..de7f9ff
Binary files /dev/null and b/web/www/routino/icons/limit-95.png differ
diff --git a/web/www/routino/icons/limit-96.png b/web/www/routino/icons/limit-96.png
new file mode 100644 (file)
index 0000000..8898cae
Binary files /dev/null and b/web/www/routino/icons/limit-96.png differ
diff --git a/web/www/routino/icons/limit-97.png b/web/www/routino/icons/limit-97.png
new file mode 100644 (file)
index 0000000..f63678c
Binary files /dev/null and b/web/www/routino/icons/limit-97.png differ
diff --git a/web/www/routino/icons/limit-98.png b/web/www/routino/icons/limit-98.png
new file mode 100644 (file)
index 0000000..b6aa054
Binary files /dev/null and b/web/www/routino/icons/limit-98.png differ
diff --git a/web/www/routino/icons/limit-99.png b/web/www/routino/icons/limit-99.png
new file mode 100644 (file)
index 0000000..b8b6b1f
Binary files /dev/null and b/web/www/routino/icons/limit-99.png differ
diff --git a/web/www/routino/icons/limit-no.png b/web/www/routino/icons/limit-no.png
new file mode 100644 (file)
index 0000000..cbcf311
Binary files /dev/null and b/web/www/routino/icons/limit-no.png differ
diff --git a/web/www/routino/icons/marker-0-grey.png b/web/www/routino/icons/marker-0-grey.png
new file mode 100644 (file)
index 0000000..29bb4c3
Binary files /dev/null and b/web/www/routino/icons/marker-0-grey.png differ
diff --git a/web/www/routino/icons/marker-0-red.png b/web/www/routino/icons/marker-0-red.png
new file mode 100644 (file)
index 0000000..9a46127
Binary files /dev/null and b/web/www/routino/icons/marker-0-red.png differ
diff --git a/web/www/routino/icons/marker-1-grey.png b/web/www/routino/icons/marker-1-grey.png
new file mode 100644 (file)
index 0000000..ecf8623
Binary files /dev/null and b/web/www/routino/icons/marker-1-grey.png differ
diff --git a/web/www/routino/icons/marker-1-red.png b/web/www/routino/icons/marker-1-red.png
new file mode 100644 (file)
index 0000000..dd50628
Binary files /dev/null and b/web/www/routino/icons/marker-1-red.png differ
diff --git a/web/www/routino/icons/marker-2-grey.png b/web/www/routino/icons/marker-2-grey.png
new file mode 100644 (file)
index 0000000..64a954a
Binary files /dev/null and b/web/www/routino/icons/marker-2-grey.png differ
diff --git a/web/www/routino/icons/marker-2-red.png b/web/www/routino/icons/marker-2-red.png
new file mode 100644 (file)
index 0000000..87765ad
Binary files /dev/null and b/web/www/routino/icons/marker-2-red.png differ
diff --git a/web/www/routino/icons/marker-3-grey.png b/web/www/routino/icons/marker-3-grey.png
new file mode 100644 (file)
index 0000000..63ecf74
Binary files /dev/null and b/web/www/routino/icons/marker-3-grey.png differ
diff --git a/web/www/routino/icons/marker-3-red.png b/web/www/routino/icons/marker-3-red.png
new file mode 100644 (file)
index 0000000..7cf0f85
Binary files /dev/null and b/web/www/routino/icons/marker-3-red.png differ
diff --git a/web/www/routino/icons/marker-4-grey.png b/web/www/routino/icons/marker-4-grey.png
new file mode 100644 (file)
index 0000000..bc310ee
Binary files /dev/null and b/web/www/routino/icons/marker-4-grey.png differ
diff --git a/web/www/routino/icons/marker-4-red.png b/web/www/routino/icons/marker-4-red.png
new file mode 100644 (file)
index 0000000..da4548e
Binary files /dev/null and b/web/www/routino/icons/marker-4-red.png differ
diff --git a/web/www/routino/icons/marker-5-grey.png b/web/www/routino/icons/marker-5-grey.png
new file mode 100644 (file)
index 0000000..0d805e5
Binary files /dev/null and b/web/www/routino/icons/marker-5-grey.png differ
diff --git a/web/www/routino/icons/marker-5-red.png b/web/www/routino/icons/marker-5-red.png
new file mode 100644 (file)
index 0000000..e6eeb93
Binary files /dev/null and b/web/www/routino/icons/marker-5-red.png differ
diff --git a/web/www/routino/icons/marker-6-grey.png b/web/www/routino/icons/marker-6-grey.png
new file mode 100644 (file)
index 0000000..c93fe1b
Binary files /dev/null and b/web/www/routino/icons/marker-6-grey.png differ
diff --git a/web/www/routino/icons/marker-6-red.png b/web/www/routino/icons/marker-6-red.png
new file mode 100644 (file)
index 0000000..87d2048
Binary files /dev/null and b/web/www/routino/icons/marker-6-red.png differ
diff --git a/web/www/routino/icons/marker-7-grey.png b/web/www/routino/icons/marker-7-grey.png
new file mode 100644 (file)
index 0000000..1bfeed2
Binary files /dev/null and b/web/www/routino/icons/marker-7-grey.png differ
diff --git a/web/www/routino/icons/marker-7-red.png b/web/www/routino/icons/marker-7-red.png
new file mode 100644 (file)
index 0000000..cbe9f41
Binary files /dev/null and b/web/www/routino/icons/marker-7-red.png differ
diff --git a/web/www/routino/icons/marker-8-grey.png b/web/www/routino/icons/marker-8-grey.png
new file mode 100644 (file)
index 0000000..fca1545
Binary files /dev/null and b/web/www/routino/icons/marker-8-grey.png differ
diff --git a/web/www/routino/icons/marker-8-red.png b/web/www/routino/icons/marker-8-red.png
new file mode 100644 (file)
index 0000000..2ae4d0d
Binary files /dev/null and b/web/www/routino/icons/marker-8-red.png differ
diff --git a/web/www/routino/icons/marker-9-grey.png b/web/www/routino/icons/marker-9-grey.png
new file mode 100644 (file)
index 0000000..4e7db79
Binary files /dev/null and b/web/www/routino/icons/marker-9-grey.png differ
diff --git a/web/www/routino/icons/marker-9-red.png b/web/www/routino/icons/marker-9-red.png
new file mode 100644 (file)
index 0000000..310b43e
Binary files /dev/null and b/web/www/routino/icons/marker-9-red.png differ
diff --git a/web/www/routino/icons/marker-home-grey.png b/web/www/routino/icons/marker-home-grey.png
new file mode 100644 (file)
index 0000000..a894854
Binary files /dev/null and b/web/www/routino/icons/marker-home-grey.png differ
diff --git a/web/www/routino/icons/marker-home-red.png b/web/www/routino/icons/marker-home-red.png
new file mode 100644 (file)
index 0000000..beb7269
Binary files /dev/null and b/web/www/routino/icons/marker-home-red.png differ
diff --git a/web/www/routino/icons/waypoint-add.png b/web/www/routino/icons/waypoint-add.png
new file mode 100644 (file)
index 0000000..c11fb26
Binary files /dev/null and b/web/www/routino/icons/waypoint-add.png differ
diff --git a/web/www/routino/icons/waypoint-centre.png b/web/www/routino/icons/waypoint-centre.png
new file mode 100644 (file)
index 0000000..e464631
Binary files /dev/null and b/web/www/routino/icons/waypoint-centre.png differ
diff --git a/web/www/routino/icons/waypoint-down.png b/web/www/routino/icons/waypoint-down.png
new file mode 100644 (file)
index 0000000..1082bfd
Binary files /dev/null and b/web/www/routino/icons/waypoint-down.png differ
diff --git a/web/www/routino/icons/waypoint-home.png b/web/www/routino/icons/waypoint-home.png
new file mode 100644 (file)
index 0000000..caf6019
Binary files /dev/null and b/web/www/routino/icons/waypoint-home.png differ
diff --git a/web/www/routino/icons/waypoint-remove.png b/web/www/routino/icons/waypoint-remove.png
new file mode 100644 (file)
index 0000000..2fcb77f
Binary files /dev/null and b/web/www/routino/icons/waypoint-remove.png differ
diff --git a/web/www/routino/icons/waypoint-up.png b/web/www/routino/icons/waypoint-up.png
new file mode 100644 (file)
index 0000000..6b1b5c0
Binary files /dev/null and b/web/www/routino/icons/waypoint-up.png differ
diff --git a/web/www/routino/index.html b/web/www/routino/index.html
new file mode 100644 (file)
index 0000000..831ef02
--- /dev/null
@@ -0,0 +1,70 @@
+<!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>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/web/www/routino/maplayout-ie6-bugfixes.css b/web/www/routino/maplayout-ie6-bugfixes.css
new file mode 100644 (file)
index 0000000..0760507
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+// Routino Internet Explorer 6 map layout web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2010 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <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%;
+}
diff --git a/web/www/routino/maplayout-ie7-bugfixes.css b/web/www/routino/maplayout-ie7-bugfixes.css
new file mode 100644 (file)
index 0000000..705056e
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+// Routino Internet Explorer 7 map layout web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2010 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <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;
+}
diff --git a/web/www/routino/maplayout.css b/web/www/routino/maplayout.css
new file mode 100644 (file)
index 0000000..bf83bb8
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+// Routino map layout web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2010 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <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;
+}
diff --git a/web/www/routino/noscript.cgi b/web/www/routino/noscript.cgi
new file mode 100755 (executable)
index 0000000..a460c81
--- /dev/null
@@ -0,0 +1,196 @@
+#!/usr/bin/perl
+#
+# Routino non-Javascript router CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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);
diff --git a/web/www/routino/noscript.html b/web/www/routino/noscript.html
new file mode 100644 (file)
index 0000000..79344e2
--- /dev/null
@@ -0,0 +1,70 @@
+<!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>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/web/www/routino/noscript.template.html b/web/www/routino/noscript.template.html
new file mode 100644 (file)
index 0000000..40eebb6
--- /dev/null
@@ -0,0 +1,420 @@
+<!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>
+&copy; Andrew M. Bishop = &lt;amb "at" gedanken.demon.co.uk&gt;
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</BODY>
+
+</HTML>
diff --git a/web/www/routino/page-elements.css b/web/www/routino/page-elements.css
new file mode 100644 (file)
index 0000000..722997d
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+// Style sheet for page elements.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2010 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <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;
+}
diff --git a/web/www/routino/page-elements.js b/web/www/routino/page-elements.js
new file mode 100644 (file)
index 0000000..f751897
--- /dev/null
@@ -0,0 +1,91 @@
+//
+// Javascript for page elements.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008,2009 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <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";
+}
diff --git a/web/www/routino/paths.pl b/web/www/routino/paths.pl
new file mode 100644 (file)
index 0000000..a896ec3
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# Routino CGI paths Perl script
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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;
diff --git a/web/www/routino/results.cgi b/web/www/routino/results.cgi
new file mode 100755 (executable)
index 0000000..5236363
--- /dev/null
@@ -0,0 +1,74 @@
+#!/usr/bin/perl
+#
+# Routino router results retrieval CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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);
diff --git a/web/www/routino/router.cgi b/web/www/routino/router.cgi
new file mode 100755 (executable)
index 0000000..41a6212
--- /dev/null
@@ -0,0 +1,105 @@
+#!/usr/bin/perl
+#
+# Routino interactive router CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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";
+  }
diff --git a/web/www/routino/router.css b/web/www/routino/router.css
new file mode 100644 (file)
index 0000000..9bb90c0
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+// Routino router web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2010 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <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 */
diff --git a/web/www/routino/router.html b/web/www/routino/router.html
new file mode 120000 (symlink)
index 0000000..9f14bc5
--- /dev/null
@@ -0,0 +1 @@
+router.html.en
\ No newline at end of file
diff --git a/web/www/routino/router.html.en b/web/www/routino/router.html.en
new file mode 100644 (file)
index 0000000..ec1020e
--- /dev/null
@@ -0,0 +1,550 @@
+<!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)">&nbsp;
+              <td>
+                <input name="lon1" type="text" size=7 title="Waypoint 1 Longitude" onchange="formSetCoords(1);"><!-- lon1 --> E&nbsp;
+              <td>
+                <input name="lat1" type="text" size=7 title="Waypoint 1 Latitude"  onchange="formSetCoords(1);"><!-- lat1 --> N&nbsp;
+              <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)">&nbsp;
+              <td>
+                <input name="lon2" type="text" size=7 title="Waypoint 2 Longitude" onchange="formSetCoords(2);"><!-- lon2 --> E&nbsp;
+              <td>
+                <input name="lat2" type="text" size=7 title="Waypoint 2 Latitude"  onchange="formSetCoords(2);"><!-- lat2 --> N&nbsp;
+              <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)">&nbsp;
+              <td>
+                <input name="lon3" type="text" size=7 title="Waypoint 3 Longitude" onchange="formSetCoords(3);"><!-- lon3 --> E&nbsp;
+              <td>
+                <input name="lat3" type="text" size=7 title="Waypoint 3 Latitude"  onchange="formSetCoords(3);"><!-- lat3 --> N&nbsp;
+              <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)">&nbsp;
+              <td>
+                <input name="lon4" type="text" size=7 title="Waypoint 4 Longitude" onchange="formSetCoords(4);"><!-- lon4 --> E&nbsp;
+              <td>
+                <input name="lat4" type="text" size=7 title="Waypoint 4 Latitude"  onchange="formSetCoords(4);"><!-- lat4 --> N&nbsp;
+              <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)">&nbsp;
+              <td>
+                <input name="lon5" type="text" size=7 title="Waypoint 5 Longitude" onchange="formSetCoords(5);"><!-- lon5 --> E&nbsp;
+              <td>
+                <input name="lat5" type="text" size=7 title="Waypoint 5 Latitude"  onchange="formSetCoords(5);"><!-- lat5 --> N&nbsp;
+              <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)">&nbsp;
+              <td>
+                <input name="lon6" type="text" size=7 title="Waypoint 6 Longitude" onchange="formSetCoords(6);"><!-- lon6 --> E&nbsp;
+              <td>
+                <input name="lat6" type="text" size=7 title="Waypoint 6 Latitude"  onchange="formSetCoords(6);"><!-- lat6 --> N&nbsp;
+              <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)">&nbsp;
+              <td>
+                <input name="lon7" type="text" size=7 title="Waypoint 7 Longitude" onchange="formSetCoords(7);"><!-- lon7 --> E&nbsp;
+              <td>
+                <input name="lat7" type="text" size=7 title="Waypoint 7 Latitude"  onchange="formSetCoords(7);"><!-- lat7 --> N&nbsp;
+              <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)">&nbsp;
+              <td>
+                <input name="lon8" type="text" size=7 title="Waypoint 8 Longitude" onchange="formSetCoords(8);"><!-- lon8 --> E&nbsp;
+              <td>
+                <input name="lat8" type="text" size=7 title="Waypoint 8 Latitude"  onchange="formSetCoords(8);"><!-- lat8 --> N&nbsp;
+              <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)">&nbsp;
+              <td>
+                <input name="lon9" type="text" size=7 title="Waypoint 9 Longitude" onchange="formSetCoords(9);"><!-- lon9 --> E&nbsp;
+              <td>
+                <input name="lat9" type="text" size=7 title="Waypoint 9 Latitude"  onchange="formSetCoords(9);"><!-- lat9 --> N&nbsp;
+              <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>
diff --git a/web/www/routino/router.js b/web/www/routino/router.js
new file mode 100644 (file)
index 0000000..efb421f
--- /dev/null
@@ -0,0 +1,1503 @@
+//
+// Routino router web page Javascript
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2010 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <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 = "";
+}
diff --git a/web/www/routino/router.pl b/web/www/routino/router.pl
new file mode 100644 (file)
index 0000000..7f5dbd0
--- /dev/null
@@ -0,0 +1,249 @@
+#
+# Routino generic router Perl script
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2010 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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;
diff --git a/web/www/routino/statistics.cgi b/web/www/routino/statistics.cgi
new file mode 100755 (executable)
index 0000000..501097a
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+#
+# Routino data statistics
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008,2009 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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";
diff --git a/web/www/routino/visualiser.cgi b/web/www/routino/visualiser.cgi
new file mode 100755 (executable)
index 0000000..d3b8f38
--- /dev/null
@@ -0,0 +1,110 @@
+#!/usr/bin/perl
+#
+# Routino data visualiser CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008,2009 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <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";
diff --git a/web/www/routino/visualiser.css b/web/www/routino/visualiser.css
new file mode 100644 (file)
index 0000000..561544e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+// Routino visualiser web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2010 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <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;
+}
diff --git a/web/www/routino/visualiser.html b/web/www/routino/visualiser.html
new file mode 100644 (file)
index 0000000..c79bea9
--- /dev/null
@@ -0,0 +1,258 @@
+<!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>
diff --git a/web/www/routino/visualiser.js b/web/www/routino/visualiser.js
new file mode 100644 (file)
index 0000000..1444c89
--- /dev/null
@@ -0,0 +1,618 @@
+//
+// Routino data visualiser web page Javascript
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2010 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <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);
+}
diff --git a/xml/Makefile b/xml/Makefile
new file mode 100644 (file)
index 0000000..c822442
--- /dev/null
@@ -0,0 +1,48 @@
+# $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
diff --git a/xml/osm.xsd b/xml/osm.xsd
new file mode 100644 (file)
index 0000000..1b657a9
--- /dev/null
@@ -0,0 +1,112 @@
+<?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>
diff --git a/xml/routino-osm.xsd b/xml/routino-osm.xsd
new file mode 100644 (file)
index 0000000..092990a
--- /dev/null
@@ -0,0 +1,123 @@
+<?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>
diff --git a/xml/routino-profiles.xml b/xml/routino-profiles.xml
new file mode 100644 (file)
index 0000000..ba3fa51
--- /dev/null
@@ -0,0 +1,461 @@
+<?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>
diff --git a/xml/routino-profiles.xsd b/xml/routino-profiles.xsd
new file mode 100644 (file)
index 0000000..7c13e94
--- /dev/null
@@ -0,0 +1,108 @@
+<?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>
diff --git a/xml/routino-tagging-nomodify.xml b/xml/routino-tagging-nomodify.xml
new file mode 100644 (file)
index 0000000..0674870
--- /dev/null
@@ -0,0 +1,43 @@
+<?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>
diff --git a/xml/routino-tagging.xml b/xml/routino-tagging.xml
new file mode 100644 (file)
index 0000000..0bec4dc
--- /dev/null
@@ -0,0 +1,435 @@
+<?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>
diff --git a/xml/routino-tagging.xsd b/xml/routino-tagging.xsd
new file mode 100644 (file)
index 0000000..7df6dae
--- /dev/null
@@ -0,0 +1,67 @@
+<?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>
diff --git a/xml/routino-translations.xml b/xml/routino-translations.xml
new file mode 100644 (file)
index 0000000..470563d
--- /dev/null
@@ -0,0 +1,177 @@
+<?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>
diff --git a/xml/routino-translations.xsd b/xml/routino-translations.xsd
new file mode 100644 (file)
index 0000000..75fbfab
--- /dev/null
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+     $Header: /home/amb/routino/xml/RCS/routino-translations.xsd,v 1.3 2010/05/29 13:54:43 amb Exp $
+
+     An XML Schema Definition for the Routino translations XML format
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level Routino translation -->
+
+  <xsd:element name="routino-translations" type="RoutinoTranslationsType"/>
+
+  <xsd:complexType name="RoutinoTranslationsType">
+    <xsd:sequence>
+      <xsd:element name="language" type="languageType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="languageType">
+    <xsd:sequence>
+      <xsd:element name="copyright"   type="CopyrightType" minOccurs="0"/>
+      <xsd:element name="turn"        type="TurnType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="heading"     type="HeadingType"   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="highway"     type="HighwayType"   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="route"       type="RouteType"     minOccurs="0" maxOccurs="2"/>
+      <xsd:element name="output-html" type="HTMLType"      minOccurs="0"/>
+      <xsd:element name="output-gpx"  type="GPXType"       minOccurs="0"/>
+    </xsd:sequence>
+    <xsd:attribute name="lang"        type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The copyright information (of the generated output, not of this file) -->
+
+  <xsd:complexType name="CopyrightType">
+    <xsd:sequence>
+      <xsd:element name="creator"   type="CopyrightCreatorType" minOccurs="0"/>
+      <xsd:element name="source"    type="CopyrightSourceType"  minOccurs="0"/>
+      <xsd:element name="license"   type="CopyrightLicenseType" minOccurs="0"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="CopyrightCreatorType">
+    <xsd:attribute name="string"  type="xsd:string"/>
+    <xsd:attribute name="text"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="CopyrightSourceType">
+    <xsd:attribute name="string"  type="xsd:string"/>
+    <xsd:attribute name="text"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="CopyrightLicenseType">
+    <xsd:attribute name="string"  type="xsd:string"/>
+    <xsd:attribute name="text"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The turn, heading, highway and route strings -->
+
+  <xsd:complexType name="TurnType">
+    <xsd:attribute name="direction" type="xsd:string"/>
+    <xsd:attribute name="string"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HeadingType">
+    <xsd:attribute name="direction" type="xsd:string"/>
+    <xsd:attribute name="string"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HighwayType">
+    <xsd:attribute name="type"      type="xsd:string"/>
+    <xsd:attribute name="string"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="RouteType">
+    <xsd:attribute name="type"      type="xsd:string"/>
+    <xsd:attribute name="string"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The HTML output strings -->
+
+  <xsd:complexType name="HTMLType">
+    <xsd:sequence>
+      <xsd:element name="waypoint" type="HTMLWaypointType" maxOccurs="2"/>
+      <xsd:element name="title"    type="HTMLTitleType"/>
+      <xsd:element name="start"    type="HTMLStartType"/>
+      <xsd:element name="node"     type="HTMLNodeType"/>
+      <xsd:element name="segment"  type="HTMLSegmentType"/>
+      <xsd:element name="stop"     type="HTMLStopType"/>
+      <xsd:element name="total"    type="HTMLTotalType"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLWaypointType">
+    <xsd:attribute name="type"   type="xsd:string"/>
+    <xsd:attribute name="string" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLTitleType">
+    <xsd:attribute name="text"  type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLStartType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLNodeType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLSegmentType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLStopType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLTotalType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The GPX output strings -->
+
+  <xsd:complexType name="GPXType">
+    <xsd:sequence>
+      <xsd:element name="waypoint" type="GPXWaypointType" maxOccurs="4"/>
+      <xsd:element name="desc"     type="GPXDescType"/>
+      <xsd:element name="name"     type="GPXNameType"/>
+      <xsd:element name="step"     type="GPXStepType"/>
+      <xsd:element name="final"    type="GPXFinalType"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="GPXWaypointType">
+    <xsd:attribute name="type"   type="xsd:string"/>
+    <xsd:attribute name="string" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="GPXDescType">
+    <xsd:attribute name="text"  type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="GPXNameType">
+    <xsd:attribute name="text"  type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="GPXStepType">
+    <xsd:attribute name="text"  type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="GPXFinalType">
+    <xsd:attribute name="text"  type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>
diff --git a/xml/xsd.xsd b/xml/xsd.xsd
new file mode 100644 (file)
index 0000000..3208cd3
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- ============================================================
+     $Header: /home/amb/routino/xml/RCS/xsd.xsd,v 1.1 2010/03/28 15:27:05 amb Exp $
+
+     An XML Schema Definition for the XML Schema Definition XML format
+
+     Not a full definition but sufficient to allow the xsd-to-xmlparser to
+     read it to bootstrap itself - a program to read in other files in the
+     same format to create more XML parsers for other useful things.
+     ============================================================
+     This file Copyright 2010 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level xsd:schema element -->
+
+  <xsd:element name="xsd:schema" type="schemaType"/>
+
+  <xsd:complexType name="schemaType">
+    <xsd:sequence>
+      <xsd:element name="xsd:element"        type="elementType"/>
+      <xsd:element name="xsd:complexType"    type="complexType"    minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="elementFormDefault" type="xsd:string"/>
+    <xsd:attribute name="xmlns:xsd"          type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The second level xsd:element and xsd:complexType elements -->
+
+  <xsd:complexType name="elementType">
+    <xsd:attribute name="name"               type="xsd:string"/>
+    <xsd:attribute name="type"               type="xsd:string"/>
+    <xsd:attribute name="minOccurs"          type="xsd:string"/>
+    <xsd:attribute name="maxOccurs"          type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="complexType">
+    <xsd:sequence>
+      <xsd:element name="xsd:sequence"       type="sequenceType"   minOccurs="0"/>
+      <xsd:element name="xsd:attribute"      type="attributeType"  minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="name"               type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The third level elements and their contents -->
+
+  <xsd:complexType name="sequenceType">
+    <xsd:sequence>
+      <xsd:element name="xsd:element"        type="elementType"    minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="attributeType">
+    <xsd:attribute name="name"               type="xsd:string"/>
+    <xsd:attribute name="type"               type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>