Search in sources :

Example 61 with Coord

use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.

the class Way method toString.

/**
 * A simple representation of this way.
 * @return A string with the name and start point
 */
public String toString() {
    if (points.isEmpty())
        return "Way: empty";
    Coord coord = points.get(0);
    StringBuilder sb = new StringBuilder();
    sb.append("WAY: ").append(getId()).append(" ");
    sb.append(getName());
    sb.append('(');
    sb.append(Utils.toDegrees(coord.getLatitude()));
    sb.append('/');
    sb.append(Utils.toDegrees(coord.getLongitude()));
    sb.append(')');
    sb.append(' ');
    sb.append(toTagString());
    return sb.toString();
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord)

Example 62 with Coord

use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.

the class LinePreparer method calcDeltas.

/**
 * Calculate the deltas of one point to the other.  While we are doing
 * this we must save more information about the maximum sizes, if they
 * are all the same sign etc.  This must be done separately for both
 * the lat and long values.
 */
private void calcDeltas() {
    Subdivision subdiv = polyline.getSubdiv();
    if (log.isDebugEnabled())
        log.debug("label offset", polyline.getLabel().getOffset());
    List<Coord> points = polyline.getPoints();
    // Space to hold the deltas
    int numPointsToUse = points.size();
    if (polyline instanceof Polygon) {
        if (points.get(0).equals(points.get(points.size() - 1)))
            // no need to write the closing point
            --numPointsToUse;
    }
    deltas = new int[2 * (numPointsToUse - 1)];
    if (extraBit)
        nodes = new boolean[numPointsToUse];
    boolean first = true;
    // OK go through the points
    int lastLat = 0;
    int lastLong = 0;
    int minDx = Integer.MAX_VALUE, maxDx = 0;
    int minDy = Integer.MAX_VALUE, maxDy = 0;
    // index of first point in a series of identical coords (after shift)
    int firstsame = 0;
    for (int i = 0; i < numPointsToUse; i++) {
        Coord co = points.get(i);
        int lat = subdiv.roundLatToLocalShifted(co.getLatitude());
        int lon = subdiv.roundLonToLocalShifted(co.getLongitude());
        if (log.isDebugEnabled())
            log.debug("shifted pos", lat, lon);
        if (first) {
            lastLat = lat;
            lastLong = lon;
            first = false;
            continue;
        }
        int dx = lon - lastLong;
        int dy = lat - lastLat;
        lastLong = lon;
        lastLat = lat;
        boolean isSpecialNode = false;
        if (co.getId() > 0 || (co.isNumberNode() && ignoreNumberOnlyNodes == false))
            isSpecialNode = true;
        if (dx != 0 || dy != 0 || extraBit && isSpecialNode)
            firstsame = i;
        /*
			 * Current thought is that the node indicator is set when
			 * the point is a routing node or a house number node. 
			 * There's a separate first extra bit
			 * that always appears to be false. The last points' extra bit
			 * is set if the point is a node and this is not the last
			 * polyline making up the road.
			 */
        if (extraBit) {
            boolean extra = false;
            if (isSpecialNode) {
                if (i < nodes.length - 1)
                    // inner node of polyline
                    extra = true;
                else
                    // end node of polyline: set if inner
                    // node of road
                    extra = !polyline.isLastSegment();
            }
            /*
				 * Only the first among a range of equal points
				 * is written, so set the bit if any of the points
				 * is a node.
				 * Since we only write extra bits at level 0 now,
				 * this can only happen when points in the input
				 * data round to the same point in map units, so
				 * it may be better to handle this in the
				 * reader.
				 */
            nodes[firstsame] = nodes[firstsame] || extra;
        }
        // find largest delta values
        if (dx < minDx)
            minDx = dx;
        if (dx > maxDx)
            maxDx = dx;
        if (dy < minDy)
            minDy = dy;
        if (dy > maxDy)
            maxDy = dy;
        // Save the deltas
        deltas[2 * (i - 1)] = dx;
        deltas[2 * (i - 1) + 1] = dy;
    }
    // Find the maximum number of bits required to hold the delta values.
    int xBits = Math.max(bitsNeeded(minDx), bitsNeeded(maxDx));
    int yBits = Math.max(bitsNeeded(minDy), bitsNeeded(maxDy));
    if (log.isDebugEnabled())
        log.debug("initial xBits, yBits", xBits, yBits);
    this.xBase = bits2Base(xBits);
    this.yBase = bits2Base(yBits);
    if (log.isDebugEnabled())
        log.debug("initial xBase, yBase", xBase, yBase);
    // Set flags for same sign etc.
    this.xSameSign = !(minDx < 0 && maxDx > 0);
    this.ySameSign = !(minDy < 0 && maxDy > 0);
    if (this.xSameSign)
        this.xSignNegative = minDx < 0;
    if (this.ySameSign)
        this.ySignNegative = minDy < 0;
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord)

