Search in sources :

Example 21 with Coord

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

the class ExtNumbers method splitInterval.

/**
 * Split an interval to remove overlaps
 * 1) detect the optimal split position
 * 2) calculate the new intervals
 * @return
 */
private ExtNumbers splitInterval() {
    if (log.isDebugEnabled())
        log.debug("trying to split", this, "so that", badNum, "is not contained");
    boolean doSplit = false;
    Numbers origNumbers = getNumbers();
    if (origNumbers.countMatches(badNum) == 0) {
        if (log.isDebugEnabled())
            log.debug("badNum", badNum, "is not contained in", this);
        return this;
    }
    // create an test interval to find out which side contains the  bad number
    Numbers testNumbers = new Numbers();
    testNumbers.setNumbers(Numbers.LEFT, origNumbers.getLeftNumberStyle(), origNumbers.getLeftStart(), origNumbers.getLeftEnd());
    boolean left = (testNumbers.countMatches(badNum) > 0);
    List<HousenumberMatch> before = new ArrayList<>();
    List<HousenumberMatch> after = new ArrayList<>();
    List<HousenumberMatch> toSplit = getHouses(left);
    boolean inc = (origNumbers.getEnd(left) > origNumbers.getStart(left));
    BitSet segmentsBefore = new BitSet();
    BitSet segmentsAfter = new BitSet();
    for (HousenumberMatch house : toSplit) {
        List<HousenumberMatch> target;
        if (house.getHousenumber() < badNum) {
            target = inc ? before : after;
        } else if (house.getHousenumber() > badNum) {
            target = inc ? after : before;
        } else {
            int s = origNumbers.getStart(left);
            target = (s == badNum) ? before : after;
        }
        target.add(house);
        if (target == before) {
            segmentsBefore.set(house.getSegment());
        } else {
            segmentsAfter.set(house.getSegment());
        }
    }
    if (before.isEmpty() || after.isEmpty())
        return this;
    if (log.isDebugEnabled())
        log.debug("todo: find best method to separate", before, "and", after);
    HousenumberMatch house1 = before.get(before.size() - 1);
    HousenumberMatch house2 = after.get(0);
    List<HousenumberMatch> testOrder = new ArrayList<>();
    testOrder.add(house1);
    testOrder.add(house2);
    Collections.sort(testOrder, new HousenumberMatchByPosComparator());
    if (testOrder.get(0) != house1) {
        log.info("order indicates random case or missing road!", this);
        housenumberRoad.setRandom(true);
    }
    int splitSegment = -1;
    if (house1.getSegment() != house2.getSegment()) {
        // simple case: change point
        if (log.isDebugEnabled())
            log.debug("simple case: change point to number node between", house1, house2);
        // what point is best?, use beginning of 2nd for now
        splitSegment = house2.getSegment();
        doSplit = true;
    } else {
        int seg = house1.getSegment();
        Coord c1 = getRoad().getPoints().get(seg);
        Coord c2 = getRoad().getPoints().get(seg + 1);
        double segmentLength = c1.distance(c2);
        Coord toAdd = null;
        boolean addOK = true;
        double wantedFraction = (house1.getSegmentFrac() + house2.getSegmentFrac()) / 2;
        // handle cases where perpendicular is not on the road
        if (wantedFraction <= 0) {
            wantedFraction = 0;
            toAdd = new Coord(c1);
        } else if (wantedFraction >= 1) {
            wantedFraction = 1;
            toAdd = new Coord(c2);
        }
        double usedFraction = wantedFraction;
        if (toAdd == null) {
            Coord wanted = c1.makeBetweenPoint(c2, wantedFraction);
            log.debug("possible solution: split segment with length", formatLen(segmentLength), "near", formatLen(wantedFraction * segmentLength));
            toAdd = rasterLineNearPoint(c1, c2, wanted, true);
            if (toAdd != null) {
                if (toAdd.equals(c1)) {
                    toAdd = new Coord(c1);
                    usedFraction = 0.0;
                } else if (toAdd.equals(c2)) {
                    toAdd = new Coord(c2);
                    usedFraction = 0;
                } else {
                    addOK = checkLineDistortion(c1, c2, toAdd);
                    if (addOK)
                        usedFraction = HousenumberGenerator.getFrac(c1, c2, toAdd);
                    else
                        toAdd = null;
                }
            }
        }
        if (toAdd == null) {
            double len1 = wantedFraction * segmentLength;
            double len2 = (1 - wantedFraction) * segmentLength;
            if (Math.min(len1, len2) < MAX_LOCATE_ERROR) {
                if (len1 < len2) {
                    toAdd = new Coord(c1);
                    usedFraction = 0.0;
                } else {
                    toAdd = new Coord(c2);
                    usedFraction = 1.0;
                }
            }
        }
        if (toAdd == null) {
            log.error("internal error, cannot split", this);
        }
        if (toAdd != null) {
            if (log.isDebugEnabled()) {
                log.debug("solution: split segment with length", formatLen(segmentLength), "at", formatLen(usedFraction * segmentLength));
                double distToLine = toAdd.getDisplayedCoord().distToLineSegment(c1.getDisplayedCoord(), c2.getDisplayedCoord());
                log.info("adding number node at", toAdd.toDegreeString(), "to split, dist to line is", formatLen(distToLine));
            }
            doSplit = true;
            splitSegment = seg + 1;
            addAsNumberNode(splitSegment, toAdd);
            this.endInRoad++;
            for (HousenumberMatch house : before) {
                if (house.getSegment() >= seg) {
                    HousenumberGenerator.findClosestRoadSegment(house, getRoad(), seg, splitSegment);
                }
            }
            for (HousenumberMatch house : after) {
                if (house.getSegment() < splitSegment)
                    HousenumberGenerator.findClosestRoadSegment(house, getRoad(), splitSegment, splitSegment + 1);
                else
                    house.setSegment(house.getSegment() + 1);
            }
            // the other side
            recalcHousePositions(getHouses(!left));
        }
    }
    if (doSplit) {
        ExtNumbers en1 = split(splitSegment);
        ExtNumbers en2 = en1.next;
        if (en1.getHouses(Numbers.LEFT).size() + en2.getHouses(Numbers.LEFT).size() != getHouses(Numbers.LEFT).size() || en1.getHouses(Numbers.RIGHT).size() + en2.getHouses(Numbers.RIGHT).size() != getHouses(Numbers.RIGHT).size()) {
            log.error("internal error, lost houses");
        }
        log.info("number node added in street", getRoad(), getNumbers(), "==>", en1.getNumbers(), "+", en2.getNumbers());
        return en1;
    }
    return this;
}
Also used : Numbers(uk.me.parabola.imgfmt.app.net.Numbers) Coord(uk.me.parabola.imgfmt.app.Coord) HousenumberMatchByPosComparator(uk.me.parabola.mkgmap.osmstyle.housenumber.HousenumberGenerator.HousenumberMatchByPosComparator) ArrayList(java.util.ArrayList) BitSet(java.util.BitSet)

