Search in sources :

Example 11 with MapRoad

use of uk.me.parabola.mkgmap.general.MapRoad in project mkgmap by openstreetmap.

the class LineSizeSplitterFilter method doFilter.

/**
 * Keep track of the max dimensions of a line and split when they get too
 * big.
 *
 * @param element A map element.
 * @param next This is used to pass the possibly transformed element onward.
 */
public void doFilter(MapElement element, MapFilterChain next) {
    // We do not deal with shapes.
    assert !(element instanceof MapShape) && element instanceof MapLine;
    MapLine line = (MapLine) element;
    if (line.getBounds().getMaxDimension() < maxSize) {
        next.doFilter(element);
        return;
    }
    if (line instanceof MapRoad) {
        MapRoad road = ((MapRoad) line);
        log.error("Way " + road.getRoadDef() + " has a max dimension of " + line.getBounds().getMaxDimension() + " and is about to be split (routing will be broken)");
    }
    // ensure that all single lines do not exceed the maximum size
    // use a slightly decreased max size (-10) to get better results
    // in the subdivision creation
    List<Coord> points = splitLinesToMaxSize(line.getPoints(), maxSize - 10);
    log.debug("line bbox too big, splitting");
    MapLine l = line.copy();
    List<Coord> coords = new ArrayList<Coord>();
    boolean first = true;
    /**
     * Class to keep track of the dimensions.
     */
    class Dim {

        private int minLat;

        private int minLong;

        private int maxLat;

        private int maxLong;

        Dim() {
            reset();
        }

        private void reset() {
            minLat = Integer.MAX_VALUE;
            minLong = Integer.MAX_VALUE;
            maxLat = Integer.MIN_VALUE;
            maxLong = Integer.MIN_VALUE;
        }

        private void addToBounds(Coord co) {
            int lat = co.getLatitude();
            if (lat < minLat)
                minLat = lat;
            if (lat > maxLat)
                maxLat = lat;
            int lon = co.getLongitude();
            if (lon < minLong)
                minLong = lon;
            if (lon > maxLong)
                maxLong = lon;
        }

        private int getMaxDim() {
            int dx = maxLong - minLong;
            int dy = maxLat - minLat;
            return Math.max(dx, dy);
        }
    }
    Dim dim = new Dim();
    Coord prev = null;
    // Add points while not too big and then start again with a fresh line.
    for (Coord co : points) {
        dim.addToBounds(co);
        if (dim.getMaxDim() > maxSize) {
            if (first)
                log.debug("bigness saving first part");
            else
                log.debug("bigness saving next part");
            l.setPoints(coords);
            next.doFilter(l);
            l = line.copy();
            first = false;
            dim.reset();
            coords = new ArrayList<Coord>();
            coords.add(prev);
            dim.addToBounds(prev);
            dim.addToBounds(co);
        }
        coords.add(co);
        prev = co;
    }
    assert coords.size() > 1;
    if (coords.size() > 1) {
        log.debug("bigness saving a final part");
        l.setPoints(coords);
        next.doFilter(l);
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) MapLine(uk.me.parabola.mkgmap.general.MapLine) ArrayList(java.util.ArrayList) MapRoad(uk.me.parabola.mkgmap.general.MapRoad) MapShape(uk.me.parabola.mkgmap.general.MapShape)

Example 12 with MapRoad

use of uk.me.parabola.mkgmap.general.MapRoad in project mkgmap by openstreetmap.

the class HousenumberGenerator method generate.

/**
 * @param adder
 * @param naxNodeId the highest nodeId used before
 */
public void generate(LineAdder adder, int naxNodeId) {
    if (numbersEnabled) {
        MultiHashMap<MapRoad, HousenumberMatch> initialHousesForRoads = findClosestRoadsToHouse();
        identifyServiceRoads();
        handleInterpolationWays(initialHousesForRoads);
        List<HousenumberRoad> hnrList = createHousenumberRoads(initialHousesForRoads);
        initialHousesForRoads = null;
        log.info("found", hnrList.size(), "road candidates for address search");
        useAddrPlaceTag(hnrList);
        Map<MapRoad, HousenumberRoad> road2HousenumberRoadMap = new HashMap<>();
        for (HousenumberRoad hnr : hnrList) {
            road2HousenumberRoadMap.put(hnr.getRoad(), hnr);
        }
        Int2ObjectOpenHashMap<HashSet<MapRoad>> nodeId2RoadLists = new Int2ObjectOpenHashMap<>();
        for (MapRoad road : allRoads) {
            for (Coord co : road.getPoints()) {
                if (co.getId() == 0)
                    continue;
                HashSet<MapRoad> connectedRoads = nodeId2RoadLists.get(co.getId());
                if (connectedRoads == null) {
                    connectedRoads = new HashSet<>();
                    nodeId2RoadLists.put(co.getId(), connectedRoads);
                }
                connectedRoads.add(road);
            }
        }
        List<HousenumberRoad> addedRoads = new ArrayList<>();
        Iterator<HousenumberRoad> iter = hnrList.iterator();
        while (iter.hasNext()) {
            HousenumberRoad hnr = iter.next();
            List<HousenumberMatch> lostHouses = hnr.checkStreetName(road2HousenumberRoadMap, nodeId2RoadLists);
            for (HousenumberMatch house : lostHouses) {
                MapRoad r = house.getRoad();
                if (r != null) {
                    HousenumberRoad hnr2 = road2HousenumberRoadMap.get(r);
                    if (hnr2 == null) {
                        CityInfo ci = getCityInfos(r.getCity(), r.getRegion(), r.getCountry());
                        hnr2 = new HousenumberRoad(r, ci, Arrays.asList(house));
                        if (r.getZip() != null)
                            hnr2.setZipCodeInfo(getZipInfos(r.getZip()));
                        road2HousenumberRoadMap.put(r, hnr2);
                        addedRoads.add(hnr2);
                    } else {
                        hnr2.addHouse(house);
                    }
                }
            }
            if (hnr.getName() == null) {
                iter.remove();
                for (HousenumberMatch house : hnr.getHouses()) {
                    log.warn("found no plausible road name for address", house.toBrowseURL(), ", closest road id:", house.getRoad());
                }
            }
        }
        hnrList.addAll(addedRoads);
        // TODO: interpolate addr:interpolation houses
        removeDupsGroupedByCityAndName(hnrList);
        // group by street name and city
        TreeMap<String, TreeMap<CityInfo, List<HousenumberRoad>>> streetnameCityRoadMap = new TreeMap<>();
        for (HousenumberRoad hnr : hnrList) {
            TreeMap<CityInfo, List<HousenumberRoad>> cluster = streetnameCityRoadMap.get(hnr.getName());
            if (cluster == null) {
                cluster = new TreeMap<>();
                streetnameCityRoadMap.put(hnr.getName(), cluster);
            }
            List<HousenumberRoad> roadsInCluster = cluster.get(hnr.getRoadCityInfo());
            if (roadsInCluster == null) {
                roadsInCluster = new ArrayList<>();
                cluster.put(hnr.getRoadCityInfo(), roadsInCluster);
            }
            roadsInCluster.add(hnr);
        }
        for (Entry<String, TreeMap<CityInfo, List<HousenumberRoad>>> streetNameEntry : streetnameCityRoadMap.entrySet()) {
            String streetName = streetNameEntry.getKey();
            for (Entry<CityInfo, List<HousenumberRoad>> clusterEntry : streetNameEntry.getValue().entrySet()) {
                useInterpolationInfo(streetName, clusterEntry.getValue(), road2HousenumberRoadMap);
            }
            for (Entry<CityInfo, List<HousenumberRoad>> clusterEntry : streetNameEntry.getValue().entrySet()) {
                List<HousenumberRoad> roadsInCluster = clusterEntry.getValue();
                if (log.isDebugEnabled()) {
                    log.debug("processing road(s) with name", streetName, "in", clusterEntry.getKey());
                }
                for (HousenumberRoad hnr : roadsInCluster) {
                    hnr.buildIntervals();
                }
                boolean optimized = false;
                for (int loop = 0; loop < 10; loop++) {
                    for (HousenumberRoad hnr : roadsInCluster) {
                        hnr.checkIntervals();
                    }
                    checkWrongRoadAssignmments(roadsInCluster);
                    boolean changed = hasChanges(roadsInCluster);
                    if (!optimized && !changed) {
                        for (HousenumberRoad hnr : roadsInCluster) {
                            hnr.improveSearchResults();
                        }
                        changed = hasChanges(roadsInCluster);
                        optimized = true;
                    }
                    if (!changed)
                        break;
                }
                for (HousenumberRoad hnr : roadsInCluster) {
                    hnr.setNumbers();
                }
            }
        }
    }
    if (log.isInfoEnabled()) {
        for (HousenumberElem house : houseElems) {
            if (house.getRoad() == null) {
                if (house.getStreet() != null)
                    log.info("found no plausible road for house number element", house.toBrowseURL(), house.getStreet(), house.getSign());
                else
                    log.info("found no plausible road for house number element", house.toBrowseURL());
            }
        }
    }
    for (MapRoad r : allRoads) {
        if (log.isDebugEnabled()) {
            List<Numbers> finalNumbers = r.getRoadDef().getNumbersList();
            if (finalNumbers != null) {
                log.info("id:" + r.getRoadDef().getId(), ", final numbers,", r, "in", r.getCity());
                for (Numbers cn : finalNumbers) {
                    if (cn.isEmpty())
                        continue;
                    log.info("id:" + r.getRoadDef().getId(), ", Left: ", cn.getLeftNumberStyle(), cn.getIndex(), "Start:", cn.getLeftStart(), "End:", cn.getLeftEnd());
                    log.info("id:" + r.getRoadDef().getId(), ", Right:", cn.getRightNumberStyle(), cn.getIndex(), "Start:", cn.getRightStart(), "End:", cn.getRightEnd());
                }
            }
        }
        adder.add(r);
    }
}
Also used : CityInfo(uk.me.parabola.mkgmap.general.CityInfo) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Long2ObjectOpenHashMap(it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap) Int2ObjectOpenHashMap(it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap) Int2IntOpenHashMap(it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap) MultiHashMap(uk.me.parabola.util.MultiHashMap) LongArrayList(it.unimi.dsi.fastutil.longs.LongArrayList) ArrayList(java.util.ArrayList) Numbers(uk.me.parabola.imgfmt.app.net.Numbers) LongArrayList(it.unimi.dsi.fastutil.longs.LongArrayList) ArrayList(java.util.ArrayList) List(java.util.List) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) Int2ObjectOpenHashMap(it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap) MapRoad(uk.me.parabola.mkgmap.general.MapRoad) TreeMap(java.util.TreeMap) Coord(uk.me.parabola.imgfmt.app.Coord)