Example 63 with Coord

use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.

the class RoadNetwork method addRoad.

public void addRoad(RoadDef roadDef, List<Coord> coordList) {
    roadDefs.add(roadDef);
    CoordNode lastCoord = null;
    int lastIndex = 0;
    double roadLength = 0;
    double arcLength = 0;
    int pointsHash = 0;
    int npoints = coordList.size();
    int numCoordNodes = 0;
    boolean hasInternalNodes = false;
    int numNumberNodes = 0;
    BitSet nodeFlags = new BitSet();
    for (int index = 0; index < npoints; index++) {
        Coord co = coordList.get(index);
        int id = co.getId();
        if (id != 0) {
            nodeFlags.set(numNumberNodes);
            ++numCoordNodes;
            if (index > 0 && index < npoints - 1)
                hasInternalNodes = true;
        }
        if (co.isNumberNode())
            ++numNumberNodes;
        if (index == 0) {
            if (id == 0)
                roadDef.setStartsWithNode(false);
        } else {
            double d = co.distance(coordList.get(index - 1));
            arcLength += d;
            roadLength += d;
        }
        if (roadDef.skipAddToNOD())
            continue;
        pointsHash += co.hashCode();
        if (id == 0)
            // not a routing node
            continue;
        // the previous node to this one (and back again).
        if (lastCoord != null) {
            int lastId = lastCoord.getId();
            if (log.isDebugEnabled()) {
                log.debug("lastId = " + lastId + " curId = " + id);
                log.debug("from " + lastCoord.toDegreeString() + " to " + co.toDegreeString());
                log.debug("arclength=" + arcLength + " roadlength=" + roadLength);
            }
            RouteNode node1 = getOrAddNode(lastId, lastCoord);
            RouteNode node2 = getOrAddNode(id, co);
            if (node1 == node2)
                log.error("Road " + roadDef + " contains consecutive identical nodes at " + co.toOSMURL() + " - routing will be broken");
            else if (arcLength == 0)
                log.warn("Road " + roadDef + " contains zero length arc at " + co.toOSMURL());
            Coord forwardBearingPoint = coordList.get(lastIndex + 1);
            if (lastCoord.equals(forwardBearingPoint) || forwardBearingPoint.isAddedNumberNode()) {
                // useful - try some more points
                for (int bi = lastIndex + 2; bi <= index; ++bi) {
                    Coord coTest = coordList.get(bi);
                    if (coTest.isAddedNumberNode() || lastCoord.equals(coTest))
                        continue;
                    forwardBearingPoint = coTest;
                    break;
                }
            }
            Coord reverseBearingPoint = coordList.get(index - 1);
            if (co.equals(reverseBearingPoint) || reverseBearingPoint.isAddedNumberNode()) {
                // useful - try some more points
                for (int bi = index - 2; bi >= lastIndex; --bi) {
                    Coord coTest = coordList.get(bi);
                    if (coTest.isAddedNumberNode() || co.equals(coTest))
                        continue;
                    reverseBearingPoint = coTest;
                    break;
                }
            }
            double forwardInitialBearing = lastCoord.bearingTo(forwardBearingPoint);
            double forwardDirectBearing = (co == forwardBearingPoint) ? forwardInitialBearing : lastCoord.bearingTo(co);
            double reverseInitialBearing = co.bearingTo(reverseBearingPoint);
            double directLength = (lastIndex + 1 == index) ? arcLength : lastCoord.distance(co);
            double reverseDirectBearing = 0;
            if (directLength > 0) {
                // bearing on rhumb line is a constant, so we can simply revert
                reverseDirectBearing = (forwardDirectBearing <= 0) ? 180 + forwardDirectBearing : -(180 - forwardDirectBearing) % 180.0;
            }
            // Create forward arc from node1 to node2
            RouteArc arc = new RouteArc(roadDef, node1, node2, forwardInitialBearing, forwardDirectBearing, arcLength, arcLength, directLength, pointsHash);
            arc.setForward();
            node1.addArc(arc);
            // Create the reverse arc
            RouteArc reverseArc = new RouteArc(roadDef, node2, node1, reverseInitialBearing, reverseDirectBearing, arcLength, arcLength, directLength, pointsHash);
            node2.addArc(reverseArc);
            // link the two arcs
            arc.setReverseArc(reverseArc);
            reverseArc.setReverseArc(arc);
        } else {
            // This is the first node in the road
            roadDef.setNode(getOrAddNode(id, co));
        }
        lastCoord = (CoordNode) co;
        lastIndex = index;
        arcLength = 0;
        pointsHash = co.hashCode();
    }
    if (roadDef.hasHouseNumbers()) {
        // we ignore number nodes when we have no house numbers
        if (numCoordNodes < numNumberNodes)
            hasInternalNodes = true;
        roadDef.setNumNodes(numNumberNodes);
        roadDef.setNod2BitSet(nodeFlags);
    } else {
        roadDef.setNumNodes(numCoordNodes);
    }
    if (hasInternalNodes)
        roadDef.setInternalNodes(true);
    roadDef.setLength(roadLength);
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) BitSet(java.util.BitSet) CoordNode(uk.me.parabola.imgfmt.app.CoordNode)

