Subversion Repositories mkgmap

Rev

Rev 1650 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2008
 *
 *  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.
 *
 * Create date: 07-Jul-2008
 */

package uk.me.parabola.imgfmt.app.net;

import uk.me.parabola.imgfmt.app.ImgFileWriter;

/**
 * A restriction in the routing graph.
 *
 * There may eventually be several types of these at which point
 * we might consider splitting them into several classes. For the
 * moment, just simple from-to-via restrictions.
 *
 * A from-to-via restriction says you can't go along arc "to"
 * if you came to node to.getSource() == from.getSource()
 * via the inverse arc of "from". We're using the inverse of
 * "from" since that has the information we need for writing
 * the Table C entry.
 *
 * @author Robert Vollmert
 */

public class RouteRestriction {
        //private static final Logger log = Logger.getLogger(RouteRestriction.class);

        // size in bytes
        private static final int SIZE = 11;

        // first three bytes of the header -- might specify the type of restriction
        // and when it is active
        private static final int HEADER = 0x004005;

        // To specify that a node is given by a relative offset instead
        // of an entry to Table B.
        private static final int F_INTERNAL = 0x8000;

        // the arcs
        private final RouteArc from;
        private final RouteArc to;

        // offset in Table C
        private byte offsetSize;
        private int offsetC;

        // last restriction in a node
        private boolean last;

        // mask that specifies which vehicle types the restriction doesn't apply to
        private final byte exceptMask;

        public final static byte EXCEPT_CAR      = 0x01;
        public final static byte EXCEPT_BUS      = 0x02;
        public final static byte EXCEPT_TAXI     = 0x04;
        public final static byte EXCEPT_DELIVERY = 0x10;
        public final static byte EXCEPT_BICYCLE  = 0x20;
        public final static byte EXCEPT_TRUCK    = 0x40;

        /**
         * Create a route restriction.
         *
         * @param from The inverse arc of "from" arc.
         * @param to The "to" arc.
         */

        public RouteRestriction(RouteArc from, RouteArc to, byte exceptMask) {
                assert from.getSource().equals(to.getSource()) : "arcs in restriction don't meet";
                this.from = from;
                this.to = to;
                this.exceptMask = exceptMask;
        }

        private int calcOffset(RouteNode node, int tableOffset) {
                int offset = tableOffset - node.getOffsetNod1();
                assert offset >= 0 : "node behind start of tables";
                assert offset < 0x8000 : "node offset too large";
                return offset | F_INTERNAL;
        }

        /**
         * Writes a Table C entry.
         *
         * @param writer The writer.
         * @param tableOffset The offset in NOD 1 of the tables area.
         */

        public void write(ImgFileWriter writer, int tableOffset) {
                int header = HEADER;

                if(exceptMask != 0)
                        header |= 0x0800;

                writer.put3(header);

                if(exceptMask != 0)
                        writer.put(exceptMask);

                int[] offsets = new int[3];

                if (from.isInternal())
                        offsets[0] = calcOffset(from.getDest(), tableOffset);
                else
                        offsets[0] = from.getIndexB();
                offsets[1] = calcOffset(to.getSource(), tableOffset);
                if (to.isInternal())
                        offsets[2] = calcOffset(to.getDest(), tableOffset);
                else
                        offsets[2] = to.getIndexB();

                for (int offset : offsets)
                        writer.putChar((char) offset);

                writer.put(from.getIndexA());
                writer.put(to.getIndexA());
        }

        /**
         * Write this restriction's offset within Table C into a node record.
         */

        public void writeOffset(ImgFileWriter writer) {
                assert 0 < offsetSize && offsetSize <= 2 : "illegal offset size";
                int offset = offsetC;
                if (offsetSize == 1) {
                        assert offset < 0x80;
                        if (last)
                                offset |= 0x80;
                        writer.put((byte) offset);
                } else {
                        assert offset < 0x8000;
                        if (last)
                                offset |= 0x8000;
                        writer.putChar((char) offset);
                }
        }

        /**
         * Size in bytes of the Table C entry.
         */

        public int getSize() {
                int size = SIZE;
                if(exceptMask != 0)
                        ++size;
                return size;
        }

        public void setOffsetC(int offsetC) {
                this.offsetC = offsetC;
        }

        public int getOffsetC() {
                return offsetC;
        }

        public void setOffsetSize(byte size) {
                offsetSize = size;
        }

        public void setLast() {
                last = true;
        }
}