Example 13 with MapRoad

use of uk.me.parabola.mkgmap.general.MapRoad in project mkgmap by openstreetmap.

the class HousenumberGenerator method findRoadForInterpolatedHouses.

private static void findRoadForInterpolatedHouses(String streetName, List<HousenumberMatch> houses, List<HousenumberRoad> roadsInCluster) {
    if (houses.isEmpty())
        return;
    Collections.sort(houses, new HousenumberMatchByNumComparator());
    HousenumberMatch prev = null;
    for (HousenumberMatch house : houses) {
        if (house.isIgnored())
            continue;
        // make sure that we don't use an old match
        house.setDistance(Double.POSITIVE_INFINITY);
        house.setRoad(null);
        List<HousenumberMatch> matches = new ArrayList<>();
        for (HousenumberRoad hnr : roadsInCluster) {
            MapRoad r = hnr.getRoad();
            // make sure that we use the street info if available
            if (house.getPlace() != null) {
                if (house.getStreet() != null && r.getStreet() != null && house.getStreet().equals(r.getStreet()) == false)
                    continue;
            }
            HousenumberMatch test = new HousenumberMatch(house);
            findClosestRoadSegment(test, r);
            if (test.getRoad() != null && test.getGroup() != null || test.getDistance() < MAX_DISTANCE_TO_ROAD) {
                matches.add(test);
            }
        }
        if (matches.isEmpty()) {
            house.setIgnored(true);
            continue;
        }
        HousenumberMatch closest, best;
        best = closest = matches.get(0);
        if (matches.size() > 1) {
            // multiple roads, we assume that the closest is the best
            // but we may have to check the alternatives as well
            Collections.sort(matches, new HousenumberGenerator.HousenumberMatchByDistComparator());
            closest = matches.get(0);
            best = checkAngle(closest, matches);
        }
        house.setDistance(best.getDistance());
        house.setSegmentFrac(best.getSegmentFrac());
        house.setRoad(best.getRoad());
        house.setSegment(best.getSegment());
        for (HousenumberMatch altHouse : matches) {
            if (altHouse.getRoad() != best.getRoad() && altHouse.getDistance() < MAX_DISTANCE_TO_ROAD)
                house.addAlternativeRoad(altHouse.getRoad());
        }
        if (house.getRoad() == null) {
            house.setIgnored(true);
        } else {
            house.calcRoadSide();
        }
        // plausibility check for duplicate house numbers
        if (prev != null && prev.getHousenumber() == house.getHousenumber()) {
            // duplicate number (e.g. 10 and 10 or 10 and 10A or 10A and 10B)
            if (prev.getSign().equals(house.getSign())) {
                prev.setDuplicate(true);
                house.setDuplicate(true);
            }
        }
        if (house.getRoad() == null) {
            if (house.isIgnored() == false)
                log.warn("found no plausible road for house number element", house.toBrowseURL(), "(", streetName, house.getSign(), ")");
        }
        if (!house.isIgnored())
            prev = house;
    }
}
Also used : LongArrayList(it.unimi.dsi.fastutil.longs.LongArrayList) ArrayList(java.util.ArrayList) MapRoad(uk.me.parabola.mkgmap.general.MapRoad)