Example 22 with Coord

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

the class ExtNumbers method tryAddNumberNode.

/**
 * Try to add a number node.
 * We may change an existing point to a number node or add a new
 * number node. A new node might be between the existing ones
 * or a duplicate of one of them.
 * @return
 */
private ExtNumbers tryAddNumberNode(int reason) {
    String action;
    if (endInRoad - startInRoad > 1)
        action = "change";
    else {
        if (getRoad().getPoints().size() + 1 > LineSplitterFilter.MAX_POINTS_IN_LINE) {
            log.warn("can't change intervals, road has already", LineSplitterFilter.MAX_POINTS_IN_LINE, "points");
            // can't add a node
            return this;
        }
        Coord c1 = getRoad().getPoints().get(startInRoad);
        Coord c2 = getRoad().getPoints().get(startInRoad + 1);
        if (c1.equals(c2)) {
            return dupNode(0, SR_FIX_ERROR);
        }
        double segmentLength = c1.distance(c2);
        int countAfterEnd = 0, countBeforeStart = 0;
        double minFraction0To1 = 2;
        double maxFraction0To1 = -1;
        for (int side = 0; side < 2; side++) {
            boolean left = side == 0;
            List<HousenumberMatch> houses = getHouses(left);
            for (HousenumberMatch house : houses) {
                if (house.getSegmentFrac() < 0)
                    ++countBeforeStart;
                else if (house.getSegmentFrac() > 1)
                    ++countAfterEnd;
                else {
                    if (minFraction0To1 > house.getSegmentFrac())
                        minFraction0To1 = house.getSegmentFrac();
                    if (maxFraction0To1 < house.getSegmentFrac())
                        maxFraction0To1 = house.getSegmentFrac();
                }
            }
        }
        // special cases: perpendicular not on the road
        if (countBeforeStart > 0) {
            return dupNode(0, SR_SPLIT_ROAD_END);
        }
        if (countAfterEnd > 0) {
            return dupNode(1, SR_SPLIT_ROAD_END);
        }
        // try to find a good split point depending on the split reason
        double wantedFraction, midFraction;
        wantedFraction = midFraction = (minFraction0To1 + maxFraction0To1) / 2;
        Coord toAdd = null;
        // dist to first
        double len1 = segmentLength * minFraction0To1;
        double len2 = segmentLength * maxFraction0To1;
        double len3 = (1 - maxFraction0To1) * segmentLength;
        if (reason == SR_FIX_ERROR && worstHouse != null) {
            wantedFraction = worstHouse.getSegmentFrac();
            if (wantedFraction < minFraction0To1 || wantedFraction > maxFraction0To1) {
                log.error("internal error, worst house not found", this, worstHouse);
            }
        }
        boolean allowSplitBetween = true;
        boolean forceEmpty = false;
        List<Double> wantedFractions = new ArrayList<>();
        if (reason == SR_OPT_LEN) {
            if (log.isDebugEnabled()) {
                if (maxFraction0To1 != minFraction0To1) {
                    log.debug("trying to find good split point, houses are between", formatLen(len1), "and", formatLen(len2), "in segment with", formatLen(segmentLength));
                } else
                    log.debug("trying to find good split point, houses are at", formatLen(len1), "in segment with", formatLen(segmentLength));
            }
            if (len2 - len1 < 10 && getHouses(Numbers.LEFT).size() <= 1 && getHouses(Numbers.RIGHT).size() <= 1) {
                // one house or two opposite houses
                // we try to split so that the house(s) are near the middle of one part
                wantedFraction = midFraction * 2 - (midFraction > 0.5 ? 1 : 0);
                allowSplitBetween = false;
            } else {
                if (len1 > MAX_LOCATE_ERROR / 2) {
                    // create empty segment at start
                    wantedFractions.add(minFraction0To1 * 0.999);
                    forceEmpty = true;
                }
                if (len3 > MAX_LOCATE_ERROR / 2) {
                    // create empty segment at end
                    if (!wantedFractions.isEmpty() && len3 > len1)
                        wantedFractions.add(0, maxFraction0To1 * 1.001);
                    else
                        wantedFractions.add(maxFraction0To1 * 1.001);
                    forceEmpty = true;
                }
            }
        }
        if (wantedFractions.isEmpty())
            wantedFractions.add(wantedFraction);
        double usedFraction = 0;
        double bestDist = Double.MAX_VALUE;
        for (int w = 0; w < wantedFractions.size(); w++) {
            wantedFraction = wantedFractions.get(w);
            double partLen = wantedFraction * segmentLength;
            double shorterLen = Math.min(partLen, segmentLength - partLen);
            if (shorterLen < 10) {
                if (reason == SR_FIX_ERROR && minFraction0To1 == maxFraction0To1)
                    return dupNode(midFraction, SR_FIX_ERROR);
                double splitFrac = len1 < len3 ? minFraction0To1 : maxFraction0To1;
                return dupNode(splitFrac, SR_OPT_LEN);
            }
            double expectedError = c1.getDisplayedCoord().distance(new Coord(c1.getLatitude() + 1, c1.getLongitude()));
            double maxDistBefore = expectedError;
            double maxDistAfter = expectedError;
            if (wantedFraction < minFraction0To1) {
                maxDistAfter = 0;
            }
            if (wantedFraction > maxFraction0To1) {
                maxDistBefore = 0;
            }
            for (; ; ) {
                Coord wanted = c1.makeBetweenPoint(c2, wantedFraction);
                Map<Double, List<Coord>> candidates = rasterLineNearPoint2(c1, c2, wanted, maxDistBefore, maxDistAfter);
                boolean foundGood = false;
                for (Entry<Double, List<Coord>> entry : candidates.entrySet()) {
                    if (foundGood)
                        break;
                    bestDist = entry.getKey();
                    for (Coord candidate : entry.getValue()) {
                        toAdd = candidate;
                        usedFraction = HousenumberGenerator.getFrac(c1, c2, toAdd);
                        if (usedFraction <= 0 || usedFraction >= 1)
                            toAdd = null;
                        else if (usedFraction > minFraction0To1 && wantedFraction < minFraction0To1 || usedFraction < maxFraction0To1 && wantedFraction > maxFraction0To1) {
                            toAdd = null;
                        } else if (allowSplitBetween == false && usedFraction > minFraction0To1 && usedFraction < maxFraction0To1) {
                            toAdd = null;
                        } else {
                            if (bestDist > 0.2) {
                                double angle = Utils.getDisplayedAngle(c1, toAdd, c2);
                                if (Math.abs(angle) > 3) {
                                    toAdd = null;
                                    continue;
                                }
                            }
                            foundGood = true;
                            break;
                        }
                    }
                }
                if (foundGood) {
                    break;
                }
                toAdd = null;
                boolean tryAgain = false;
                if (maxDistBefore > 0 && maxDistBefore < segmentLength * wantedFraction) {
                    maxDistBefore *= 2;
                    tryAgain = true;
                }
                if (maxDistAfter > 0 && maxDistAfter < segmentLength * (1 - wantedFraction)) {
                    maxDistAfter *= 2;
                    tryAgain = true;
                }
                if (!tryAgain)
                    break;
            }
            if (toAdd != null)
                break;
        }
        boolean addOK = true;
        if (toAdd == null)
            addOK = false;
        else {
            toAdd.incHighwayCount();
            if (log.isDebugEnabled()) {
                log.debug("spliting road segment", startInRoad, "at", formatLen(usedFraction * segmentLength));
            }
        }
        if (!addOK) {
            if (reason == SR_FIX_ERROR && minFraction0To1 == maxFraction0To1)
                return dupNode(midFraction, SR_FIX_ERROR);
            if (Math.min(len1, len3) < MAX_LOCATE_ERROR) {
                double splitFrac = midFraction;
                if (splitFrac <= 0.5) {
                    if (splitFrac * segmentLength > MAX_LOCATE_ERROR)
                        splitFrac = Math.max(minFraction0To1, MAX_LOCATE_ERROR / segmentLength);
                } else {
                    if ((1 - splitFrac) * segmentLength > MAX_LOCATE_ERROR)
                        splitFrac = Math.min(maxFraction0To1, (segmentLength - MAX_LOCATE_ERROR) / segmentLength);
                }
                return dupNode(splitFrac, SR_OPT_LEN);
            }
            if (reason == SR_FIX_ERROR)
                log.warn("can't fix error in interval", this);
            else if (log.isDebugEnabled())
                log.debug("can't improve search result", this);
            return this;
        }
        if (log.isInfoEnabled())
            log.info("adding number node at", toAdd.toDegreeString(), "to split, dist to line is", formatLen(bestDist));
        action = "add";
        this.endInRoad = addAsNumberNode(startInRoad + 1, toAdd);
        int forcedSegment = -1;
        if (forceEmpty) {
            if (wantedFraction < minFraction0To1)
                forcedSegment = startInRoad + 1;
            else if (wantedFraction > maxFraction0To1)
                forcedSegment = startInRoad;
        }
        if (forcedSegment >= 0) {
            setSegment(forcedSegment, getHouses(Numbers.LEFT));
            setSegment(forcedSegment, getHouses(Numbers.RIGHT));
        } else {
            this.recalcHousePositions(getHouses(Numbers.LEFT));
            this.recalcHousePositions(getHouses(Numbers.RIGHT));
        }
    }
    int splitSegment = (startInRoad + endInRoad) / 2;
    if (worstHouse != null) {
        if (worstHouse.getSegment() == startInRoad)
            splitSegment = startInRoad + 1;
        else if (worstHouse.getSegment() == endInRoad - 1)
            splitSegment = worstHouse.getSegment();
    } else if (endInRoad - startInRoad > 2) {
        int firstSegWithHouses = endInRoad;
        int lastSegWithHouses = -1;
        for (int side = 0; side < 2; side++) {
            boolean left = side == 0;
            List<HousenumberMatch> houses = getHouses(left);
            for (HousenumberMatch house : houses) {
                int s = house.getSegment();
                if (s < firstSegWithHouses)
                    firstSegWithHouses = s;
                if (s > lastSegWithHouses)
                    lastSegWithHouses = s;
            }
        }
        splitSegment = (firstSegWithHouses + lastSegWithHouses) / 2;
        if (splitSegment == startInRoad)
            splitSegment++;
    }
    ExtNumbers en1 = split(splitSegment);
    ExtNumbers en2 = en1.next;
    if (reason == SR_OPT_LEN) {
    // TODO: fill gaps, e.g. if split results in O,1,9 -> O,1,1 + O,9,9 ?
    }
    if ("add".equals(action))
        log.info("number node added in street", getRoad(), getNumbers(), "==>", en1.getNumbers(), "+", en2.getNumbers());
    else
        log.info("point changed to number node in street", getRoad(), getNumbers(), "==>", en1.getNumbers(), "+", en2.getNumbers());
    return en1;
}
Also used : ArrayList(java.util.ArrayList) Coord(uk.me.parabola.imgfmt.app.Coord) ArrayList(java.util.ArrayList) List(java.util.List)

