Search in sources :

Example 46 with Coord

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

the class MultiPolygonRelation method runIntersectionCheck.

private void runIntersectionCheck(BitSet unfinishedPolys) {
    if (intersectingPolygons.isEmpty()) {
        // nothing to do
        return;
    }
    log.warn("Some polygons are intersecting. This is not allowed in multipolygons.");
    boolean oneOufOfBbox = false;
    for (JoinedWay polygon : intersectingPolygons) {
        int pi = polygons.indexOf(polygon);
        unfinishedPolys.clear(pi);
        boolean outOfBbox = false;
        for (Coord c : polygon.getPoints()) {
            if (!tileBounds.contains(c)) {
                outOfBbox = true;
                oneOufOfBbox = true;
                break;
            }
        }
        logWayURLs(Level.WARNING, (outOfBbox ? "*" : "-"), polygon);
    }
    for (JoinedWay polygon : intersectingPolygons) {
        // print out the details of the original ways
        logFakeWayDetails(Level.WARNING, polygon);
    }
    if (oneOufOfBbox) {
        log.warn("Some of these intersections/overlaps may be caused by incomplete data on bounding box edges (*).");
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord)

Example 47 with Coord

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

the class RestrictionRelation method eval.

/**
 * The evaluation should happen after style processing.
 * Normally this is called from the {@link RelationStyleHook}
 * Performs also diverse plausibility checks.
 * @param bbox tile boundary
 */
public void eval(Area bbox) {
    if (evalWasCalled) {
        log.error(messagePrefix, "internal error: eval() was already called");
        fromWayIds.clear();
        toWayIds.clear();
        viaWayIds.clear();
    }
    evalWasCalled = true;
    if (getTag("type") == null) {
        // style removed the tag
        log.info(messagePrefix, "type tag was removed, relation is ignored");
        valid = false;
        return;
    }
    List<Way> fromWays = new ArrayList<>();
    List<Way> toWays = new ArrayList<>();
    List<Way> viaWays = new ArrayList<>();
    final String browseURL = toBrowseURL();
    valid = true;
    // find out what kind of restriction we have and to which vehicles it applies
    exceptMask = DEFAULT_EXCEPT_MASK;
    String specifc_type = getTag("restriction");
    int count_unknown = 0;
    Map<String, String> vehicles = getTagsWithPrefix("restriction:", true);
    if (vehicles.isEmpty() == false) {
        exceptMask = (byte) 0xff;
        Iterator<Entry<String, String>> iter = vehicles.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, String> entry = iter.next();
            String vehicle = entry.getKey();
            if (setExceptMask(vehicle, false) == false)
                count_unknown++;
            if (specifc_type == null)
                specifc_type = entry.getValue();
            else if (specifc_type.equals(entry.getValue()) == false) {
                log.warn(messagePrefix, "is invalid, it specifies different kinds of turns");
                valid = false;
                break;
            }
        }
        if (valid && vehicles.size() == count_unknown) {
            log.warn(messagePrefix, "no supported vehicle in turn restriction");
            valid = false;
            return;
        }
    }
    if (specifc_type == null) {
        // style removed the tag
        log.info(messagePrefix, "no valid restriction tag found");
        valid = false;
        return;
    }
    restriction = specifc_type.trim();
    messagePrefix = "Turn restriction (" + restriction + ") " + browseURL;
    if (supportedRestrictions.contains(restriction) == false) {
        log.warn(messagePrefix, "ignoring unsupported restriction type '" + restriction + "'");
        valid = false;
        return;
    }
    String dirInfo = "";
    if (restriction.contains("left"))
        dirInfo += "l";
    if (restriction.contains("right"))
        dirInfo += "r";
    if (restriction.contains("straight"))
        dirInfo += "s";
    if (restriction.endsWith("u_turn"))
        dirInfo += "u";
    if (dirInfo.length() > 1) {
        log.warn(messagePrefix, "ignoring unsupported restriction type '" + restriction + "'");
        valid = false;
        return;
    } else if (dirInfo.length() == 1) {
        dirIndicator = dirInfo.charAt(0);
    } else
        dirIndicator = '?';
    String type = getTag("type");
    if (type.startsWith("restriction:")) {
        exceptMask = (byte) 0xff;
        String vehicle = type.substring("restriction:".length());
        if (setExceptMask(vehicle, false) == false) {
            log.warn(messagePrefix, "ignoring unsupported '" + vehicle + "' in turn restriction");
            valid = false;
            return;
        }
    }
    String except = getTag("except");
    if (except != null) {
        for (String vehicle : except.split("[,;]")) {
            // be nice
            vehicle = vehicle.trim();
            setExceptMask(vehicle, true);
        }
    }
    for (String unsupportedTag : unsupportedTags) {
        if (getTag(unsupportedTag) != null) {
            log.warn(messagePrefix, "ignoring unsupported '" + unsupportedTag + "' tag");
        }
    }
    // evaluate members
    for (Map.Entry<String, Element> pair : getElements()) {
        String role = pair.getKey();
        Element el = pair.getValue();
        Coord location = null;
        if (viaCoord != null)
            location = viaCoord;
        else if (!fromWays.isEmpty() && !fromWays.get(0).getPoints().isEmpty())
            location = fromWays.get(0).getPoints().get(0);
        else if (!toWays.isEmpty() && !toWays.get(0).getPoints().isEmpty())
            location = toWays.get(0).getPoints().get(0);
        else if (!viaWays.isEmpty() && !viaWays.get(0).getPoints().isEmpty())
            location = viaWays.get(0).getPoints().get(0);
        if (location != null)
            messagePrefix = "Turn restriction (" + restriction + ") " + browseURL + " (at " + location.toOSMURL() + ")";
        if ("to".equals(role)) {
            if (!(el instanceof Way)) {
                log.warn(messagePrefix, "'to' member", el.toBrowseURL(), "is not a way but it should be");
            } else if (((Way) el).getPoints().isEmpty()) {
                log.warn(messagePrefix, "ignoring empty 'to' way", el.toBrowseURL());
            } else
                toWays.add((Way) el);
        } else if ("from".equals(role)) {
            if (!(el instanceof Way)) {
                log.warn(messagePrefix, "'from' member", el.toBrowseURL(), "is not a way but it should be");
            } else if (((Way) el).getPoints().isEmpty()) {
                log.warn(messagePrefix, "ignoring empty 'from' way", el.toBrowseURL());
            } else
                fromWays.add((Way) el);
        } else if ("via".equals(role)) {
            if (el instanceof Node) {
                if (viaCoord != null) {
                    log.warn(messagePrefix, "has extra 'via' node", el.toBrowseURL());
                    valid = false;
                } else
                    viaCoord = ((Node) el).getLocation();
            } else if (el instanceof Way) {
                if (viaCoord != null) {
                    log.warn(messagePrefix, "has extra 'via' way", el.toBrowseURL());
                    valid = false;
                } else
                    viaWays.add((Way) el);
            } else {
                log.warn(messagePrefix, "'via' member", el.toBrowseURL(), "is not a node or way");
            }
        } else if ("location_hint".equals(role)) {
        // relax - we don't care about this
        } else {
            log.warn(messagePrefix, "unknown member role '" + role + "'");
        }
    }
    if (!valid)
        return;
    if ("no_entry".equals(restriction) == false) {
        if (fromWays.size() > 1) {
            log.warn(messagePrefix, "multiple 'from' members are only accepted for no_entry restrictions");
            valid = false;
            return;
        }
    }
    if ("no_exit".equals(restriction) == false) {
        if (toWays.size() > 1) {
            log.warn(messagePrefix, "multiple 'to' members are only accepted for no_exit restrictions");
            valid = false;
            return;
        }
    }
    if (viaWays.isEmpty() && viaCoord == null && fromWays.size() == 1 && toWays.size() == 1) {
        Way fromWay = fromWays.get(0);
        Way toWay = toWays.get(0);
        List<Coord> fromPoints = fromWay.getPoints();
        List<Coord> toPoints = toWay.getPoints();
        int countSame = 0;
        for (Coord fp : fromPoints) {
            for (Coord tp : toPoints) {
                if (fp == tp) {
                    countSame++;
                    viaCoord = fp;
                }
            }
        }
        if (countSame > 1) {
            log.warn(messagePrefix, "lacks 'via' node and way and the 'from' (", fromWay.toBrowseURL(), ") and 'to' (", toWay.toBrowseURL(), ") ways connect in more than one place");
            valid = false;
        } else if (viaCoord == null) {
            log.warn(messagePrefix, "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' (" + toWay.toBrowseURL() + ") ways don't connect");
            valid = false;
        } else {
            if (fromPoints.get(0) != viaCoord && fromPoints.get(fromPoints.size() - 1) != viaCoord || toPoints.get(0) != viaCoord && toPoints.get(toPoints.size() - 1) != viaCoord) {
                log.warn(messagePrefix, "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' (" + toWay.toBrowseURL() + ") ways don't connect at an end point");
                valid = false;
            } else
                log.warn(messagePrefix, "lacks 'via' node (guessing it should be at", viaCoord.toOSMURL() + ", why don't you add it to the OSM data?)");
        }
    }
    if (fromWays.isEmpty()) {
        log.warn(messagePrefix, "lacks 'from' way");
        valid = false;
    }
    if (toWays.isEmpty()) {
        log.warn(messagePrefix, "lacks 'to' way");
        valid = false;
    }
    if ((fromWays.size() > 1 || toWays.size() > 1) && viaWays.isEmpty() == false) {
        log.warn(messagePrefix, "'via' way(s) are not supported with multiple 'from' or 'to' ways");
        valid = false;
    }
    if (!valid)
        return;
    for (List<Way> ways : Arrays.asList(fromWays, viaWays, toWays)) {
        for (Way way : ways) {
            if (way.getPoints().size() < 2) {
                log.warn(messagePrefix, "way", way.toBrowseURL(), "has less than 2 points, restriction is ignored");
                valid = false;
            } else {
                if (way.getPoints().get(0) == way.getPoints().get(way.getPoints().size() - 1)) {
                    if (ways == toWays && dirIndicator != '?')
                        // we try to determine the correct part in RoadNetwork
                        continue;
                    log.warn(messagePrefix, "way", way.toBrowseURL(), "starts and ends at same node, don't know which one to use");
                    valid = false;
                }
            }
        }
    }
    if (!valid)
        return;
    if (viaPoints.isEmpty() == false)
        viaCoord = viaPoints.get(0);
    if (viaCoord == null && viaWays.isEmpty()) {
        valid = false;
        return;
    }
    viaPoints.clear();
    Coord v1 = viaCoord;
    Coord v2 = viaCoord;
    if (viaWays.isEmpty() == false) {
        v1 = viaWays.get(0).getPoints().get(0);
        v2 = viaWays.get(0).getPoints().get(viaWays.get(0).getPoints().size() - 1);
    }
    // check if all from ways are connected at the given via point or with the given via ways
    for (Way fromWay : fromWays) {
        Coord e1 = fromWay.getPoints().get(0);
        Coord e2 = fromWay.getPoints().get(fromWay.getPoints().size() - 1);
        if (e1 == v1 || e2 == v1)
            viaCoord = v1;
        else if (e1 == v2 || e2 == v2)
            viaCoord = v2;
        else {
            log.warn(messagePrefix, "'from' way", fromWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
            valid = false;
        }
    }
    if (!valid)
        return;
    viaPoints.add(viaCoord);
    // check if via ways are connected in the given order
    for (int i = 0; i < viaWays.size(); i++) {
        Way way = viaWays.get(i);
        Coord v = viaPoints.get(viaPoints.size() - 1);
        if (way.getPoints().get(0) == v)
            v2 = way.getPoints().get(way.getPoints().size() - 1);
        else if (way.getPoints().get(way.getPoints().size() - 1) == v)
            v2 = way.getPoints().get(0);
        else {
            log.warn(messagePrefix, "'via' way", way.toBrowseURL(), "doesn't start or end at", v.toDegreeString());
            valid = false;
        }
        viaPoints.add(v2);
    }
    // check if all via points are inside the bounding box
    int countInside = 0;
    for (Coord via : viaPoints) {
        if (bbox.contains(via))
            ++countInside;
    }
    if (countInside == 0)
        valid = false;
    else if (countInside > 0 && countInside < viaPoints.size()) {
        log.warn(messagePrefix, "via way crosses tile boundary. Don't know how to save that, ignoring it");
        valid = false;
    }
    if (!valid)
        return;
    // check if all to ways are connected to via point or last via way
    Coord lastVia = viaPoints.get(viaPoints.size() - 1);
    for (Way toWay : toWays) {
        Coord e1 = toWay.getPoints().get(0);
        Coord e2 = toWay.getPoints().get(toWay.getPoints().size() - 1);
        if (e1 != lastVia && e2 != lastVia) {
            log.warn(messagePrefix, "'to' way", toWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
            valid = false;
        }
    }
    if (valid && !viaWays.isEmpty() && restriction.startsWith("only")) {
        log.warn(messagePrefix, "check: 'via' way(s) are used in", restriction, "restriction");
    }
    if (valid) {
        // make sure that via way(s) don't appear in the from or to lists
        for (Way w : viaWays) {
            if (fromWays.contains(w)) {
                log.warn(messagePrefix, "'via' way", w.toBrowseURL(), "appears also as 'from' way");
                valid = false;
            }
            if (toWays.contains(w)) {
                log.warn(messagePrefix, "'via' way", w.toBrowseURL(), "appears also as 'to' way");
                valid = false;
            }
        }
    }
    if (valid) {
        for (Way w : fromWays) fromWayIds.add(w.getId());
        for (Way w : toWays) toWayIds.add(w.getId());
        for (Way w : viaWays) {
            w.setViaWay(true);
            viaWayIds.add(w.getId());
        }
        for (Coord v : viaPoints) v.setViaNodeOfRestriction(true);
    }
}
Also used : CoordNode(uk.me.parabola.imgfmt.app.CoordNode) ArrayList(java.util.ArrayList) Coord(uk.me.parabola.imgfmt.app.Coord) Entry(java.util.Map.Entry) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap) Map(java.util.Map)

Example 48 with Coord

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

the class SeaGenerator method findIntesectionPoints.

/**
 * Find the points where the remaining shore line segments intersect with the
 * map boundary.
 *
 * @param shoreline The remaining shore line segments.
 * @param seaBounds The map boundary.
 * @param seaRelation If we are using a multi-polygon, this is it. Otherwise it will be null.
 * @return A map of the 'hits' where the shore line intersects the boundary.
 */
private NavigableMap<EdgeHit, Way> findIntesectionPoints(List<Way> shoreline, Area seaBounds, Relation seaRelation) {
    assert !generateSeaUsingMP || seaRelation != null;
    NavigableMap<EdgeHit, Way> hitMap = new TreeMap<EdgeHit, Way>();
    for (Way w : shoreline) {
        List<Coord> points = w.getPoints();
        Coord pStart = points.get(0);
        Coord pEnd = points.get(points.size() - 1);
        EdgeHit hStart = getEdgeHit(seaBounds, pStart);
        EdgeHit hEnd = getEdgeHit(seaBounds, pEnd);
        if (hStart == null || hEnd == null) {
            /*
				 * This problem occurs usually when the shoreline is cut by osmosis (e.g. country-extracts from geofabrik)
				 * There are two possibilities to solve this problem:
				 * 1. Close the way and treat it as an island. This is sometimes the best solution (Germany: Usedom at the
				 *    border to Poland)
				 * 2. Create a "sea sector" only for this shoreline segment. This may also be the best solution
				 *    (see German border to the Netherlands where the shoreline continues in the Netherlands)
				 * The first choice may lead to "flooded" areas, the second may lead to "triangles".
				 *
				 * Usually, the first choice is appropriate if the segment is "nearly" closed.
				 */
            double length = 0;
            Coord p0 = pStart;
            for (Coord p1 : points.subList(1, points.size() - 1)) {
                length += p0.distance(p1);
                p0 = p1;
            }
            boolean nearlyClosed = pStart.distance(pEnd) < 0.1 * length;
            if (nearlyClosed) {
                // close the way
                points.add(pStart);
                if (!FakeIdGenerator.isFakeId(w.getId())) {
                    Way w1 = new Way(w.getOriginalId());
                    w1.setFakeId();
                    w1.getPoints().addAll(w.getPoints());
                    // only copy the name tags
                    for (Entry<String, String> tagEntry : w.getTagEntryIterator()) {
                        if (tagEntry.getKey().equals("name") || tagEntry.getKey().contains("name"))
                            w1.addTag(tagEntry.getKey(), tagEntry.getValue());
                    }
                    w = w1;
                }
                w.addTag(landTag[0], landTag[1]);
                saver.addWay(w);
                if (generateSeaUsingMP) {
                    seaRelation.addElement("inner", w);
                }
            } else if (allowSeaSectors) {
                Way sea;
                if (seaRelation != null) {
                    sea = new Way(seaRelation.getOriginalId());
                    sea.setFakeId();
                } else
                    sea = new Way(FakeIdGenerator.makeFakeId());
                sea.getPoints().addAll(points);
                sea.addPoint(new Coord(pEnd.getLatitude(), pStart.getLongitude()));
                sea.addPoint(pStart);
                sea.addTag("natural", "sea");
                log.info("sea: ", sea);
                saver.addWay(sea);
                if (generateSeaUsingMP)
                    seaRelation.addElement("outer", sea);
                generateSeaBackground = false;
            } else if (extendSeaSectors) {
                // create additional points at next border to prevent triangles from point 2
                if (null == hStart) {
                    hStart = getNextEdgeHit(seaBounds, pStart);
                    w.getPoints().add(0, hStart.getPoint(seaBounds));
                }
                if (null == hEnd) {
                    hEnd = getNextEdgeHit(seaBounds, pEnd);
                    w.getPoints().add(hEnd.getPoint(seaBounds));
                }
                log.debug("hits (second try): ", hStart, hEnd);
                hitMap.put(hStart, w);
                hitMap.put(hEnd, null);
            } else {
                // show the coastline even though we can't produce
                // a polygon for the land
                w.addTag("natural", "coastline");
                if (w.hasIdenticalEndPoints() == false) {
                    log.error("adding sea shape that is not really closed");
                }
                saver.addWay(w);
            }
        } else {
            log.debug("hits: ", hStart, hEnd);
            hitMap.put(hStart, w);
            hitMap.put(hEnd, null);
        }
    }
    return hitMap;
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) TreeMap(java.util.TreeMap)

Example 49 with Coord

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

the class SeaGenerator method closeGaps.

private void closeGaps(List<Way> ways, Area bounds) {
    // maxCoastlineGap metres apart
    if (maxCoastlineGap > 0) {
        boolean changed = true;
        while (changed) {
            changed = false;
            for (Way w1 : ways) {
                if (w1.hasIdenticalEndPoints())
                    continue;
                List<Coord> points1 = w1.getPoints();
                Coord w1e = points1.get(points1.size() - 1);
                if (bounds.onBoundary(w1e))
                    continue;
                Way nearest = null;
                double smallestGap = Double.MAX_VALUE;
                for (Way w2 : ways) {
                    if (w1 == w2 || w2.hasIdenticalEndPoints())
                        continue;
                    List<Coord> points2 = w2.getPoints();
                    Coord w2s = points2.get(0);
                    if (bounds.onBoundary(w2s))
                        continue;
                    double gap = w1e.distance(w2s);
                    if (gap < smallestGap) {
                        nearest = w2;
                        smallestGap = gap;
                    }
                }
                if (nearest != null && smallestGap < maxCoastlineGap) {
                    Coord w2s = nearest.getPoints().get(0);
                    log.warn("Bridging " + (int) smallestGap + "m gap in coastline from " + w1e.toOSMURL() + " to " + w2s.toOSMURL());
                    Way wm;
                    if (FakeIdGenerator.isFakeId(w1.getId())) {
                        wm = w1;
                    } else {
                        wm = new Way(w1.getOriginalId());
                        wm.setFakeId();
                        ways.remove(w1);
                        ways.add(wm);
                        wm.getPoints().addAll(points1);
                        wm.copyTags(w1);
                    }
                    wm.getPoints().addAll(nearest.getPoints());
                    ways.remove(nearest);
                    // make a line that shows the filled gap
                    Way w = new Way(FakeIdGenerator.makeFakeId());
                    w.addTag("natural", "mkgmap:coastline-gap");
                    w.addPoint(w1e);
                    w.addPoint(w2s);
                    saver.addWay(w);
                    changed = true;
                    break;
                }
            }
        }
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord)

Example 50 with Coord

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

the class SeaGenerator method createInnerWays.

private boolean createInnerWays(Area seaBounds, List<Way> islands, NavigableMap<EdgeHit, Way> hitMap) {
    NavigableSet<EdgeHit> hits = hitMap.navigableKeySet();
    boolean shorelineReachesBoundary = false;
    while (!hits.isEmpty()) {
        long id = FakeIdGenerator.makeFakeId();
        Way w = new Way(id);
        saver.addWay(w);
        EdgeHit hit = hits.first();
        EdgeHit hFirst = hit;
        do {
            Way segment = hitMap.get(hit);
            log.info("current hit:", hit);
            EdgeHit hNext;
            if (segment != null) {
                // add the segment and get the "ending hit"
                log.info("adding:", segment);
                for (Coord p : segment.getPoints()) w.addPointIfNotEqualToLastPoint(p);
                hNext = getEdgeHit(seaBounds, segment.getPoints().get(segment.getPoints().size() - 1));
            } else {
                w.addPointIfNotEqualToLastPoint(hit.getPoint(seaBounds));
                hNext = hits.higher(hit);
                if (hNext == null)
                    hNext = hFirst;
                Coord p;
                if (hit.compareTo(hNext) < 0) {
                    log.info("joining: ", hit, hNext);
                    for (int i = hit.edge; i < hNext.edge; i++) {
                        EdgeHit corner = new EdgeHit(i, 1.0);
                        p = corner.getPoint(seaBounds);
                        log.debug("way: ", corner, p);
                        w.addPointIfNotEqualToLastPoint(p);
                    }
                } else if (hit.compareTo(hNext) > 0) {
                    log.info("joining: ", hit, hNext);
                    for (int i = hit.edge; i < 4; i++) {
                        EdgeHit corner = new EdgeHit(i, 1.0);
                        p = corner.getPoint(seaBounds);
                        log.debug("way: ", corner, p);
                        w.addPointIfNotEqualToLastPoint(p);
                    }
                    for (int i = 0; i < hNext.edge; i++) {
                        EdgeHit corner = new EdgeHit(i, 1.0);
                        p = corner.getPoint(seaBounds);
                        log.debug("way: ", corner, p);
                        w.addPointIfNotEqualToLastPoint(p);
                    }
                }
                w.addPointIfNotEqualToLastPoint(hNext.getPoint(seaBounds));
            }
            hits.remove(hit);
            hit = hNext;
        } while (!hits.isEmpty() && !hit.equals(hFirst));
        if (!w.hasIdenticalEndPoints())
            // close shape
            w.addPoint(w.getPoints().get(0));
        log.info("adding non-island landmass, hits.size()=" + hits.size());
        islands.add(w);
        shorelineReachesBoundary = true;
    }
    return shorelineReachesBoundary;
}
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