Hi Steve,

attached is my latest version of NodConvert. Maybe it helps you.
It doesn't contain the changes from r317.

Gerd

Date: Tue, 7 Jan 2014 08:07:21 +0000
From: [email protected]
To: [email protected]
Subject: Re: [mkgmap-dev] Loops in roads

 
Hi Gerd
> I must confest that I don't fully understand why a loop is causing
> trouble with routing. Of course, a very simple loop
> without any exit point is a problem, but why also normal
> roundabouts? In NOD, we save only parts of the roundabout,
> so NOD doesn't "see" a loop.
> Is the reason that we save the way as one polyline in
> NET and that it has only one ref to NOD?
 
I don't know. I have started on my program to display the
routing graph information on top of the roads.
I hope it will help to understand what is going on.
 
Attached is the first result. Not very useful yet, it displays the
routing nodes in black with the direction held within each part as a
short arrow. Best viewed in an svg viewer such as inkscape so you can
hide layers. I've attached a screen shot as well.
 
I based this on NodConvert but it doesn't cope with many files.
Do you have any updates to NodConvert?
 
..Steve

_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev                            
          
/*
 * Copyright (C) 2007 Steve Ratcliffe
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 * 
 *  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 General Public License for more details.
 * 
 * 
 * Author: Steve Ratcliffe
 * Create date: Dec 16, 2007
 */
package test.display;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;

import uk.me.parabola.imgfmt.Utils;
import uk.me.parabola.imgfmt.app.ImgReader;
import uk.me.parabola.imgfmt.app.map.MapReader;
import uk.me.parabola.imgfmt.app.net.RoadDef;
import uk.me.parabola.mkgmap.general.LevelInfo;

/**
 * Standalone program to display the NOD file as it is worked out.  Will start
 * out with what is in imgdecode by John Mechalas.
 *
 * Credits:
 * Alexander Atanasov and his libgarmin (http://libgarmin.sourceforge.net/) 
project.
 * Robert Vollmert
 */
public class NodConvert extends CommonDisplay {
        // whether this is a new direction compared to the previous link
        // not set for first link
        // thus, we have a short link if NEWDIR is not set and it's not the 
first link
        private static final int NEWDIR = 0x80;
        // this appears to signify the orientation of the link within the road
        private static final int SIGN = 0x40;
        private static final int CURVE = 0x20;
        private static final int LEN = 0x18;
        private static final int EXTRA = CURVE|LEN;

        // restrictions, first byte
        private static final int TOLL = 0x80;
        private static final int CLASS = 0x70;
        private static final int ONEWAY = 0x08;
        private static final int SPEED = 0x07;
        // second byte + top 2 bits of net pointer
        private static final int NOEMERGENCY = 0x8000;
        private static final int NODELIVERY  = 0x4000;
        private static final int NOCAR       = 0x0001;
        private static final int NOBUS       = 0x0002;
        private static final int NOTAXI      = 0x0004;
        private static final int NOCARPOOL   = 0x0008;
        private static final int NOFOOT      = 0x0010;
        private static final int NOBIKE      = 0x0020;
        private static final int NOTRUCK     = 0x0040;

        private static final int NO_THROUGH_ROUTING = 0x0080;
        private int citySize = 1;
        private int zipSize = 1;

        private int nodesStart;
        private int nodesLen;

        private int roadDataStart;
        private int roadDataLen;

        private int boundriesStart;
        private int boundriesLen;
        private byte boundriesRecsize;

        private final TreeMap<Integer, Offset> nod1recs = new TreeMap<Integer, 
Offset>();
        

        private NetDisplay netDisplay;

        private byte align;
        private int aMask;

        private Table curTable;

        private final String booltag = "<tag k='%s' v='%b' />\n";
        private final String inttag = "<tag k='%s' v='%d' />\n";
        private final String bytetag = "<tag k='%s' v='%02x' />\n";
        private final String strtag = "<tag k='%s' v='%s' />\n";        
        boolean convert = true;
        