Example 23 with Coord

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

the class HousenumberGenerator method identifyServiceRoads.

/**
 * process option --x-name-service-roads=n
 * The program identifies unnamed roads which are only connected to one
 * road with a name or to multiple roads with the same name. The process is
 * repeated n times. If n > 1 the program will also use unnamed roads which
 * are connected to unnamed roads if those are connected to named roads.
 * Higher values for n mean deeper search, but reasonable values are
 * probably between 1 and 5.
 *
 * These roads are then used for house number processing like the named
 * ones. If house numbers are assigned to these roads, they are named so
 * that address search will find them.
 */
private void identifyServiceRoads() {
    Int2ObjectOpenHashMap<String> roadNamesByNodeIds = new Int2ObjectOpenHashMap<>();
    HashMap<MapRoad, List<Coord>> coordNodesUnnamedRoads = new HashMap<>();
    HashSet<Integer> unclearNodeIds = new HashSet<>();
    long t1 = System.currentTimeMillis();
    List<MapRoad> unnamedRoads = new ArrayList<>();
    for (MapRoad road : allRoads) {
        if (road.isSkipHousenumberProcessing())
            continue;
        if (road.getStreet() == null) {
            // the road probably has a ref. We assume these are not service roads.
            if (road.getName() == null) {
                unnamedRoads.add(road);
                List<Coord> nodes = new ArrayList<>();
                for (Coord co : road.getPoints()) {
                    if (co.getId() != 0)
                        nodes.add(co);
                }
                coordNodesUnnamedRoads.put(road, nodes);
            }
        } else {
            identifyNodes(road.getPoints(), road.getStreet(), roadNamesByNodeIds, unclearNodeIds);
        }
    }
    int numUnnamedRoads = unnamedRoads.size();
    long t2 = System.currentTimeMillis();
    if (log.isDebugEnabled())
        log.debug("identifyServiceRoad step 1 took", (t2 - t1), "ms, found", roadNamesByNodeIds.size(), "nodes to check and", numUnnamedRoads, "unnamed roads");
    long t3 = System.currentTimeMillis();
    int named = 0;
    for (int pass = 1; pass <= nameSearchDepth; pass++) {
        int unnamed = 0;
        List<MapRoad> namedRoads = new ArrayList<>();
        for (int j = 0; j < unnamedRoads.size(); j++) {
            MapRoad road = unnamedRoads.get(j);
            if (road == null)
                continue;
            unnamed++;
            List<Coord> coordNodes = coordNodesUnnamedRoads.get(road);
            String name = null;
            for (Coord co : coordNodes) {
                if (unclearNodeIds.contains(co.getId())) {
                    name = null;
                    // don't process again
                    unnamedRoads.set(j, null);
                    break;
                }
                String possibleName = roadNamesByNodeIds.get(co.getId());
                if (possibleName == null)
                    continue;
                if (name == null)
                    name = possibleName;
                else if (name.equals(possibleName) == false) {
                    name = null;
                    // don't process again
                    unnamedRoads.set(j, null);
                    break;
                }
            }
            if (name != null) {
                named++;
                road.setStreet(name);
                namedRoads.add(road);
                // don't process again
                unnamedRoads.set(j, null);
            }
        }
        for (MapRoad road : namedRoads) {
            road.setNamedByHousenumberProcessing(true);
            String name = road.getStreet();
            if (log.isDebugEnabled())
                log.debug("pass", pass, "using unnamed road for housenumber processing,id=", road.getRoadDef().getId(), ":", name);
            List<Coord> coordNodes = coordNodesUnnamedRoads.get(road);
            identifyNodes(coordNodes, name, roadNamesByNodeIds, unclearNodeIds);
        }
        if (namedRoads.isEmpty())
            break;
        if (log.isDebugEnabled())
            log.debug("pass", pass, unnamed, named);
    }
    long t4 = System.currentTimeMillis();
    if (log.isDebugEnabled()) {
        log.debug("indentifyServiceRoad step 2 took", (t4 - t3), "ms, found a name for", named, "of", numUnnamedRoads, "roads");
    }
    return;
}
Also used : Int2ObjectOpenHashMap(it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap) 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) MapRoad(uk.me.parabola.mkgmap.general.MapRoad) Coord(uk.me.parabola.imgfmt.app.Coord) LongArrayList(it.unimi.dsi.fastutil.longs.LongArrayList) ArrayList(java.util.ArrayList) List(java.util.List) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 24 with Coord

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