Example 64 with Coord

use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.

the class RouteNode method checkRoundabouts.

public void checkRoundabouts() {
    List<RouteArc> roundaboutArcs = new ArrayList<>();
    List<RouteArc> nonRoundaboutArcs = new ArrayList<>();
    int countNonRoundaboutRoads = 0;
    int countNonRoundaboutOtherHighways = 0;
    int countHighwaysInsideRoundabout = 0;
    for (RouteArc ra : arcs) {
        if (ra.isDirect()) {
            // ignore ways that have been synthesised by mkgmap
            RoadDef rd = ra.getRoadDef();
            if (!rd.isSynthesised()) {
                if (rd.isRoundabout())
                    roundaboutArcs.add(ra);
                else
                    nonRoundaboutArcs.add(ra);
            }
        }
    }
    if (roundaboutArcs.size() > 0) {
        // get the coordinates of a box bounding the junctions of the roundabout
        int minRoundaboutLat = coord.getHighPrecLat();
        int maxRoundaboutLat = minRoundaboutLat;
        int minRoundaboutLon = coord.getHighPrecLon();
        int maxRoundaboutLon = minRoundaboutLon;
        List<RouteNode> processedNodes = new ArrayList<>();
        processedNodes.add(this);
        for (RouteArc ra : roundaboutArcs) {
            if (ra.isForward()) {
                for (RouteArc ra1 : nonRoundaboutArcs) {
                    if ((ra1.getDirectHeading() == ra.getDirectHeading()) && (ra1.getInitialHeading() == ra.getInitialHeading()) && (ra1.getFinalHeading() == ra.getFinalHeading()) && (ra1.getLengthInMeter() == ra.getLengthInMeter())) {
                        // non roundabout highway overlaps roundabout
                        nonRoundaboutArcs.remove(ra1);
                        if (!ra.getRoadDef().messagePreviouslyIssued("roundabout forks/overlaps"))
                            log.warn("Highway", ra1.getRoadDef(), "overlaps roundabout", ra.getRoadDef(), "at", coord.toOSMURL());
                        break;
                    }
                }
                RouteNode rn = ra.getDest();
                while (rn != null && !processedNodes.contains(rn)) {
                    processedNodes.add(rn);
                    int lat = rn.coord.getHighPrecLat();
                    int lon = rn.coord.getHighPrecLon();
                    minRoundaboutLat = Math.min(minRoundaboutLat, lat);
                    maxRoundaboutLat = Math.max(maxRoundaboutLat, lat);
                    minRoundaboutLon = Math.min(minRoundaboutLon, lon);
                    maxRoundaboutLon = Math.max(maxRoundaboutLon, lon);
                    RouteNode nrn = null;
                    for (RouteArc nra : rn.arcs) {
                        if (nra.isDirect() && nra.isForward()) {
                            RoadDef nrd = nra.getRoadDef();
                            if (nrd.isRoundabout() && !nrd.isSynthesised())
                                nrn = nra.getDest();
                        }
                    }
                    rn = nrn;
                }
            }
        }
        if (nonRoundaboutArcs.size() > 1) {
            // get an approximate centre of the roundabout
            Coord roundaboutCentre = Coord.makeHighPrecCoord((minRoundaboutLat + maxRoundaboutLat) / 2, (minRoundaboutLon + maxRoundaboutLon) / 2);
            for (RouteArc ra : nonRoundaboutArcs) {
                double distanceToCentre = roundaboutCentre.distance(coord);
                RoadDef rd = ra.getRoadDef();
                // ignore footpaths and ways with no access
                byte access = rd.getAccess();
                if (access != 0 && (access != AccessTagsAndBits.FOOT)) {
                    // check whether the way is inside the roundabout by seeing if the next point is nearer to the centre of the bounding box than this
                    RouteNode nextNode = ra.getSource().coord == coord ? ra.getDest() : ra.getSource();
                    Coord nextCoord = nextNode.coord;
                    for (RouteNode roundaboutNode : processedNodes) {
                        if (roundaboutNode.coord.equals(nextCoord)) {
                            // arc rejoins roundabout, so calculate another point to use half the distance away at the initial bearing
                            double heading1 = ra.getSource().coord == coord ? ra.getInitialHeading() : 180 + ra.getFinalHeading();
                            double distance = coord.distance(nextCoord) / 2;
                            Coord nextCoord1 = coord.offset(heading1, distance);
                            // now calculate a point the same distance away from the end point 180 degrees from the final bearing
                            double heading2 = ra.getSource().coord == coord ? 180 + ra.getFinalHeading() : ra.getInitialHeading();
                            Coord nextCoord2 = nextCoord.offset(heading2, distance);
                            double distanceToCentreOfNextCoord = roundaboutCentre.distance(nextCoord);
                            // use the point which has a bigger difference in distance from the centre to increase accuracy
                            if (Math.abs(distanceToCentre - roundaboutCentre.distance(nextCoord1)) >= Math.abs(distanceToCentreOfNextCoord - roundaboutCentre.distance(nextCoord2)))
                                nextCoord = nextCoord1;
                            else {
                                distanceToCentre = distanceToCentreOfNextCoord;
                                nextCoord = nextCoord2;
                            }
                            break;
                        }
                    }
                    double nextDistanceToCentre = roundaboutCentre.distance(nextCoord);
                    if (Math.abs(nextDistanceToCentre - distanceToCentre) < 2)
                        log.info("Way", rd, "unable to accurately determine whether", nextCoord.toOSMURL(), " is inside roundabout");
                    if (nextDistanceToCentre < distanceToCentre)
                        countHighwaysInsideRoundabout++;
                    else {
                        if ((access & AccessTagsAndBits.CAR) != 0)
                            countNonRoundaboutRoads++;
                        else if ((access & (AccessTagsAndBits.BIKE | AccessTagsAndBits.BUS | AccessTagsAndBits.TAXI | AccessTagsAndBits.TRUCK)) != 0)
                            countNonRoundaboutOtherHighways++;
                    }
                }
            }
            RouteArc roundaboutArc = roundaboutArcs.get(0);
            if (arcs.size() > 1 && roundaboutArcs.size() == 1)
                log.warn("Roundabout", roundaboutArc.getRoadDef(), roundaboutArc.isForward() ? "starts at" : "ends at", coord.toOSMURL());
            if (countNonRoundaboutRoads > 1)
                log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to more than one road at", coord.toOSMURL());
            else if (countNonRoundaboutRoads == 1) {
                if (countNonRoundaboutOtherHighways > 0) {
                    if (countHighwaysInsideRoundabout > 0)
                        log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to a road", countNonRoundaboutOtherHighways, "other highway(s) and", countHighwaysInsideRoundabout, "highways inside the roundabout at", coord.toOSMURL());
                    else
                        log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to a road and", countNonRoundaboutOtherHighways, "other highway(s) at", coord.toOSMURL());
                } else if (countHighwaysInsideRoundabout > 0)
                    log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to a road and", countHighwaysInsideRoundabout, "highway(s) inside the roundabout at", coord.toOSMURL());
            } else if (countNonRoundaboutOtherHighways > 0) {
                if (countHighwaysInsideRoundabout > 0)
                    log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to", countNonRoundaboutOtherHighways, "highway(s) and", countHighwaysInsideRoundabout, "inside the roundabout at", coord.toOSMURL());
                else if (countNonRoundaboutOtherHighways > 1)
                    log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to", countNonRoundaboutOtherHighways, "highways at", coord.toOSMURL());
            } else if (countHighwaysInsideRoundabout > 1)
                log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to", countHighwaysInsideRoundabout, "highways inside the roundabout at", coord.toOSMURL());
            if (roundaboutArcs.size() > 2) {
                for (RouteArc fa : roundaboutArcs) {
                    if (fa.isForward()) {
                        RoadDef rd = fa.getRoadDef();
                        for (RouteArc fb : roundaboutArcs) {
                            if (fb != fa) {
                                if (fa.getPointsHash() == fb.getPointsHash() && ((fb.isForward() && fb.getDest() == fa.getDest()) || (!fb.isForward() && fb.getSource() == fa.getDest()))) {
                                    if (!rd.messagePreviouslyIssued("roundabout forks/overlaps")) {
                                        log.warn("Roundabout " + rd + " overlaps " + fb.getRoadDef() + " at " + coord.toOSMURL());
                                    }
                                } else if (fb.isForward()) {
                                    if (!rd.messagePreviouslyIssued("roundabout forks/overlaps")) {
                                        log.warn("Roundabout " + rd + " forks at " + coord.toOSMURL());
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) IntArrayList(it.unimi.dsi.fastutil.ints.IntArrayList) ArrayList(java.util.ArrayList)

Example 65 with Coord

use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.

the class Point method getLocation.

public Coord getLocation() {
    int shift = getSubdiv().getShift();
    Coord co = new Coord(getSubdiv().getLatitude() + (getDeltaLat() << shift), getSubdiv().getLongitude() + (getDeltaLong() << shift));
    return co;
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord)

Aggregations

Coord (uk.me.parabola.imgfmt.app.Coord)178 ArrayList (java.util.ArrayList)71 Way (uk.me.parabola.mkgmap.reader.osm.Way)31 MapPoint (uk.me.parabola.mkgmap.general.MapPoint)27 List (java.util.List)23 MapLine (uk.me.parabola.mkgmap.general.MapLine)16 Area (uk.me.parabola.imgfmt.app.Area)15 MapShape (uk.me.parabola.mkgmap.general.MapShape)15 CoordNode (uk.me.parabola.imgfmt.app.CoordNode)13 MapExitPoint (uk.me.parabola.mkgmap.general.MapExitPoint)13 Node (uk.me.parabola.mkgmap.reader.osm.Node)13 HashMap (java.util.HashMap)12 IdentityHashMap (java.util.IdentityHashMap)11 Test (org.junit.Test)11 MapRoad (uk.me.parabola.mkgmap.general.MapRoad)9 Long2ObjectOpenHashMap (it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap)8 Area (java.awt.geom.Area)8 HashSet (java.util.HashSet)8 IntArrayList (it.unimi.dsi.fastutil.ints.IntArrayList)5 LinkedHashMap (java.util.LinkedHashMap)5