        protected void print() {
                readCommonHeader();

                printHeader();
                /*
                openLbl();
                if (lbl.getCities().size() > 255)
                        citySize = 2;
                if (lbl.getZips().size() > 255)
                        zipSize = 2;

                openTre();

                openNet();
                openRgn();
                */
//              rgn.setNetFile(net);
                
                System.out.printf("<?xml version='1.0' encoding='UTF-8'?>\n");
                System.out.printf("<osm version='0.5' upload='false' 
generator='NodConvert'>\n");
                printRoadData();
                readBoundryNodes();
                for (Integer i:nod1recs.keySet())
                        System.err.println("nod1off = 0x" + 
Integer.toHexString(i));
                printNodes();
                System.out.printf("</osm>\n");
        }

        private long calcTablePosition(long start, int low) {
                long pos = start - nodesStart;
                pos += aMask + 1;
                pos += low * ((long) 1 << align);
                pos &= ~aMask;
                return nodesStart + pos;
        }

        private void printNodes() {

                Displayer d = new Displayer(reader);
                d.setTitle("NOD 1 (nodes)");
                d.setSectStart(nodesStart);

                reader.position(nodesStart);

                while (reader.position() < nodesStart + nodesLen) {
                        long start = reader.position();
                        int low = reader.get() & 0xff;


                        long end = calcTablePosition(start, low);
                        int testSectoff = (int)(start - nodesStart);
                        Offset off = nod1recs.get(testSectoff);
                        if (off == null){
                                testSectoff = getNextKnownOffset(testSectoff, 
start+1000);
                                if (testSectoff >= 0 && testSectoff < end - 
nodesStart){
                                        long pos2 = reader.position();
                                        reader.position(testSectoff + 
nodesStart);
                                        int low2 = reader.get() & 0xff;
                                        long end2 = calcTablePosition(start, 
low);
                                        if (end != end2){
                                                System.err.println("sync?");
                                        }
                                        reader.position(pos2);
                                }
                                long dd = 4;
                        }
                        
                        d.item().addText("tables at %x", end);

                        // determine size of Table C offsets
                        int tabCOffsetSize = 0;
                        reader.position(end);
                        
                        // read Table C format
                        int fmt = reader.get();
                        if((fmt & 2) != 0) {
                                // Table C size is 16 bits, so offset must be 
too
                                tabCOffsetSize = 2;
                        }
                        else if((fmt & 1) != 0) {
                                // this is tricky because the size could be 
more than
                                // 128 in which case the offset needs to be 16 
bits so
                                // we need to actually read the size to find out
                                reader.position(end + 7);
                                int tabASize = reader.get() & 0xff;
                                int tabBSize = reader.get() & 0xff;
                                reader.position(end + 9 + tabASize * 5 + 
tabBSize * 3);
                                if((reader.get() & 0xff) >= 0x80)
                                        tabCOffsetSize = 2;
                                else
                                        tabCOffsetSize = 1;
                        }
                        reader.position(start); // step back to low byte

                        if(tabCOffsetSize == 1)
                                d.item().addText("Table C offsets are 8 bits");
                        else if(tabCOffsetSize == 2)
                                d.item().addText("Table C offsets are 16 bits");
                        curTable = readTable(end, tabCOffsetSize);
                        printNode(end, tabCOffsetSize);

//                      reader.position(end);
//                      d.print(outStream);

                        //printTables(0);
                        reader.position(curTable.next);
                }

                d.print(outStream);
        }

        private void printNode(long end, int tabCOffsetSize) {
                long groupStart = reader.position();
                TableHeader tableHeader = readTableHeader((int) end);
                int lastLow = Integer.MAX_VALUE;
                while (reader.position() < end) {
//                      d.gap();
//                      d.item().addText("New node");
                        long nodeOff = reader.position();
                        if (nodeOff == 5043){
                                long dd = 4;
                        }
                        int sectoff = (int)nodeOff - nodesStart;
                        Offset off = nod1recs.get(sectoff);
                        long rest = end - nodeOff;
                        if (rest < 10){
                                long dd = 4;
                        }
                        
                        
                        int low = reader.get() & 0xff;
                        /*
                        if (low > lastLow){
                                System.err.println("lost sync: low byte too 
high:" + low + " offset:" + sectoff );
                                for (int i = sectoff - 1; i > 0; i--){
                                        Offset testOff = nod1recs.get(i);
                                        if (testOff != null){
                                                System.err.println("prev known 
offset is at " + i + " (" + (nodesStart + i + 1) + ")");
                                                break;
                                        }
                                }
                                boolean foundMore = false;
                                for (int i = sectoff + 1; i < end-nodesStart; 
i++){
                                        Offset testOff = nod1recs.get(i);
                                        if (testOff != null){
                                                System.err.println("next known 
offset is at " + i + " (" + (nodesStart + i + 1) + ")");
                                                
reader.position(testOff.getOffset() + nodesStart);
                                                foundMore = true;
                                                break;
                                        }
                                }
                                if (foundMore)
                                        continue;
                                break;
                        }
                        lastLow = low;
                        */
                        if (calcTablePosition(nodeOff, low) != end) {
                                /*
                                if (low == 0) {
                                        d.item().addText("spurious 0?");
                                        continue;
                                }
                                d.item().addText("lost sync calc-end=%x, should 
be=%x",
                                                                 
calcTablePosition(nodeOff, low), end);
                                d.rawValue((int) (end - reader.position()), 
"remaining bytes");
                                */
                                System.err.println("lost sync calc-end " + low);
                                break;
                        }

                        // byte2 looks like flags, only a small number of values
                        int flags = reader.get() & 0xff;
                        System.err.printf("flags 0x%x\n",flags);
                        boolean restr = (flags & 0x10) == 0x10;         // 
restrictions present at this node
                        boolean bigoff = (flags & 0x20) == 0x20;                
// 2 bytes each for lat/lon offsets
                        boolean boundry = (flags & 0x08) == 0x08;       // this 
is a boundry node
                        boolean arcs = (flags & 0x40) == 0x40; // has arcs

                        int minRequired = ((bigoff) ? 4:3 ) + ((arcs) ? 4:0 ) ; 
 
                        if (rest < minRequired)
                                break;
                        StringBuilder sb = new StringBuilder(": ");
                        if (restr) sb.append("restrictions ");
                        if (bigoff) sb.append("large-offsets ");
                        if (boundry) sb.append("boundry-node ");
                        if (arcs) sb.append("arcs ");

                        if (restr && tabCOffsetSize == 0 ){
                                System.err.println("lost sync: restr is true, 
but table is empty");
                        }
//                      System.out.printf(booltag, "verified offset", (off != 
null));
                        if (off == null){
                                long dd = 4;
                                if (boundry)
                                        return;
                        }
                        
                        
//                      d.item().addText(sb.toString());
                        System.out.printf("<node id='%d' ", nodeOff+1);
                        if (nodeOff + 1 == 12868){
                                long dd = 4;
                        }
                        // 1. even spread
                        // 2. biased toward 00 f0 0f ff etc
                        // 3. even
                        // 4. uneven, peaks at 0x20, 40, 60
                        // 5. uneven again
                        // 6. fairly even but big peak at 3e,3f
                        // 7. fairly even
                        // 8. number decreases with value

                        positionOffsets(tableHeader, bigoff);
                        System.out.printf("<tag k='verified' v='%b' />\n", 
off!=null);
                        System.out.printf("<tag k='restrictions' v='%b' />\n", 
restr);
                        System.out.printf("<tag k='boundary' v='%b' />\n", 
boundry);
                        System.out.printf("</node>\n");

                        if(arcs){
                                if (off == null){
                                        long dd  = 4;
                                }
                                rest = end - reader.position();
                                if (rest < 10){
                                        System.err.println("reading arc near 
table");
                                }
                                pointerPart(nodeOff, groupStart, end);
                        }
                        /*
                        if(restr) {
                            boolean done = false;
                            while(!done) {
                                        if(tabCOffsetSize == 1) {
                                                int off = 
d.byteValue("Restriction offset 0x%x");
                                                done = (off & 0x80) == 0x80;
                                        }
                                        else if(tabCOffsetSize == 2) {
                                                int off = 
d.charValue("Restriction offset 0x%x");
                                                done = (off & 0x8000) == 0x8000;
                                        }
                                        else {
                                                done = true;
                                        }
                            }
                        }
                        */
                }
                
        }
        private int tableId = 1;

        class Table {

                final int id;
                final int nodeid;

                int lat, lon;

                long next; // start of next RouteCenter

                // just the class for now
                final ArrayList<Integer> tableA = new ArrayList<Integer>();
                // destination offsets for now
                final ArrayList<Integer> tableB = new ArrayList<Integer>();

                Table() {
                        id = tableId++;
                        nodeid = -id;
                }
        }


        
        private Table readTable(long offset, int tabCOffsetSize) {
                if (offset == 0x62bf){
                        long dd = 4;
                }
                System.err.println("reading table at 0x" + 
Long.toHexString(offset));
                long orig = reader.position();

                Table table = new Table();

                reader.position(offset);


                // Get the header
                int restrbytes = reader.get() & 0xff;

                int l = latLongField();
                table.lon = l;

                l = latLongField();
                table.lat = l;
                System.out.printf(Locale.ROOT, "<node id='%d' lon='%f' 
lat='%f'>\n",
                        table.nodeid,
                        Utils.toDegrees(table.lon),
                        Utils.toDegrees(table.lat));
                System.out.printf(strtag, "routecenter", table.id);
                System.out.printf("</node>\n");



                int n = reader.get() & 0xff;
                int m = reader.get() & 0xff;

                System.err.println("table sizes: " + n + " " + m);

                // Now do 'Table A' (segments)
                for (int i = 0; i < n; i++) {
                        int off = reader.get3();
                        off &= 0x3fffff;
                        System.err.printf("net off: %06x\n", off);
                        int paramA = reader.get();
                        table.tableA.add((paramA & CLASS) >> 4);
                        reader.get();
                }

                // 'Table B' (inter-section pointers)
                for (int i = 0; i < m; i++) {
                        System.err.println("adding table b entry " + i);
                        int nod1off = reader.getu3();
                        if (nod1off > nodesLen){
                                System.err.println("lost sync: invalid entry in 
tableB" );
                        }
                        table.tableB.add(nod1off);
                }

                if (tabCOffsetSize != 0){
                        // 'Table C' (restrictions)
                        int size=0;
                        // I've seen restrbytes up to 2
                        if (restrbytes == 0) {
                                // if next byte is 0, discard it
                                long pos = reader.position();
                                int val = reader.get();
                                if(val == 0) {
                                        //d.item().addText("table c size is 
zero");
                                        System.err.println("zero byte 
discarded");
                                }
                                else {
                                        // rewind so that byte gets used
                                        reader.position(pos);
                                }               
                        }
                        else if ((restrbytes & 1) != 0) {
                                size = reader.get() & 0xff;
                        }
                        else if ((restrbytes & 2) != 0) {
                                size = reader.getChar() & 0xffff;
                        }

                        if (size % 11 == 0) {
                                // assume these are fixed length records of 
size 11
                                for (; size > 0; size -= 11) {
                                        // turn restriction at second node from 
first node (via first segment)
                                        // to third node (via second segment)
                                        reader.get3();
                                        for (int i = 0; i < 3; i++) {
                                                reader.getChar();
                                        }
                                        reader.get();
                                        reader.get();
                                }
                        } else {
                                reader.get(size);
                        }
                }
                if ((restrbytes & 4) != 0) {
                        //d.byteValue("??? restrformat4");
                        reader.get();
                }

                if ((restrbytes & 8) != 0) {
                        //d.byteValue("%d unpaved roads");
                        reader.get();
                }

                if((restrbytes & 0x10) != 0) {
                        //d.byteValue("%d ferry routes");
                        reader.get();
                }

                if(/*restrbytes != 0 && (restrbytes & 0x03) == 0*/ 
tabCOffsetSize == 0) {
//                      d.byteValue("???");
                        long pos = reader.position();
                        int unk = reader.get() & 0xff;
                        if (unk != 0)
                                reader.position(pos);
                        else 
                                System.err.printf("unk byte eaten: %x\n" , unk);
                }
                
                table.next = reader.position();

                // Restore position
                reader.position(orig);

                return table;
        }

        private TableHeader readTableHeader(int offset) {
                long orig = reader.position();

                TableHeader tableHeader = new TableHeader();

                reader.position(offset);
                reader.get();

                tableHeader.setLong(reader.get3());
                tableHeader.setLat(reader.get3());

                // Restore position
                reader.position(orig);

                return tableHeader;
        }

        private void positionOffsets(TableHeader currentTableHeader, boolean 
bigoff) {
                short latoff, longoff;
                if (bigoff ) {
                        longoff = (short) reader.getChar();
                        latoff = (short) reader.getChar();

                } else {
                        int latlon = reader.get3();

                        latoff = (short) (latlon >> 12);
                        if ((latoff & 0x800) != 0)
                                latoff |= 0xf000;
                        longoff = (short) (latlon & 0xfff);
                        if ((longoff & 0x800) != 0)
                                longoff |= 0xf000;
                }
                System.out.printf(Locale.ROOT, "lon='%f' lat='%f'>\n",
                                Utils.toDegrees(longoff + 
currentTableHeader.getLon()),
                                Utils.toDegrees(latoff + 
currentTableHeader.getLat()));
        }

        private void pointerPart(long offset, long min, long max) {
                // looks like there are 2b before the low1 pointer and 4 after.
                boolean end = false;
                boolean first = true;

                do {
                        if (reader.position() == 5184){
                                long dd = 4;
                        }
                        if (reader.position() + 10 > max ){
                                long dd = 4; // close to end
                        }
                        System.out.printf("<way id='%d'>\n", reader.position());
                        System.out.printf("<nd ref='%d' />\n", offset+1);
                        // Start with alt6 byte
                        // bit 0x20 seems to determine whether there's an extra 
byte at the end
                        int alt6 = reader.get() & 0xff;
                        System.out.printf(bytetag, "alt6", alt6);


                        // this is not the class of the segment, but the max of 
classes of the dest node
                        int classmask = 0x07;
                        boolean newdir = (alt6 & NEWDIR) != 0;
                        System.out.printf(booltag, "newdir", newdir);
                        int destclass = alt6 & classmask;
                        System.out.printf(inttag, "destclass", destclass);
                        System.out.printf(booltag, "sign", (alt6 & SIGN) != 0);
                        if (first) {
                                newdir = true;
                                first = false;
                        }

                        // Continue with two byte values.  The first one has 
the top
                        // bit set if this is the last pointer in the node 
record.
                        int flagB = reader.get() & 0xff;

                        // Note that this is the last if it is.
                        if ((flagB & 0x80) == 0x80) {
                                end = true;
                                System.out.printf(booltag, "last", true);
                        }

                        // The second highest bit, means inter-section pointer
                        boolean external = (flagB & 0x40) == 0x40;
                        System.out.printf(booltag, "external", external);
                        
                        long pos = reader.position();
                        
                        if (external) {
                                int idx = flagB & 0x3f;
                                if (idx == 0x3f) {
                                        idx = reader.get() & 0xff;
                                }
                                System.out.printf(inttag, "indexB", idx);
                                int off = curTable.tableB.get(idx);
                                if (nod1recs.containsKey(off) == false){
                                        long dd = 4;
                                } else {
                                        long dd = 4;
                                }
                                System.out.printf("<nd ref='%d' />\n",
                                                off +1);
                        } else {
                                // in-section relative node pointer
                                int intro2 = reader.get() & 0xff;
                                short nodeoff = (short) ((flagB << 8 | intro2) 
& 0x3fff);

                                // Construct a pointer to another node, signed 
16 bit quantity
                                if ((nodeoff & 0x2000) != 0)
                                        nodeoff |= 0xc000;
                                long otherNode = offset + nodeoff;
                                if (min > otherNode || otherNode >= max) {
                                        System.err.println("lost sync in 
pointerPart");
                                }
                                System.out.printf("<nd ref='%d' />\n", 
otherNode+1);

                        }
                        if (newdir && curTable.tableA.isEmpty()){
                                System.err.println("newdir with empty tableA");
                        }
                        if (newdir){
                                int indexA = reader.get() & 0xff;
                                System.out.printf(inttag, "indexA", indexA);
                                System.out.printf(inttag, "roadclass",
                                                curTable.tableA.get(indexA));
                        } else {
                                //d.item().addText("short link, no segment 
pointer");
                        }
                        System.out.printf(strtag, "type", newdir ? "arc" : 
"link");

                        int len;
                        boolean curve;
                        int curveInfo = (alt6 & EXTRA) >> 3; 
                
                        System.err.println("curveinfo: " + curveInfo);
                        if (curveInfo != 7){
                                long dd = 4;
                        }
                        if ((alt6 & EXTRA) == EXTRA) {
                                int len1 = reader.get() & 0xff;
                                if ((len1 & 0x80) == 0x80) {
                                        if ((len1 & 0x40) == 0x40) {
                                                int len2 = reader.getChar();
                                                len = (len1 & 0x3f) | (len2 << 
6); // 6+16 bits
                                                System.out.printf(inttag, 
"lengthbits", 22);
                                                if (len <(1 << 14)) {
                                                        
System.err.println("invalid length 22 bits?");          
                                                }
                                                curve = true;
                                        } else {
                                                int len2 = reader.get() & 0xff;
                                                len = (len1 & 0x3f) | (len2 << 
6); // 6+8 bits
                                                System.out.printf(inttag, 
"lengthbits", 14);
                                                curve = false;
                                        }
                                } else {
                                        int len2 = reader.get() & 0xff;
                                        len = (len1 & 0x7f) | (len2 << 7); // 
7+8 bits
                                        System.out.printf(inttag, "lengthbits", 
15);
                                        
                                        curve = true;
                                }
                        }
                        else {
                                curve = (alt6 & CURVE) == CURVE;
                                len = (alt6 & 0x08) << 5;
                                len |= reader.get() & 0xff; // 1+8 bits
                                if (len > 0x200){
                                        System.err.println("invalid length 9 
bits?");
                                }
                                System.out.printf(inttag, "lengthbits", 9);
                        }
                        // length should be in units of 16 feet
                        System.out.printf(inttag, "length-16f", len);
                        System.out.printf(inttag, "length-m", (int)(len * 16 / 
3.2808));

                        if (newdir) {
                                int dir = reader.get();
                                System.out.printf(inttag, "direction", (dir * 
360) >> 8);
                        }
        
                        if (curve) {
                                int curvea = reader.get() & 0xff;
                                pos = reader.position();
                                int curveb;
                                if ((curvea & 0xe0) == 0) {
                                        curveb = reader.get() & 0xff;
                                        //item.addText("curve[0] %02x curve[1] 
%02x (two bytes)", curvea, curveb);
                                        System.out.printf(inttag, "curvebytes", 
2);
                                        if (curveb == 0){
                                                long dd = 4;
//                                              reader.position(pos);
                                        }

                                } else {
                                        System.out.printf(inttag, "curvebytes", 
1);
                                        System.out.printf(inttag, 
"curvebyte-raw", curvea);
                                        int angle = 360 * (byte)(((curvea & 
0x1f) << 3) |
                                                                                
         ((curvea & 0xe0) >> 5)) / 256;
                                        //item.addText("curve[0] %02x (%d 
deg?)", curvea, angle);
                                        curveb = (curvea & 0x1f) << 3;
                                        curvea = curvea & 0x70;
                                }
                                System.out.printf(inttag, "curvea", curvea);
                                System.out.printf(inttag, "curveb", curveb);
                                
                        }
                        System.out.printf("</way>\n");
                } while (!end);
        }

        private void printTables(int len) {
                int remain = len;

                // Get the header
                TableHeader tableHeader = new TableHeader();
                tableHeader.setPosition(reader.position());
                int restrformat = reader.get() & 0xff; 
                remain -= 1;

                int l = latLongField();
                tableHeader.setLong(l);
                remain -= 3;

                l = latLongField();
                tableHeader.setLat(l);
                remain -= 3;

                int n = reader.get() & 0xff;
                remain -= 1;
                int m = reader.get() & 0xff;
                remain -= 1;

                // Now do 'Table A' (segments)
                for (int i = 0; i < n; i++) {
                        int off = reader.get3();
                        int paramA = reader.get();
                        int paramB = reader.get();
                        /*
                        // top 2 bits of net pointer are access bits
                        int access = (off & 0xc00000) >> 8;
                        off &= 0x3fffff;

                        String par = "class %d, speed %d";
                        if ((paramA & TOLL) == TOLL)
                                par += ", toll";
                        if ((paramA & ONEWAY) == ONEWAY)
                                par += ", oneway";
                        if ((paramB & NO_THROUGH_ROUTING) == NO_THROUGH_ROUTING)
                                par += ", no through routing";
                        item.addText(par, (paramA & CLASS) >> 4, paramA & 
SPEED);

                        access |= paramB & 0xff;
                        par = "";
                        par += (access & NOEMERGENCY) == 0 ? "emergency, " : 
"no emergency, ";
                        par += (access & NODELIVERY) == 0 ? "delivery, " : "no 
delivery, ";
                        par += (access & NOCAR) == 0 ? "car, " : "no car, ";
                        par += (access & NOBUS) == 0 ? "bus, " : "no bus, ";
                        par += (access & NOTAXI) == 0 ? "taxi, " : "no taxi, ";
                        par += (access & NOCARPOOL) == 0 ? "carpool, " : "no 
carpool, ";
                        par += (access & NOFOOT) == 0 ? "foot, " : "no foot, ";
                        par += (access & NOBIKE) == 0 ? "bike, " : "no bike, ";
                        par += (access & NOTRUCK) == 0 ? "truck, " : "no truck, 
";

                        item.addText("access: %s", par);
                        if((paramB & 0x08) != 0)
                                item.addText("Unknown access bits: %02x", 
paramB & 0x08);
                         */
                        remain -= 5;
                }
//              d.print(outStream);

                // 'Table B' (inter-section pointers)
//              d.setTitle("Table B (inter-section pointers)");
                for (int i = 0; i < m; i++) {
                        int nodeOff = reader.get3();
                        remain -= 3;
                }
//              d.print(outStream);

                // 'Table C' (restrictions)
//              d.setTitle("Table C (restrictions)");
                int size=0;
                if (restrformat == 0) {
                        // if next byte is 0, discard it
                        long pos = reader.position();
                        int val = reader.get();
                        if(val == 0) {
//                              d.item().addText("table c size is zero");
                        }
                        else {
                                // rewind so that byte gets used
                                reader.position(pos);
                        }
                }
                else if ((restrformat & 1) != 0) {
                        size = reader.get() & 0xff;
                        remain--;
                }
                else if ((restrformat & 2) != 0) {
                        size = reader.getChar() & 0xffff;
                        remain -= 2;
                }

                if (size % 11 == 0) {
                        // assume these are fixed length records of size 11
                        remain -= size;
                        for (; size > 0; size -= 11) {
                                // turn restriction at second node from first 
node (via first segment)
                                // to third node (via second segment)
//                              d.rawValue(3, "restriction header");
                                reader.get3();

                                for (int i = 0; i < 3; i++) {
                                        int off = reader.getChar() & 0xffff;

                                }
                                reader.get();
                                reader.get();
                        }
                } else {
                        reader.get(size);
                        remain -= size;
                }

                if ((restrformat & 4) != 0) {
//                      d.byteValue("??? restrformat4");
                        reader.get();
                        remain--;
                }

                if ((restrformat & 8) != 0) {
//                      d.byteValue("%d unpaved roads");
                        reader.get();
                        remain--;
                }

                if((restrformat & 0x10) != 0) {
//                      d.byteValue("%d ferry routes");
                        reader.get();
                        remain--;
                }

                if(restrformat != 0 && (restrformat & 0x03) == 0) {
//                      d.byteValue("???");
                        reader.get();
                        remain--;
                }

//              d.print(outStream);

                // if there's something left, we probably missed the first
                // node of the next section
                /*
                if (remain > 0) {
                        d.setTitle("left over");
                        d.rawValue(remain, "extra data remaining");
                }

                d.print(outStream);
                d.setTitle("");
                */
        }

        private int latLongField() {
                int l = reader.get3();
                if ((l & 0x800000) != 0)
                        l |= 0xff000000;
                return l;
        }

        private String getNameFromNetOff(int off) {
                if (netDisplay != null)
                        return netDisplay.getNameFromNetOff(off);
                else
                        return "";
        }

        private void printRoadData() {
                Displayer d = new Displayer(reader);
                d.setTitle("NOD 2 (road data)");
                d.setSectStart(roadDataStart);
                d.print(outStream);

                reader.position(roadDataStart);
                int end = roadDataStart + roadDataLen;
                int nrecords = 0;
                while (reader.position() < end) {
                        nrecords++;
                        d = new Displayer(reader);
                        d.setSectStart(roadDataStart);

                        int recstart = (int) reader.position();

                        // XXX looks like a set of flags but ?
                        // agree with speed & class in RouteParam (plus one bit)
                        DisplayItem item = d.item();
                        int flags = item.setBytes(reader.get());
                        item.addText("Road classification speed=%d, type=%d",
                                                 (flags & 0xf) >> 1, (flags & 
0x70) >> 4);
                        if((flags & 1) == 0)
                                item.addText("bit 0 is zero");
                        int sectoff = d.int3Value("offset into NOD 1 %06x");
                        String origin = (new Formatter()).format("nod 2 %06x", 
recstart).toString();
                        Offset offset = nod1recs.get(sectoff);
                        if (offset != null) {
                                offset.appendOrigin(origin);
                        } else {
                                Offset offval = new Offset(sectoff, origin);
                                nod1recs.put(sectoff, offval);
                        }

                        // Ok this is the number of bits in the following.
                        int nbits = d.charValue("Bit stream len");

                        // The number of set bits appears to be the number of 
nodes in the road.
                        // Usually th lowest nbits appear to be set, and I've 
seen the lowest
                        // missing when an end of the road is not a node. --Rob 

                        // A number of bits follows.  Work out how many bytes 
are needed to
                        // hold that number of bits.
                        int nstream = (nbits+7)/8;
                        byte[] bs = d.rawValue(nstream, "Bit stream");
                        String bsStr = bitStreamAsString(bs, nbits);
                        d.item().addText("BIT STREAM %s", bsStr);

                        if((flags & 0x80) != 0) {
                                int extraFormat = d.byteValue("extra data 
format");
                                if(extraFormat >= 0x01 && extraFormat <= 0x0b) {
                                        if((extraFormat & 0x01) != 0) {
                                                int len = d.byteValue("len");
                                                d.rawValue(len >> 1, "extra 
data 1");
                                        }
                                        if((extraFormat & 0x02) != 0) {
                                                int len = d.byteValue("len");
                                                d.rawValue(len >> 1, "extra 
data 2");
                                        }
                                        if((extraFormat & 0x04) != 0) {
                                                int extra = d.byteValue("extra 
data 4");
                                        }
                                        if((extraFormat & 0x08) != 0) {
                                                int extra = d.charValue("extra 
data 8");
                                        }
                                }
                                else if(extraFormat == 0x0c) {
                                        int len = d.byteValue("len");
                                        d.rawValue(len >> 1, "extra data c");
                                }
                                else if(extraFormat == 0x0d) {
                                        int len = d.byteValue("len");
                                        d.rawValue(len >> 1, "extra data da");
                                        len = d.byteValue("len");
                                        d.rawValue(len >> 1, "extra data db");
                                }
                                else if(extraFormat == 0x0e) {
                                        int len = d.byteValue("len");
                                        d.rawValue(len >> 1, "extra data ea");
                                        len = d.byteValue("len");
                                        d.rawValue(len >> 1, "extra data eb");
                                }
                                else if(extraFormat == 0x0f) {
                                        int len = d.byteValue("len");
                                        d.rawValue(len >> 1, "extra data fa");
                                        len = d.byteValue("len");
                                        d.rawValue(len >> 1, "extra data fb");
                                        len = d.byteValue("len");
                                        d.rawValue(len >> 1, "extra data fc");
                                }
                                else
                                        d.item().addText("Unknown format");
                        }

                        d.gap();
//                      d.print(outStream);
                }

                d.item().addText("Number of records %d", nrecords);
                d.print(outStream);
        }
        
        private String bitStreamAsString(byte[] bs, int nbits) {
                long l = 0;
                for (int i = 0; i < (nbits+7)/8; i++) {
                        byte b = bs[i];
                        l |= (b & 0xff) << (i * 8);
                }
                String s = Long.toBinaryString(l);
                if (s.length() < nbits) {
                        StringBuilder sb = new StringBuilder(s);
                        for (int i = s.length(); i < nbits; i++)
                                sb.insert(0, '0');
                        return sb.toString();
                }
                return s;
        }

        int getNextKnownOffset(int offset, long end){
                for (int i = offset + 1; i < end-nodesStart; i++){
                        Offset testOff = nod1recs.get(i);
                        if (testOff != null){
                                System.err.println("next known offset is at " + 
i + " (" + (nodesStart + i + 1) + ")");
                                reader.position(testOff.getOffset() + 
nodesStart);
                                return testOff.getOffset();
                        }
                }
                return -1;
        }
        /**
         * This is a set of fixed length records, so is a good one to start 
with.
         */
        private void readBoundryNodes() {
                reader.position(boundriesStart);
                for (int pos = boundriesStart; pos < boundriesStart + 
boundriesLen; pos += boundriesRecsize) {
                        //latLongField(d, "longitude");
                        //latLongField(d, "latitude");
                        reader.get(6);
                        
                        // limited range
                        int sectoff = reader.getu3();
                        Offset offset = nod1recs.get(sectoff);
                        if (offset != null) {
                                offset.appendOrigin("NOD 3");
                        } else {
                                Offset offval = new Offset(sectoff, "NOD 3");
                                nod1recs.put(sectoff, offval);
                        }
                        //d.int3Value("offset into NOD 1 %06x");

                        // We believe that this is an offset into unk1 too
//                      nodeOffsets.add(new Offset(sectoff, "NOD 3 chunk3"));
                }
        }

        private void printHeader() {
                Displayer d = new Displayer(reader);
                d.setTitle("NOD header");

                nodesStart = d.intValue("NOD 1 (nodes) at offset %#08x");
                nodesLen = d.intValue("NOD 1 length %d");
                d.item().addText("End of section %08x, len %#08x", nodesStart + 
nodesLen, nodesLen);

                int flags = d.charValue("flags"); // usually 0x0025 or 0x0027
                if ((flags & 0x02) != 0)
                        d.item().addText("have restrictions");
                d.charValue("???");
                //d.charValue("???");
                align = d.byteValue("node align");
                aMask = (1<<align) - 1;
                d.byteValue("???");
                d.charValue("???");

                roadDataStart = d.intValue("NOD 2 (road data) at offset %#08x");
                roadDataLen = d.intValue("NOD 2 length %d");
                d.item().addText("End of section %08x, len %#08x", 
roadDataStart + roadDataLen, roadDataLen);

                d.intValue("???");

                boundriesStart = d.intValue("NOD 3 (boundry nodes) at offset 
%#08x");
                boundriesLen = d.intValue("NOD 3 length %d");
                boundriesRecsize = d.byteValue("NOD 3 record size %d");
                d.item().addText("End of section %08x, len %#08x", 
boundriesStart + boundriesLen, boundriesLen)
                                .addText("Number of records %d", boundriesLen / 
boundriesRecsize);

                d.print(outStream);
        }

        private void readNetHeader() {
                Displayer d = new Displayer(reader);
                readSection(d, "road defs", 1, false, false);
                reader.get();

                readSection(d, "segmented roads", 2, false, false);
                reader.get();

                readSection(d, "road index", 3, true, false);
        }

        public static void main(String[] args) {
                if (args.length < 1) {
                        System.err.println("Usage: noddisplay <filename>");
                        System.exit(1);
                }

                String name = args[0];

                NodConvert nd = new NodConvert();
                nd.setOutStream(System.err);
                nd.display(name, "NOD");
        }
}
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to