Search in sources :

Example 6 with CoordNode

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

the class PredictFilterPoints method predictedMaxNumPoints.

public static int predictedMaxNumPoints(List<Coord> points, int resolution, boolean checkPreserved) {
    // see RemoveObsoletePointsFilter, RoundCoordsFilter, ... for comments on preserved and resolution
    // %%% checkPreserved = config.getLevel() == 0 && config.isRoutable() && line.isRoad()){
    // final int shift = 30 - resolution; // NB getting highPrec
    // final int half = 1 << (shift - 1); // 0.5 shifted
    // final int mask = ~((1 << shift) - 1); // to remove fraction bits
    // best use same info as filters
    final int shift = 24 - resolution;
    int half;
    int mask;
    if (shift == 0) {
        half = 0;
        mask = ~0;
    } else {
        // 0.5 shifted
        half = 1 << (shift - 1);
        // to remove fraction bits
        mask = ~((1 << shift) - 1);
    }
    int numPoints = 0;
    int lastLat = 0, lastLon = 0;
    for (Coord p : points) {
        // final int lat = (p.getHighPrecLat() + half) & mask;
        // final int lon = (p.getHighPrecLon() + half) & mask;
        final int lat = (p.getLatitude() + half) & mask;
        final int lon = (p.getLongitude() + half) & mask;
        if (numPoints == 0)
            // always have one/first point
            numPoints = 1;
        else {
            if (lat != lastLat || lon != lastLon || (checkPreserved && (p instanceof CoordNode || p.preserved())))
                ++numPoints;
        }
        lastLat = lat;
        lastLon = lon;
    }
    // true shapes will have >3 points, lines >1
    return numPoints;
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) CoordNode(uk.me.parabola.imgfmt.app.CoordNode)

Example 7 with CoordNode

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

the class StyledConverter method end.