the class HousenumberGenerator method findClosestRoadSegment.

/**
 * Fill/overwrite the fields in house which depend on the assigned road.
 */
public static void findClosestRoadSegment(HousenumberMatch house, MapRoad r, int firstSeg, int stopSeg) {
    Coord cx = house.getLocation();
    double oldDist = house.getDistance();
    MapRoad oldRoad = house.getRoad();
    house.setRoad(null);
    house.setDistance(Double.POSITIVE_INFINITY);
    boolean foundGroupLink = false;
    int end = Math.min(r.getPoints().size(), stopSeg + 1);
    for (int node = firstSeg; node + 1 < end; node++) {
        Coord c1 = r.getPoints().get(node);
        Coord c2 = r.getPoints().get(node + 1);
        double frac = getFrac(c1, c2, cx);
        double dist = distanceToSegment(c1, c2, cx, frac);
        if (house.getGroup() != null && house.getGroup().linkNode == c1) {
            if (c1.highPrecEquals(c2) == false) {
                log.debug("block doesn't have zero length segment! Road:", r, house);
            }
            foundGroupLink = true;
            house.setDistance(dist);
            house.setSegmentFrac(frac);
            house.setRoad(r);
            house.setSegment(node);
            break;
        } else if (dist < house.getDistance()) {
            house.setDistance(dist);
            house.setSegmentFrac(frac);
            house.setRoad(r);
            house.setSegment(node);
        }
    }
    if (house.getGroup() != null && house.getGroup().linkNode != null && foundGroupLink == false) {
        log.debug(r, house, "has a group but the link was not found, should only happen after split of zero-length-segment");
    }
    if (oldRoad == r) {
        if (house.getDistance() > MAX_DISTANCE_TO_ROAD + 2.5 && oldDist <= MAX_DISTANCE_TO_ROAD) {
            log.warn("line distorted? Road segment was moved by more than", String.format("%.2f m", 2.5), ", from address", r, house.getSign());
        }
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) MapRoad(uk.me.parabola.mkgmap.general.MapRoad)

Example 25 with Coord

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

the class HousenumberGroup method housesFormAGroup.

public static boolean housesFormAGroup(HousenumberMatch house1, HousenumberMatch house2) {
    if (house1.isIgnored() || house2.isIgnored())
        return false;
    if (house1.getRoad() != house2.getRoad()) {
        log.error("internal error, group check with houses on different roads?", house1.getElement().getId(), house2.getElement().getId());
        return false;
    }
    if (house1.getSegment() > house2.getSegment()) {
        HousenumberMatch help = house1;
        house1 = house2;
        house2 = help;
    }
    double distBetweenHouses = house1.getLocation().distance(house2.getLocation());
    if (distBetweenHouses == 0)
        return true;
    double minDistToRoad = Math.min(house1.getDistance(), house2.getDistance());
    double maxDistToRoad = Math.max(house1.getDistance(), house2.getDistance());
    double distOnRoad = house2.getDistOnRoad(house1);
    if (house1.getSegment() != house2.getSegment()) {
        if (minDistToRoad > 40 && distBetweenHouses < CLOSE_HOUSES_DIST)
            return true;
        // not the same segment, the distance on road may be misleading when segments have a small angle
        // and the connection point is a bit more away
        Coord c1 = house1.getLocation();
        Coord c2 = house2.getLocation();
        Coord closest1 = house1.getClosestPointOnRoad();
        Coord closest2 = house2.getClosestPointOnRoad();
        double frac1 = HousenumberGenerator.getFrac(closest1, closest2, c1);
        double frac2 = HousenumberGenerator.getFrac(closest1, closest2, c2);
        double segLen = closest1.distance(closest2);
        if (frac1 < 0)
            frac1 = 0;
        if (frac2 < 0)
            frac2 = 0;
        if (frac1 > 1)
            frac1 = 1;
        if (frac2 > 1)
            frac2 = 1;
        double distOnRoadSimple = (Math.max(frac1, frac2) - Math.min(frac1, frac2)) * segLen;
        if (distOnRoadSimple != distOnRoad) {
            // log.debug("distOnRoad recalculation:", house1.getRoad(),house1,house2,distOnRoad,"--->",distOnRoadSimple);
            distOnRoad = distOnRoadSimple;
        }
    }
    if (distOnRoad <= 0) {
        return true;
    }
    // two houses form a group when the distance on road is short
    // how short? The closer the houses are to the road, the shorter
    double toleranceDistOnRoad = 5 + maxDistToRoad / 10;
    if (distOnRoad > toleranceDistOnRoad) {
        return false;
    }
    double deltaDistToRoad = maxDistToRoad - minDistToRoad;
    double ratio2 = deltaDistToRoad / distBetweenHouses;
    // road are on a straight line
    if (ratio2 > 0.9)
        return true;
    if (ratio2 < 0.666)
        return false;
    return true;
}
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