Subversion Repositories display

Rev

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

/*
 * Copyright (C) 2014 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 3 or
 * 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.
 */

package test.files;

import test.display.check.Log;
import uk.me.parabola.imgfmt.app.Coord;

import static test.util.ArcFlags.*;

/**
 * An arc in the routing network.
 *
 * @author Steve Ratcliffe
 */

public class RouteArc {
        private int offset;  // Offset in the file section

        private final RouteNode node; // The associated start node.
    private int alt6;

    private boolean longLink;
    private int link;
    private boolean bad;
    private int direction;
    private int index;
    private int distance;
    private boolean hasDirection;
    private boolean last;
    private int localNet;

        // This is the extra distance from the last arc
        private int partialDistance;
        private int curveA;
        private int curveB;
        private RouteCenter.TableA tableA;
        private RoadData road;
        private RouteNode targetNode;
        private boolean hasCurve;

        public RouteArc(RouteNode node) {
        this.node = node;
    }

    public void setAlt6(int alt6) {
        this.alt6 = alt6;
    }

    public boolean newNet() {
        return (alt6 & ARC_HASNET) == 0x80;
    }

    public boolean isSign() {
        return (alt6 & ARC_SIGN) != 0;
    }
    public boolean hasCurve() {
        return hasCurve;
    }
    public int getAlt6Len() {
        return alt6 & ARC_LEN;
    }

    public int getDestclass() {
        return alt6 & ARC_CLASSMASK;
    }

    public String alt6String() {
        StringBuilder sb = new StringBuilder();
            if (newNet())
                    sb.append("new,");
            else
                    sb.append("cont,");
        if (isSign())
            sb.append("sign,");
            if (hasCurve())
                    sb.append("curve,");
        sb.append(String.format("l%x,", getAlt6Len()));
        sb.append("dst=");
        sb.append(getDestclass());

        return sb.toString();
    }

    public void setLongLink(boolean longLink) {
        this.longLink = longLink;
    }

    public boolean isLongLink() {
        return longLink;
    }

    public void setLink(int link) {
        this.link = link;
    }

    public int getLink() {
        return link;
    }

    public void setBad(boolean bad) {
        this.bad = bad;
    }

    public boolean isBad() {
        return bad;
    }

        /**
         * The initial bearing in file format.
         * @return An byte sized representation of the bearing. 256 is 360 degrees.
         */

    public int getDirection() {
        return direction;
    }

    public void setDirection(int direction) {
        hasDirection = true;
        this.direction = direction & 0xff;
    }

        /**
         * @return The initial bearing converted to degrees.
         * Can return null if there was no direction or it wasn't found. I don't think that this
         * can happen any more, since we should always read one now even if it is wrong.
         */

    public Double getInitialDegrees() {
        if (!hasDirection())
            return null;

        return directionToDegrees(direction);
    }

        /**
         * Convert from the integer based direction to value in degrees.
         *
         * Note that if the bearing is stored as a 4-bit number then this is shifted up to the
         * top bits so that they are easily comparable with the 8-bit bearings.
         *
         * @param raw The value from the file.
         * @return Bearing in degrees.
         */

        public static double directionToDegrees(int raw) {
                double dir = (raw * 360) / 256;
                if (dir > 180)
                        dir -= 360;
                return dir;
        }

        public static int directionFromDegrees(double dir) {
                return (int) Math.round(dir * 256.0 / 360) & 0xff;
        }

        public RouteNode getNode() {
        return node;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public int getIndex() {
        return index;
    }

    public void setDistance(int distance) {
        this.distance = distance;
    }

    /**
     * @return The length in file units.
     */

    public int getDistance() {
        return distance;
    }

        public boolean hasDirection() {
        return hasDirection;
    }

    public void setOffset(long offset) {
        this.offset = (int) offset;
    }

    public long getOffset() {
        return offset;
    }

        public Double getActualInitialBearing() {
                Coord co1 = node.getCoord();

                CoordLocator loc = road.locateNode(node);
        if (loc == null) return null;

                loc = road.nextCoord(loc, isSign());
                Coord co2 = loc.getCoord();

                if (co1.distance(co2) < Math.min(10, co1.distance(targetNode.getCoord())/50) + 11
                                && targetNode.getCoord().distance(co2) > 20) {
                        // We need the initial bearing of the road. However this may not be very
                        // well represented in the file.
                        //
                        // If the first segment is long, then the initial bearing will lie along that
                        // segment.  If however it is a very short segment, then it may well not be. In
                        // this case we look at the next segment and use that as a perhaps better approximation.
                        // An even better approximation might be to work out the bearing at about 30-40m
                        // along the road.
                        //
                        // If the first coord is near the target already then use it.
                        loc = road.nextCoord(loc, isSign());
                        if (loc != null)
                                co2 = loc.getCoord();
                }

                return co1.bearingTo(co2);
        }

    public void setLast(boolean last) {
        this.last = last;
    }

    public boolean isLast() {
        return last;
    }

    public void setLocalNet(int localNet) {
        this.localNet = localNet;
    }

    public int getLocalNet() {
        return localNet;
    }

        public void setTableA(RouteCenter.TableA tableA) {
                this.tableA = tableA;
        }

        public Integer getNetOffset() {
                return tableA.getNetOffset();
        }

        public int getRoadClass() {
                return tableA.getRoadClass();
        }

    public int getSpeed() {
        return tableA.getSpeed();
    }

        public int getAccess() {
                return tableA.getAccess();
        }

        public boolean isOneway() {
                return tableA.isOneway();
        }

        public void setPartialDistance(int partialDistance) {
                this.partialDistance = partialDistance;
        }

        public int getPartialDistance() {
                return partialDistance;
        }

        public void setCurveA(int curveA) {
                this.curveA = curveA;
                hasCurve = true;
        }

        public int getCurveA() {
                return curveA;
        }

        public void setCurveB(int curveB) {
                this.curveB = curveB;
        }

        public int getCurveB() {
                return curveB;
        }

        public int getCurveDirection() {
                if ((curveA & 0xe0) == 0)
                        return curveB;
                else
                        return (curveA & 0x1f) << 3;
        }

        public void setRoad(RoadData road) {
                this.road = road;
        }

        public RoadData getRoad() {
                return road;
        }

        public void setTargetNode(RouteNode targetNode) {
                this.targetNode = targetNode;
        }

        public RouteNode getTargetNode() {
                return targetNode;
        }
}