public void end() {
    pointMap.clear();
    style.reportStats();
    driveOnLeft = calcDrivingSide();
    setHighwayCounts();
    findUnconnectedRoads();
    rotateClosedWaysToFirstNode();
    filterCoordPOI();
    WrongAngleFixer wrongAngleFixer = new WrongAngleFixer(bbox);
    wrongAngleFixer.optimizeWays(roads, lines, modifiedRoads, deletedRoads, restrictions);
    // make sure that copies of modified roads have equal points
    for (ConvertedWay line : lines) {
        if (!line.isValid())
            continue;
        Way way = line.getWay();
        if (deletedRoads.contains(way.getId())) {
            line.getPoints().clear();
            continue;
        }
        if (!line.isOverlay())
            continue;
        ConvertedWay modWay = modifiedRoads.get(way.getId());
        if (modWay != null) {
            List<Coord> points = line.getPoints();
            points.clear();
            points.addAll(modWay.getPoints());
            if (modWay.isReversed() != line.isReversed())
                Collections.reverse(points);
        }
    }
    for (Long wayId : deletedRoads) {
        if (wayRelMap.containsKey(wayId)) {
            // may happen e.g. when very short way is leading to nowhere
            log.warn("Way that is used in valid restriction relation was removed, id:", wayId);
        }
    }
    deletedRoads = null;
    modifiedRoads = null;
    mergeRoads();
    resetHighwayCounts();
    setHighwayCounts();
    for (ConvertedWay cw : lines) {
        if (cw.isValid())
            addLine(cw.getWay(), cw.getGType());
    }
    lines = null;
    if (roadLog.isInfoEnabled()) {
        roadLog.info("Flags: oneway,no-emergency, no-delivery, no-throughroute, no-truck, no-bike, no-foot, carpool, no-taxi, no-bus, no-car");
        roadLog.info(String.format("%19s %4s %11s %6s %6s %6s %s", "Road-OSM-Id", "Type", "Flags", "Class", "Speed", "Points", "Labels"));
    }
    // add the roads after the other lines
    for (ConvertedWay cw : roads) {
        if (cw.isValid())
            addRoad(cw);
    }
    housenumberGenerator.generate(lineAdder, nextNodeId);
    housenumberGenerator = null;
    if (routable)
        createRouteRestrictionsFromPOI();
    poiRestrictions = null;
    if (routable) {
        for (RestrictionRelation rr : restrictions) {
            rr.addRestriction(collector, nodeIdMap);
        }
    }
    roads = null;
    if (routable) {
        for (Relation relation : throughRouteRelations) {
            Node node = null;
            Way w1 = null;
            Way w2 = null;
            for (Map.Entry<String, Element> member : relation.getElements()) {
                if (member.getValue() instanceof Node) {
                    if (node == null)
                        node = (Node) member.getValue();
                    else
                        log.warn("Through route relation", relation.toBrowseURL(), "has more than 1 node");
                } else if (member.getValue() instanceof Way) {
                    Way w = (Way) member.getValue();
                    if (w1 == null)
                        w1 = w;
                    else if (w2 == null)
                        w2 = w;
                    else
                        log.warn("Through route relation", relation.toBrowseURL(), "has more than 2 ways");
                }
            }
            CoordNode coordNode = null;
            if (node == null)
                log.warn("Through route relation", relation.toBrowseURL(), "is missing the junction node");
            else {
                Coord junctionPoint = node.getLocation();
                if (bbox != null && !bbox.contains(junctionPoint)) {
                    // junction is outside of the tile - ignore it
                    continue;
                }
                coordNode = nodeIdMap.get(junctionPoint);
                if (coordNode == null)
                    log.warn("Through route relation", relation.toBrowseURL(), "junction node at", junctionPoint.toOSMURL(), "is not a routing node");
            }
            if (w1 == null || w2 == null)
                log.warn("Through route relation", relation.toBrowseURL(), "should reference 2 ways that meet at the junction node");
            if (coordNode != null && w1 != null && w2 != null)
                collector.addThroughRoute(coordNode.getId(), w1.getId(), w2.getId());
        }
    }
    // return memory to GC
    nodeIdMap = null;
    throughRouteRelations.clear();
    restrictions.clear();
}
Also used : Node(uk.me.parabola.mkgmap.reader.osm.Node) CoordNode(uk.me.parabola.imgfmt.app.CoordNode) MapElement(uk.me.parabola.mkgmap.general.MapElement) Element(uk.me.parabola.mkgmap.reader.osm.Element) Way(uk.me.parabola.mkgmap.reader.osm.Way) Coord(uk.me.parabola.imgfmt.app.Coord) RestrictionRelation(uk.me.parabola.mkgmap.reader.osm.RestrictionRelation) Relation(uk.me.parabola.mkgmap.reader.osm.Relation) RestrictionRelation(uk.me.parabola.mkgmap.reader.osm.RestrictionRelation) CoordNode(uk.me.parabola.imgfmt.app.CoordNode) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) MultiHashMap(uk.me.parabola.util.MultiHashMap)

Example 8 with CoordNode

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

the class RoadNetwork method addRestriction.

/**
 * One restriction forbids to travel a specific combination of arcs.
 * We know two kinds: 3 nodes with two arcs and one via node or 4 nodes with 3 arcs
 * and two via nodes. Maybe more nodes are possible, but we don't know for sure how
 * to write them (2014-04-02).
 * Depending on the data in grr we create one or more such restrictions.
 * A restriction with 4 (or more) nodes is added to each via node.
 *
 * The OSM restriction gives a from way id and a to way id and one or more
 * via nodes. It is possible that the to-way is a loop, so we have to identify
 * the correct arc.
 * @param grr the object that holds the details about the route restriction
 */
