Search in sources :

Example 1 with CoordNode

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

the class StyledConverter method createRouteRestrictionsFromPOI.

/**
 * If POI changes access restrictions (e.g. bollards), create corresponding
 * route restrictions so that only allowed vehicles/pedestrians are routed
 * through this point.
 */
private void createRouteRestrictionsFromPOI() {
    Iterator<Map.Entry<Node, List<Way>>> iter = poiRestrictions.entrySet().iterator();
    while (iter.hasNext()) {
        Map.Entry<Node, List<Way>> entry = iter.next();
        Node node = entry.getKey();
        Coord p = node.getLocation();
        // list of ways that are connected to the poi
        List<Way> wayList = entry.getValue();
        byte exceptMask = AccessTagsAndBits.evalAccessTags(node);
        Map<Integer, CoordNode> otherNodeIds = new LinkedHashMap<>();
        CoordNode viaNode = null;
        boolean viaIsUnique = true;
        for (Way way : wayList) {
            CoordNode lastNode = null;
            for (Coord co : way.getPoints()) {
                // not 100% fail safe: points may have been replaced before
                if (co instanceof CoordNode == false)
                    continue;
                CoordNode cn = (CoordNode) co;
                if (p.highPrecEquals(cn)) {
                    if (viaNode == null)
                        viaNode = cn;
                    else if (viaNode != cn) {
                        log.error("Found multiple points with equal coords as CoordPOI at " + p.toOSMURL());
                        // if we ever get here we can add code to identify the exact node
                        viaIsUnique = false;
                    }
                    if (lastNode != null)
                        otherNodeIds.put(lastNode.getId(), lastNode);
                } else {
                    if (p.highPrecEquals(lastNode))
                        otherNodeIds.put(cn.getId(), cn);
                }
                lastNode = cn;
            }
        }
        if (viaNode == null) {
            log.error("Did not find CoordPOI node at " + p.toOSMURL() + " in ways " + wayList);
            continue;
        }
        if (viaIsUnique == false) {
            log.error("Found multiple points with equal coords as CoordPOI at " + p.toOSMURL());
            continue;
        }
        if (otherNodeIds.size() < 2) {
            log.info("Access restriction in POI node " + node.toBrowseURL() + " was ignored, has no effect on any connected way");
            continue;
        }
        GeneralRouteRestriction rr = new GeneralRouteRestriction("no_through", exceptMask, "CoordPOI at " + p.toOSMURL());
        rr.setViaNodes(Arrays.asList(viaNode));
        int added = collector.addRestriction(rr);
        if (added == 0) {
            log.info("Access restriction in POI node " + node.toBrowseURL() + " was ignored, has no effect on any connected way");
        } else {
            log.info("Access restriction in POI node", node.toBrowseURL(), "was translated to", added, "route restriction(s)");
        }
        if (wayList.size() > 1 && added > 2) {
            log.warn("Access restriction in POI node", node.toBrowseURL(), "affects routing on multiple ways");
        }
    }
}
Also used : Node(uk.me.parabola.mkgmap.reader.osm.Node) CoordNode(uk.me.parabola.imgfmt.app.CoordNode) Way(uk.me.parabola.mkgmap.reader.osm.Way) MapPoint(uk.me.parabola.mkgmap.general.MapPoint) MapExitPoint(uk.me.parabola.mkgmap.general.MapExitPoint) LinkedHashMap(java.util.LinkedHashMap) Coord(uk.me.parabola.imgfmt.app.Coord) Entry(java.util.Map.Entry) GeneralRouteRestriction(uk.me.parabola.imgfmt.app.net.GeneralRouteRestriction) List(java.util.List) ArrayList(java.util.ArrayList) 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 2 with CoordNode

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

the class StyledConverter method addRoadWithoutLoops.