Example 14 with MapRoad

use of uk.me.parabola.mkgmap.general.MapRoad in project mkgmap by openstreetmap.

the class LineSplitterFilter method doFilter.

/**
 * If the line is short enough then we just pass it on straight away.
 * Otherwise we cut it into pieces that are short enough and hand them
 * on.
 *
 * @param element A map element.
 * @param next This is used to pass the possibly transformed element onward.
 */
public void doFilter(MapElement element, MapFilterChain next) {
    // We do not deal with shapes.
    assert !(element instanceof MapShape) && element instanceof MapLine;
    MapLine line = (MapLine) element;
    List<Coord> points = line.getPoints();
    int npoints = points.size();
    if (npoints <= MAX_POINTS_IN_LINE) {
        next.doFilter(element);
        return;
    }
    log.debug("line has too many points, splitting");
    if (line.isRoad() && level == 0 && isRoutable && log.isDebugEnabled()) {
        log.debug("Way " + ((MapRoad) line).getRoadDef() + " has more than " + MAX_POINTS_IN_LINE + " points and is about to be split");
    }
    boolean last = false;
    int wantedSize = (npoints < 2 * MAX_POINTS_IN_LINE) ? npoints / 2 + 1 : MAX_POINTS_IN_LINE;
    int pos = 0;
    while (true) {
        if (pos == 0)
            log.debug("saving first part");
        else if (!last)
            log.debug("saving next part");
        else
            log.debug("saving final part");
        MapLine l = line.copy();
        l.setPoints(new ArrayList<>(points.subList(pos, pos + wantedSize)));
        if (wantedSize < MAX_POINTS_IN_LINE / 2)
            log.error("size?", npoints, pos, wantedSize);
        if (!last && line instanceof MapRoad)
            ((MapRoad) l).setSegmentsFollowing(true);
        next.doFilter(l);
        if (last)
            break;
        // we start with the last point of previous part
        pos += wantedSize - 1;
        int remaining = npoints - pos;
        // make sure that the last parts have enough points
        if (remaining <= MAX_POINTS_IN_LINE) {
            last = true;
            wantedSize = remaining;
        } else if (remaining < 2 * MAX_POINTS_IN_LINE)
            wantedSize = remaining / 2 + 1;
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) MapLine(uk.me.parabola.mkgmap.general.MapLine) MapRoad(uk.me.parabola.mkgmap.general.MapRoad) MapShape(uk.me.parabola.mkgmap.general.MapShape)

Example 15 with MapRoad

use of uk.me.parabola.mkgmap.general.MapRoad in project mkgmap by openstreetmap.

the class HousenumberIvl method checkRoads2.

private boolean checkRoads2() {
    for (int i = 0; i < 2; i++) {
        if (knownHouses[i] == null) {
            log.error("internal error: housenumber matches not properly set", this);
            return false;
        }
        if (knownHouses[i].getRoad() == null || knownHouses[i].getDistance() > 100) {
            log.warn("cannot find any reasonable road for both nodes, ignoring them", streetName, this);
            return false;
        }
    }
    if (knownHouses[0].getRoad().getRoadDef().getId() == knownHouses[1].getRoad().getRoadDef().getId()) {
        if (knownHouses[0].getRoad() != knownHouses[1].getRoad()) {
            // special case: interval goes along clipped road, data is probably OK
            hasMultipleRoads = true;
            return true;
        }
        for (MapRoad r : knownHouses[0].getAlternativeRoads()) {
            if (r.getRoadDef().getId() == knownHouses[0].getRoad().getRoadDef().getId()) {
                // special case: interval may go along clipped road, data is probably OK
                hasMultipleRoads = true;
                return true;
            }
        }
    }
    MapRoad bestRoad = null;
    // make sure that the closest road is one with a matching name
    for (int i = 0; i < 2; i++) {
        while (streetName.equals(knownHouses[i].getRoad().getStreet()) == false && knownHouses[i].hasAlternativeRoad()) {
            HousenumberMatch testx = new HousenumberMatch(knownHouses[i]);
            MapRoad r = knownHouses[i].getAlternativeRoads().remove(0);
            if (streetName.equals(r.getStreet())) {
                HousenumberGenerator.findClosestRoadSegment(testx, r);
                if (testx.getDistance() < MAX_INTERPOLATION_DISTANCE_TO_ROAD) {
                    copyRoadData(testx, knownHouses[i]);
                }
            }
        }
    }
    List<MapRoad> toTest = new ArrayList<>();
    toTest.add(knownHouses[0].getRoad());
    toTest.add(knownHouses[1].getRoad());
    for (MapRoad r : knownHouses[0].getAlternativeRoads()) {
        if (knownHouses[1].getAlternativeRoads().contains(r))
            toTest.add(r);
    }
    HousenumberMatch[] test = new HousenumberMatch[2];
    HousenumberMatch[] closest = new HousenumberMatch[2];
    boolean foundSingleRoad = false;
    for (MapRoad r : toTest) {
        if (streetName.equals(r.getStreet()) == false)
            continue;
        foundSingleRoad = true;
        for (int i = 0; i < 2; i++) {
            test[i] = knownHouses[i];
            if (test[i].getRoad() != r) {
                test[i] = new HousenumberMatch(knownHouses[i]);
                HousenumberGenerator.findClosestRoadSegment(test[i], r);
                test[i].calcRoadSide();
            }
            if (test[i].getRoad() == null || test[i].getDistance() > MAX_INTERPOLATION_DISTANCE_TO_ROAD) {
                foundSingleRoad = false;
                break;
            }
        }
        if (foundSingleRoad) {
            if (test[0].isLeft() != test[1].isLeft()) {
                foundSingleRoad = false;
                continue;
            }
            int s0 = test[0].getSegment();
            int s1 = test[1].getSegment();
            // check if the road and the addr:interpolation way are nearly parallel lines
            double angle1 = Utils.getAngle(test[0].getClosestPointOnRoad(), points.get(0), points.get(1));
            if (Math.abs(angle1) < 30) {
                foundSingleRoad = false;
                HousenumberMatch testx = new HousenumberMatch(test[0]);
                for (int s = Math.min(s0, s1); s <= Math.max(s0, s1); s++) {
                    if (s != test[0].getSegment()) {
                        HousenumberGenerator.findClosestRoadSegment(testx, r, s, s + 1);
                        angle1 = Utils.getAngle(testx.getClosestPointOnRoad(), points.get(0), points.get(1));
                        if (Math.abs(angle1) >= 30 && testx.getDistance() < 2 * test[0].getDistance()) {
                            test[0] = testx;
                            foundSingleRoad = true;
                            break;
                        }
                    }
                }
            }
            double angle2 = Utils.getAngle(points.get(points.size() - 2), points.get(points.size() - 1), test[1].getClosestPointOnRoad());
            if (Math.abs(angle2) < 30) {
                foundSingleRoad = false;
                HousenumberMatch testx = new HousenumberMatch(test[1]);
                for (int s = Math.min(s0, s1); s <= Math.max(s0, s1); s++) {
                    if (s != test[1].getSegment()) {
                        HousenumberGenerator.findClosestRoadSegment(testx, r, s, s + 1);
                        angle2 = Utils.getAngle(points.get(points.size() - 2), points.get(points.size() - 1), testx.getClosestPointOnRoad());
                        if (Math.abs(angle2) >= 30 && testx.getDistance() < 2 * test[1].getDistance()) {
                            test[1] = testx;
                            foundSingleRoad = true;
                            break;
                        }
                    }
                }
            }
        }
        if (foundSingleRoad) {
            if (r.isNamedByHousenumberProcessing() == false)
                break;
            // the closest road was originally unnamed , try to find one that is named in OSM
            if (bestRoad == null) {
                bestRoad = r;
                closest[0] = test[0];
                closest[1] = test[1];
            }
        }
    }
    if (!foundSingleRoad && bestRoad != null) {
        // not matching road name in original OSM data, use the closest
        foundSingleRoad = true;
        test[0] = closest[0];
        test[1] = closest[1];
    }
    if (!foundSingleRoad) {
        if (streetName.equals(knownHouses[0].getRoad().getStreet()) == false || streetName.equals(knownHouses[1].getRoad().getStreet()) == false) {
            log.warn("cannot find reasonable road for both nodes", streetName, this);
            return false;
        }
        hasMultipleRoads = true;
        return true;
    }
    // we found the road that should be used for interpolation
    roadForInterpolatedHouses = test[0].getRoad();
    // we found a single plausible road, make sure that both nodes are using it
    for (int i = 0; i < 2; i++) {
        if (knownHouses[i].getRoad() != test[i].getRoad() || knownHouses[i].getSegment() != test[i].getSegment()) {
            copyRoadData(test[i], knownHouses[i]);
            knownHouses[i].forgetAlternativeRoads();
        }
        if (knownHouses[i].getSegmentFrac() < 0 || knownHouses[i].getSegmentFrac() > 1) {
            hasMultipleRoads = true;
        }
    }
    if (knownHouses[0].isLeft() != knownHouses[1].isLeft()) {
        log.warn("addr:interpolation way crosses road", streetName, this);
        return false;
    }
    return true;
}
Also used : ArrayList(java.util.ArrayList) MapRoad(uk.me.parabola.mkgmap.general.MapRoad)

Aggregations

MapRoad (uk.me.parabola.mkgmap.general.MapRoad)16 ArrayList (java.util.ArrayList)11 Coord (uk.me.parabola.imgfmt.app.Coord)9 MapLine (uk.me.parabola.mkgmap.general.MapLine)6 MapPoint (uk.me.parabola.mkgmap.general.MapPoint)5 LongArrayList (it.unimi.dsi.fastutil.longs.LongArrayList)4 MapShape (uk.me.parabola.mkgmap.general.MapShape)4 Int2ObjectOpenHashMap (it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap)3 HashMap (java.util.HashMap)3 HashSet (java.util.HashSet)3 LinkedHashSet (java.util.LinkedHashSet)3 Numbers (uk.me.parabola.imgfmt.app.net.Numbers)3 CityInfo (uk.me.parabola.mkgmap.general.CityInfo)3 Int2IntOpenHashMap (it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap)2 Long2ObjectOpenHashMap (it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 List (java.util.List)2 CoordNode (uk.me.parabola.imgfmt.app.CoordNode)2 MapExitPoint (uk.me.parabola.mkgmap.general.MapExitPoint)2 MultiHashMap (uk.me.parabola.util.MultiHashMap)2