public int addRestriction(GeneralRouteRestriction grr) {
    if (grr.getType() == GeneralRouteRestriction.RestrType.TYPE_NO_TROUGH)
        return addNoThroughRoute(grr);
    String sourceDesc = grr.getSourceDesc();
    List<RouteNode> viaNodes = new ArrayList<>();
    for (CoordNode via : grr.getViaNodes()) {
        RouteNode vn = nodes.get(via.getId());
        if (vn == null) {
            log.error(sourceDesc, "can't locate 'via' RouteNode with id", via.getId());
            return 0;
        }
        viaNodes.add(vn);
    }
    int firstViaId = grr.getViaNodes().get(0).getId();
    int lastViaId = grr.getViaNodes().get(grr.getViaNodes().size() - 1).getId();
    RouteNode firstViaNode = nodes.get(firstViaId);
    RouteNode lastViaNode = nodes.get(lastViaId);
    List<List<RouteArc>> viaArcsList = new ArrayList<>();
    if (grr.getViaNodes().size() != grr.getViaWayIds().size() + 1) {
        log.error(sourceDesc, "internal error: number of via nodes and via ways doesn't fit");
        return 0;
    }
    for (int i = 1; i < grr.getViaNodes().size(); i++) {
        RouteNode vn = viaNodes.get(i - 1);
        Long viaWayId = grr.getViaWayIds().get(i - 1);
        List<RouteArc> viaArcs = vn.getDirectArcsTo(viaNodes.get(i), viaWayId);
        if (viaArcs.isEmpty()) {
            log.error(sourceDesc, "can't locate arc from 'via' node at", vn.getCoord().toOSMURL(), "to next 'via' node on way", viaWayId);
            return 0;
        }
        viaArcsList.add(viaArcs);
    }
    // determine the from node and arc(s)
    int fromId = 0;
    RouteNode fn = null;
    if (grr.getFromNode() != null) {
        fromId = grr.getFromNode().getId();
        // polish input data provides id
        fn = nodes.get(fromId);
        if (fn == null) {
            log.error(sourceDesc, "can't locate 'from' RouteNode with id", fromId);
            return 0;
        }
    } else {
        List<RouteArc> possibleFromArcs = firstViaNode.getDirectArcsOnWay(grr.getFromWayId());
        for (RouteArc arc : possibleFromArcs) {
            if (fn == null)
                fn = arc.getDest();
            else if (fn != arc.getDest()) {
                log.warn(sourceDesc, "found different 'from' arcs for way", grr.getFromWayId(), "restriction is ignored");
                return 0;
            }
        }
        if (fn == null) {
            log.warn(sourceDesc, "can't locate 'from' RouteNode for 'from' way", grr.getFromWayId());
            return 0;
        }
        fromId = fn.getCoord().getId();
    }
    List<RouteArc> fromArcs = fn.getDirectArcsTo(firstViaNode, grr.getFromWayId());
    if (fromArcs.isEmpty()) {
        log.error(sourceDesc, "can't locate arc from 'from' node ", fromId, "to 'via' node", firstViaId, "on way", grr.getFromWayId());
        return 0;
    }
    // a bit more complex: determine the to-node and arc(s)
    RouteNode tn = null;
    int toId = 0;
    List<RouteArc> toArcs = new ArrayList<>();
    if (grr.getToNode() != null) {
        // polish input data provides id
        toId = grr.getToNode().getId();
        tn = nodes.get(toId);
        if (tn == null) {
            log.error(sourceDesc, "can't locate 'to' RouteNode with id", toId);
            return 0;
        }
    } else {
        // we can have multiple arcs between last via node and to node. The
        // arcs can be on the same OSM way or on different OSM ways.
        // We can have multiple arcs with different RoadDef objects that refer to the same
        // OSM way id. The direction indicator tells us what arc is probably meant.
        List<RouteArc> possibleToArcs = lastViaNode.getDirectArcsOnWay(grr.getToWayId());
        RouteArc fromArc = fromArcs.get(0);
        boolean ignoreAngle = false;
        if (fromArc.getLengthInMeter() <= 0.0001)
            ignoreAngle = true;
        if (grr.getDirIndicator() == '?')
            ignoreAngle = true;
        log.info(sourceDesc, "found", possibleToArcs.size(), "candidates for to-arc");
        // group the available arcs by angle
        Map<Integer, List<RouteArc>> angleMap = new TreeMap<>();
        for (RouteArc arc : possibleToArcs) {
            if (arc.getLengthInMeter() <= 0.0001)
                ignoreAngle = true;
            Integer angle = Math.round(getAngle(fromArc, arc));
            List<RouteArc> list = angleMap.get(angle);
            if (list == null) {
                list = new ArrayList<>();
                angleMap.put(angle, list);
            }
            list.add(arc);
        }
        // find the group that fits best
        Iterator<Entry<Integer, List<RouteArc>>> iter = angleMap.entrySet().iterator();
        Integer bestAngle = null;
        while (iter.hasNext()) {
            Entry<Integer, List<RouteArc>> entry = iter.next();
            if (ignoreAngle || matchDirectionInfo(entry.getKey(), grr.getDirIndicator())) {
                if (bestAngle == null)
                    bestAngle = entry.getKey();
                else {
                    bestAngle = getBetterAngle(bestAngle, entry.getKey(), grr.getDirIndicator());
                }
            }
        }
        if (bestAngle == null) {
            log.warn(sourceDesc, "the angle of the from and to way don't match the restriction");
            return 0;
        }
        toArcs = angleMap.get(bestAngle);
    }
    if (toArcs.isEmpty()) {
        log.error(sourceDesc, "can't locate arc from 'via' node ", lastViaId, "to 'to' node", toId, "on way", grr.getToWayId());
        return 0;
    }
    List<RouteArc> badArcs = new ArrayList<>();
    if (grr.getType() == GeneralRouteRestriction.RestrType.TYPE_NOT) {
        for (RouteArc toArc : toArcs) {
            badArcs.add(toArc);
        }
    } else if (grr.getType() == GeneralRouteRestriction.RestrType.TYPE_ONLY) {
        // this is the inverse logic, grr gives the allowed path, we have to find the others
        for (RouteArc badArc : lastViaNode.arcsIteration()) {
            if (!badArc.isDirect() || toArcs.contains(badArc))
                continue;
            badArcs.add(badArc);
        }
        if (badArcs.isEmpty()) {
            log.warn(sourceDesc, "restriction ignored because it has no effect");
            return 0;
        }
    }
    // create all possible paths for which the restriction applies
    List<List<RouteArc>> arcLists = new ArrayList<>();
    arcLists.add(fromArcs);
    arcLists.addAll(viaArcsList);
    arcLists.add(badArcs);
    if (arcLists.size() > MAX_RESTRICTIONS_ARCS) {
        log.warn(sourceDesc, "has more than", MAX_RESTRICTIONS_ARCS, "arcs, this is not supported");
        return 0;
    }
    // remove arcs which cannot be travelled by the vehicles listed in the restriction
    for (int i = 0; i < arcLists.size(); i++) {
        List<RouteArc> arcs = arcLists.get(i);
        int countNoEffect = 0;
        int countOneway = 0;
        for (int j = arcs.size() - 1; j >= 0; --j) {
            RouteArc arc = arcs.get(j);
            if (isUsable(arc.getRoadDef().getAccess(), grr.getExceptionMask()) == false) {
                countNoEffect++;
                arcs.remove(j);
            } else if (arc.getRoadDef().isOneway()) {
                if (!arc.isForward()) {
                    countOneway++;
                    arcs.remove(j);
                }
            }
        }
        String arcType = null;
        if (arcs.isEmpty()) {
            if (i == 0)
                arcType = "from way is";
            else if (i == arcLists.size() - 1) {
                if (grr.getType() == GeneralRouteRestriction.RestrType.TYPE_ONLY)
                    arcType = "all possible other ways are";
                else
                    arcType = "to way is";
            } else
                arcType = "via way is";
            String reason;
            if (countNoEffect > 0 & countOneway > 0)
                reason = "wrong direction in oneway or not accessible for restricted vehicles";
            else if (countNoEffect > 0)
                reason = "not accessible for restricted vehicles";
            else
                reason = "wrong direction in oneway";
            log.warn(sourceDesc, "restriction ignored because", arcType, reason);
            return 0;
        }
    }
    if (viaNodes.contains(fn)) {
        log.warn(sourceDesc, "restriction not written because from node appears also as via node");
        return 0;
    }
    // determine all possible combinations of arcs. In most cases,
    // this will be 0 or one, but if the style creates multiple roads for one
    // OSM way, this can be a larger number
    int numCombis = 1;
    int[] indexes = new int[arcLists.size()];
    for (int i = 0; i < indexes.length; i++) {
        List<RouteArc> arcs = arcLists.get(i);
        numCombis *= arcs.size();
    }
    List<RouteArc> path = new ArrayList<>();
    int added = 0;
    for (int i = 0; i < numCombis; i++) {
        for (RouteNode vn : viaNodes) {
            path.clear();
            boolean viaNodeFound = false;
            byte pathNoAccessMask = 0;
            for (int j = 0; j < indexes.length; j++) {
                RouteArc arc = arcLists.get(j).get(indexes[j]);
                if (arc.getDest() == vn || viaNodeFound == false) {
                    arc = arc.getReverseArc();
                }
                if (arc.getSource() == vn)
                    viaNodeFound = true;
                if (arc.getDest() == vn) {
                    if (added > 0)
                        log.error(sourceDesc, "restriction incompletely written because dest in arc is via node");
                    else
                        log.warn(sourceDesc, "restriction not written because dest in arc is via node");
                    return added;
                }
                pathNoAccessMask |= ~arc.getRoadDef().getAccess();
                path.add(arc);
            }
            byte pathAccessMask = (byte) ~pathNoAccessMask;
            if (isUsable(pathAccessMask, grr.getExceptionMask())) {
                vn.addRestriction(new RouteRestriction(vn, path, grr.getExceptionMask()));
                ++added;
            }
        }
        // get next combination of arcs
        ++indexes[indexes.length - 1];
        for (int j = indexes.length - 1; j > 0; --j) {
            if (indexes[j] >= arcLists.get(j).size()) {
                indexes[j] = 0;
                indexes[j - 1]++;
            }
        }
    }
    // double check
    if (indexes[0] != arcLists.get(0).size())
        log.error(sourceDesc, " failed to generate all possible paths");
    log.info(sourceDesc, "added", added, "route restriction(s) to img file");
    return added;
}
Also used : ArrayList(java.util.ArrayList) TreeMap(java.util.TreeMap) Entry(java.util.Map.Entry) CoordNode(uk.me.parabola.imgfmt.app.CoordNode) ArrayList(java.util.ArrayList) List(java.util.List)