private void addRoadWithoutLoops(ConvertedWay cw) {
    Way way = cw.getWay();
    List<Integer> nodeIndices = new ArrayList<>();
    List<Coord> points = way.getPoints();
    if (points.size() < 2) {
        log.warn("road has < 2 points", way.getId(), "(discarding)");
        return;
    }
    Way trailingWay = null;
    String debugWayName = way.getDebugName();
    // collect the Way's nodes and also split the way if any
    // inter-node arc length becomes excessive
    double arcLength = 0;
    // detect if it would be split by the LineSizeSplitterFilter
    class WayBBox {

        int minLat = Integer.MAX_VALUE;

        int maxLat = Integer.MIN_VALUE;

        int minLon = Integer.MAX_VALUE;

        int maxLon = Integer.MIN_VALUE;

        void addPoint(Coord co) {
            int lat = co.getLatitude();
            if (lat < minLat)
                minLat = lat;
            if (lat > maxLat)
                maxLat = lat;
            int lon = co.getLongitude();
            if (lon < minLon)
                minLon = lon;
            if (lon > maxLon)
                maxLon = lon;
        }

        boolean tooBig() {
            return LineSizeSplitterFilter.testDims(maxLat - minLat, maxLon - minLon) >= 1.0;
        }
    }
    WayBBox wayBBox = new WayBBox();
    for (int i = 0; i < points.size(); ++i) {
        Coord p = points.get(i);
        wayBBox.addPoint(p);
        // the arc length between nodes
        if ((i + 1) < points.size()) {
            Coord nextP = points.get(i + 1);
            double d = p.distance(nextP);
            for (; ; ) {
                int dlat = Math.abs(nextP.getLatitude() - p.getLatitude());
                int dlon = Math.abs(nextP.getLongitude() - p.getLongitude());
                if (d > MAX_ARC_LENGTH || Math.max(dlat, dlon) >= LineSizeSplitterFilter.MAX_SIZE) {
                    double frac = Math.min(0.5, 0.95 * (MAX_ARC_LENGTH / d));
                    nextP = p.makeBetweenPoint(nextP, frac);
                    nextP.incHighwayCount();
                    points.add(i + 1, nextP);
                    double newD = p.distance(nextP);
                    if (log.isInfoEnabled())
                        log.info("Way", debugWayName, "contains a segment that is", (int) d + "m long but I am adding a new point to reduce its length to", (int) newD + "m");
                    d = newD;
                } else
                    break;
            }
            wayBBox.addPoint(nextP);
            if ((arcLength + d) > MAX_ARC_LENGTH) {
                if (i <= 0)
                    log.error("internal error: long arc segment was not split", debugWayName);
                assert i > 0 : "long arc segment was not split";
                assert trailingWay == null : "trailingWay not null #1";
                trailingWay = splitWayAt(way, i);
                // points so the loop will now terminate
                if (log.isInfoEnabled())
                    log.info("Splitting way", debugWayName, "at", points.get(i).toOSMURL(), "to limit arc length to", (long) arcLength + "m");
            } else if (wayBBox.tooBig()) {
                if (i <= 0)
                    log.error("internal error: arc segment with big bbox not split", debugWayName);
                assert i > 0 : "arc segment with big bbox not split";
                assert trailingWay == null : "trailingWay not null #2";
                trailingWay = splitWayAt(way, i);
                // points so the loop will now terminate
                if (log.isInfoEnabled())
                    log.info("Splitting way", debugWayName, "at", points.get(i).toOSMURL(), "to limit the size of its bounding box");
            } else {
                if (p.getHighwayCount() > 1) {
                    // point is a node so zero arc length
                    arcLength = 0;
                }
                arcLength += d;
            }
        }
        if (p.getHighwayCount() > 1) {
            // this point is a node connecting highways
            CoordNode coordNode = nodeIdMap.get(p);
            if (coordNode == null) {
                // assign a node id
                coordNode = new CoordNode(p, nextNodeId++, p.getOnBoundary());
                nodeIdMap.put(p, coordNode);
            }
            if (p instanceof CoordPOI) {
                // check if this poi should be converted to a route restriction
                CoordPOI cp = (CoordPOI) p;
                if (cp.getConvertToViaInRouteRestriction()) {
                    String wayPOI = way.getTag(WAY_POI_NODE_IDS);
                    if (wayPOI != null && wayPOI.contains("[" + cp.getNode().getId() + "]")) {
                        byte nodeAccess = AccessTagsAndBits.evalAccessTags(cp.getNode());
                        if (nodeAccess != cw.getAccess()) {
                            List<Way> wayList = poiRestrictions.get(cp.getNode());
                            if (wayList == null) {
                                wayList = new ArrayList<>();
                                poiRestrictions.put(cp.getNode(), wayList);
                            }
                            wayList.add(way);
                        }
                    }
                }
            }
            // add this index to node Indexes (should not already be there)
            assert !nodeIndices.contains(i) : debugWayName + " has multiple nodes for point " + i + " new node is " + p.toOSMURL();
            nodeIndices.add(i);
            if ((i + 1) < points.size() && nodeIndices.size() == MAX_NODES_IN_WAY) {
                // limit
                assert trailingWay == null : "trailingWay not null #7";
                trailingWay = splitWayAt(way, i);
                // points so the loop will now terminate
                if (log.isInfoEnabled())
                    log.info("Splitting way", debugWayName, "at", points.get(i).toOSMURL(), "as it has at least", MAX_NODES_IN_WAY, "nodes");
            }
        }
    }
    MapLine line = new MapLine();
    elementSetup(line, cw.getGType(), way);
    line.setPoints(points);
    MapRoad road = new MapRoad(nextRoadId++, way.getId(), line);
    if (routable == false)
        road.skipAddToNOD(true);
    boolean doFlareCheck = true;
    if (cw.isRoundabout()) {
        road.setRoundabout(true);
        doFlareCheck = false;
    }
    if (way.tagIsLikeYes("mkgmap:synthesised")) {
        road.setSynthesised(true);
        doFlareCheck = false;
    }
    if (way.tagIsLikeNo("mkgmap:flare-check")) {
        doFlareCheck = false;
    } else if (way.tagIsLikeYes("mkgmap:flare-check")) {
        doFlareCheck = true;
    }
    road.doFlareCheck(doFlareCheck);
    // set road parameters
    // copy road class and road speed
    road.setRoadClass(cw.getRoadClass());
    road.setSpeed(cw.getRoadSpeed());
    if (cw.isOneway()) {
        road.setDirection(true);
        road.setOneway();
    }
    road.setAccess(cw.getAccess());
    // does the road have a carpool lane?
    if (cw.isCarpool())
        road.setCarpoolLane();
    if (cw.isThroughroute() == false)
        road.setNoThroughRouting();
    if (cw.isToll())
        road.setToll();
    // by default, ways are paved
    if (cw.isUnpaved())
        road.paved(false);
    // by default, way's are not ferry routes
    if (cw.isFerry())
        road.ferry(true);
    int numNodes = nodeIndices.size();
    if (way.isViaWay() && numNodes > 2) {
        List<RestrictionRelation> rrList = wayRelMap.get(way.getId());
        for (RestrictionRelation rr : rrList) {
            rr.updateViaWay(way, nodeIndices);
        }
    }
    if (numNodes > 0) {
        // replace Coords that are nodes with CoordNodes
        for (int i = 0; i < numNodes; ++i) {
            int n = nodeIndices.get(i);
            Coord coord = points.get(n);
            CoordNode thisCoordNode = nodeIdMap.get(coord);
            assert thisCoordNode != null : "Way " + debugWayName + " node " + i + " (point index " + n + ") at " + coord.toOSMURL() + " yields a null coord node";
            boolean boundary = coord.getOnBoundary();
            if (boundary && log.isInfoEnabled()) {
                log.info("Way", debugWayName + "'s point #" + n, "at", coord.toOSMURL(), "is a boundary node");
            }
            points.set(n, thisCoordNode);
        }
    }
    if (roadLog.isInfoEnabled()) {
        // shift the bits so that they have the correct position
        int cmpAccess = (road.getRoadDef().getTabAAccess() & 0xff) + ((road.getRoadDef().getTabAAccess() & 0xc000) >> 6);
        if (road.isDirection()) {
            cmpAccess |= 1 << 10;
        }
        String access = String.format("%11s", Integer.toBinaryString(cmpAccess)).replace(' ', '0');
        roadLog.info(String.format("%19d 0x%-2x %11s %6d %6d %6d %s", way.getId(), road.getType(), access, road.getRoadDef().getRoadClass(), road.getRoadDef().getRoadSpeed(), road.getPoints().size(), Arrays.toString(road.getLabels())));
    }
    // add the road to the housenumber generator
    // it will add the road later on to the lineAdder
    housenumberGenerator.addRoad(way, road);
    if (trailingWay != null)
        addRoadWithoutLoops(new ConvertedWay(cw, trailingWay));
}
Also used : MapLine(uk.me.parabola.mkgmap.general.MapLine) ArrayList(java.util.ArrayList) MapRoad(uk.me.parabola.mkgmap.general.MapRoad) Way(uk.me.parabola.mkgmap.reader.osm.Way) MapPoint(uk.me.parabola.mkgmap.general.MapPoint) MapExitPoint(uk.me.parabola.mkgmap.general.MapExitPoint) Coord(uk.me.parabola.imgfmt.app.Coord) RestrictionRelation(uk.me.parabola.mkgmap.reader.osm.RestrictionRelation) CoordPOI(uk.me.parabola.mkgmap.reader.osm.CoordPOI) CoordNode(uk.me.parabola.imgfmt.app.CoordNode)

Example 3 with CoordNode

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

the class HousenumberRoad method buildIntervals.

public void buildIntervals() {
    Collections.sort(houseNumbers, new HousenumberMatchByNumComparator());
    if (log.isInfoEnabled())
        log.info("Initial housenumbers for", road, "in", road.getCity(), houseNumbers);
    filterRealDuplicates();
    filterGroups();
    if (houseNumbers.isEmpty())
        return;
    List<HousenumberMatch> leftNumbers = new ArrayList<HousenumberMatch>();
    List<HousenumberMatch> rightNumbers = new ArrayList<HousenumberMatch>();
    for (HousenumberMatch house : houseNumbers) {
        if (house.getRoad() == null || house.isIgnored()) {
            continue;
        }
        if (house.getHousenumberRoad() != this || house.getHousenumberRoad().getRoad() != house.getRoad()) {
            log.error("internal error, road links are not correct", house.toBrowseURL());
        }
        if (house.isLeft()) {
            leftNumbers.add(house);
        } else {
            rightNumbers.add(house);
        }
    }
    detectGroups(leftNumbers, rightNumbers);
    Collections.sort(leftNumbers, new HousenumberMatchByPosComparator());
    Collections.sort(rightNumbers, new HousenumberMatchByPosComparator());
    int currNodePos = 0;
    int nodeIndex = 0;
    int prevNumberNodeIndex = 0;
    int prevNodePos = 0;
    extNumbersHead = null;
    ExtNumbers currNumbers = null;
    for (Coord p : road.getPoints()) {
        if (currNodePos == 0) {
            if (road.skipAddToNOD() == false)
                assert p instanceof CoordNode;
        }
        // An ordinary point in the road.
        if (p.isNumberNode() == false) {
            currNodePos++;
            continue;
        }
        // The first time round, this is guaranteed to be a CoordNode
        if (currNodePos == 0) {
            nodeIndex++;
            currNodePos++;
            continue;
        }
        // Now we have a CoordNode and it is not the first one.
        ExtNumbers numbers = new ExtNumbers(this);
        numbers.setNodeIndex(prevNumberNodeIndex);
        int leftUsed = numbers.setNumbers(leftNumbers, prevNodePos, currNodePos, true);
        int rightUsed = numbers.setNumbers(rightNumbers, prevNodePos, currNodePos, false);
        prevNodePos = currNodePos;
        // maintain chain
        numbers.prev = currNumbers;
        if (currNumbers != null)
            currNumbers.next = numbers;
        else {
            extNumbersHead = numbers;
        }
        currNumbers = numbers;
        leftNumbers.subList(0, leftUsed).clear();
        rightNumbers.subList(0, rightUsed).clear();
        prevNumberNodeIndex = nodeIndex;
        nodeIndex++;
        currNodePos++;
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) HousenumberMatchByPosComparator(uk.me.parabola.mkgmap.osmstyle.housenumber.HousenumberGenerator.HousenumberMatchByPosComparator) HousenumberMatchByNumComparator(uk.me.parabola.mkgmap.osmstyle.housenumber.HousenumberGenerator.HousenumberMatchByNumComparator) ArrayList(java.util.ArrayList) CoordNode(uk.me.parabola.imgfmt.app.CoordNode)

Example 4 with CoordNode

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

the class RoadHelper method makeRoad.

public MapRoad makeRoad(MapLine l) {
    assert roadId != 0;
    if (log.isDebugEnabled())
        log.debug("finishing road id " + roadId);
    MapRoad road = new MapRoad(roadId, roadId, l);
    // Set parameters.
    road.setRoadClass(roadClass);
    road.setSpeed(speed);
    if (oneway)
        road.setOneway();
    if (toll)
        road.setToll();
    road.setAccess(mkgmapAccess);
    if (numbers != null && !numbers.isEmpty()) {
        convertNodesForHouseNumbers(road);
        road.setNumbers(numbers);
    }
    List<Coord> points = road.getPoints();
    for (NodeIndex ni : nodes) {
        int n = ni.index;
        if (log.isDebugEnabled())
            log.debug("road has " + points.size() + " points");
        Coord coord = points.get(n);
        long id = coord.getId();
        if (id == 0) {
            CoordNode node = nodeCoords.get((long) ni.nodeId);
            if (node == null) {
                node = new CoordNode(coord, ni.nodeId, ni.boundary);
                nodeCoords.put((long) ni.nodeId, node);
            }
            points.set(n, node);
        } else if (id != ni.nodeId) {
            log.warn("Inconsistant node ids");
        }
    }
    return road;
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) CoordNode(uk.me.parabola.imgfmt.app.CoordNode) MapRoad(uk.me.parabola.mkgmap.general.MapRoad)

Example 5 with CoordNode

use of uk.me.parabola.imgfmt.app.CoordNode 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)

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