Example 9 with CoordNode

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

the class RGNFileReader method readBitStream.

/**
 * Read the bit stream for a single line in the file.
 * @param br The bit stream reader.
 * @param div The subdivision that the line is in.
 * @param line The line itself.
 * @param extra True if there is an 'extra' bit in the stream. Used for nodes.
 * @param len The length of the stream.
 * @param base The base size of the deltas.
 */
private void readBitStream(BitReader br, Subdivision div, Polyline line, boolean extra, int len, int base) {
    int currLat = line.getLat();
    int currLon = line.getLong();
    log.debug(String.format("Start point %.5f,%.5f", Utils.toDegrees(currLat), Utils.toDegrees(currLon)));
    if (extra)
        line.addCoord(new CoordNode(currLat, currLon, 0, /* XXX */
        false));
    else
        line.addCoord(new Coord(currLat, currLon));
    int xbase = 2;
    int n = base & 0xf;
    if (n <= 9)
        xbase += n;
    else
        xbase += (2 * n) - 9;
    n = (base >>> 4) & 0xf;
    int ybase = 2;
    if (n <= 9)
        ybase += n;
    else
        ybase += (2 * n) - 9;
    if (len == 0)
        return;
    boolean xneg = false;
    boolean xsame = br.get1();
    if (xsame) {
        xneg = br.get1();
    } else
        xbase++;
    boolean ysame = br.get1();
    boolean yneg = false;
    if (ysame) {
        yneg = br.get1();
    } else
        ybase++;
    if (line.hasExtendedType()) {
        br.get1();
    }
    if (extra) {
        boolean firstextra = br.get1();
        log.debug("the first extra bit is", firstextra);
    }
    // proper lat/long coords.
    while (br.getBitPosition() <= 8 * len - ((extra ? 1 : 0) + xbase + ybase)) {
        br.getBitPosition();
        int dx;
        if (xsame) {
            dx = br.get(xbase);
            if (xneg)
                dx = -dx;
        } else {
            dx = br.sget2(xbase);
        }
        int dy;
        if (ysame) {
            dy = br.get(ybase);
            if (yneg)
                dy = -dy;
        } else {
            dy = br.sget2(ybase);
        }
        boolean isnode = false;
        if (extra)
            isnode = br.get1();
        currLat += dy << (24 - div.getResolution());
        currLon += dx << (24 - div.getResolution());
        Coord coord;
        if (isnode)
            coord = new CoordNode(currLat, currLon, 0, /* XXX */
            false);
        else
            coord = new Coord(currLat, currLon);
        line.addCoord(coord);
    }
    if (line instanceof Polygon) {
        // make sure that polygon is closed
        line.addCoord(line.getPoints().get(0));
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) CoordNode(uk.me.parabola.imgfmt.app.CoordNode)

Example 10 with CoordNode

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

the class RoundCoordsFilter method doFilter.

/**
 * @param element A map element that will be a line or a polygon.
 * @param next This is used to pass the possibly transformed element onward.
 */
public void doFilter(MapElement element, MapFilterChain next) {
    MapLine line = (MapLine) element;
    // 0.5 shifted
    int half = 1 << (shift - 1);
    // to remove fraction bits
    int mask = ~((1 << shift) - 1);
    if (shift == 0) {
        // do nothing
        next.doFilter(line);
    } else {
        // round lat/lon values to nearest for shift
        List<Coord> newPoints = new ArrayList<Coord>(line.getPoints().size());
        Coord lastP = null;
        for (Coord p : line.getPoints()) {
            int lat = (p.getLatitude() + half) & mask;
            int lon = (p.getLongitude() + half) & mask;
            Coord newP;
            if (p instanceof CoordNode && checkRouting)
                newP = new CoordNode(lat, lon, p.getId(), p.getOnBoundary());
            else
                newP = new Coord(lat, lon);
            newP.preserved(p.preserved());
            // CoordNode and the last point wasn't a CoordNode
            if (lastP == null || !lastP.equals(newP) || (newP instanceof CoordNode && !(lastP instanceof CoordNode))) {
                newPoints.add(newP);
                lastP = newP;
            } else if (newP.preserved()) {
                // this point is not going to be used because it
                // has the same (rounded) coordinates as the last
                // node but it has been marked as being "preserved" -
                // transfer that property to the previous point so
                // that it's not lost
                lastP.preserved(true);
            }
        }
        if (newPoints.size() > 1) {
            MapLine newLine = line.copy();
            newLine.setPoints(newPoints);
            next.doFilter(newLine);
        }
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) MapLine(uk.me.parabola.mkgmap.general.MapLine) ArrayList(java.util.ArrayList) CoordNode(uk.me.parabola.imgfmt.app.CoordNode)

Aggregations

CoordNode (uk.me.parabola.imgfmt.app.CoordNode)12 Coord (uk.me.parabola.imgfmt.app.Coord)10 ArrayList (java.util.ArrayList)6 GeneralRouteRestriction (uk.me.parabola.imgfmt.app.net.GeneralRouteRestriction)3 Way (uk.me.parabola.mkgmap.reader.osm.Way)3 HashMap (java.util.HashMap)2 IdentityHashMap (java.util.IdentityHashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 List (java.util.List)2 Map (java.util.Map)2 Entry (java.util.Map.Entry)2 MapExitPoint (uk.me.parabola.mkgmap.general.MapExitPoint)2 MapLine (uk.me.parabola.mkgmap.general.MapLine)2 MapPoint (uk.me.parabola.mkgmap.general.MapPoint)2 MapRoad (uk.me.parabola.mkgmap.general.MapRoad)2 Node (uk.me.parabola.mkgmap.reader.osm.Node)2 RestrictionRelation (uk.me.parabola.mkgmap.reader.osm.RestrictionRelation)2 MultiHashMap (uk.me.parabola.util.MultiHashMap)2 BitSet (java.util.BitSet)1 TreeMap (java.util.TreeMap)1