Search in sources :

Example 1 with Numbers

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

the class ExtNumbers method calcSearchPositions.

/**
 * Try to simulate a Garmin address search for each number covered by the interval.
 * @param fullLength
 * @param searchPositions filled by this routine
 * @return false if calculation failed
 */
private boolean calcSearchPositions(double fullLength, TreeMap<Integer, Double> searchPositions) {
    Numbers ivl = getNumbers();
    for (int side = 0; side < 2; side++) {
        boolean left = side == 0;
        NumberStyle style = ivl.getNumberStyle(left);
        if (style != NumberStyle.NONE) {
            int start = ivl.getStart(left);
            int end = ivl.getEnd(left);
            int step = style == NumberStyle.BOTH ? 1 : 2;
            if (step != 1 && start % 2 != end % 2) {
                log.error("internal error, bad interval in optimization", this);
                return false;
            }
            if (start == end) {
                searchPositions.put(start, fullLength / 2);
            } else {
                int parts = Math.abs(end - start) / step;
                double partLen = fullLength / parts;
                if (start > end)
                    step = -step;
                int hn = start;
                double dist = 0;
                while (true) {
                    searchPositions.put(hn, dist);
                    if (hn == end)
                        break;
                    dist += partLen;
                    hn += step;
                }
                if (parts > 1)
                    assert Math.abs(fullLength - dist) < 0.1;
            }
        }
    }
    return true;
}
Also used : Numbers(uk.me.parabola.imgfmt.app.net.Numbers) NumberStyle(uk.me.parabola.imgfmt.app.net.NumberStyle)

Example 2 with Numbers

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

the class ExtNumbers method getNumberList.

/**
 * Return the intervals in the format used for the writer routines
 * @return
 */
public List<Numbers> getNumberList() {
    // do we have numbers?
    boolean foundNumbers = false;
    for (ExtNumbers curr = this; curr != null; curr = curr.next) {
        if (curr.hasNumbers()) {
            foundNumbers = true;
            break;
        }
    }
    if (!foundNumbers)
        return null;
    List<Numbers> list = new ArrayList<>();
    boolean headerWasReported = false;
    for (ExtNumbers curr = this; curr != null; curr = curr.next) {
        if (curr.hasNumbers() == false)
            continue;
        list.add(curr.getNumbers());
        if (log.isInfoEnabled()) {
            if (headerWasReported == false) {
                MapRoad road = curr.getRoad();
                if (road.getStreet() == null && road.getName() == null)
                    log.info("final numbers for", road, curr.housenumberRoad.getName(), "in", road.getCity());
                else
                    log.info("final numbers for", road, "in", road.getCity());
                headerWasReported = true;
            }
            Numbers cn = curr.getNumbers();
            log.info("Left: ", cn.getLeftNumberStyle(), cn.getIndex(), "Start:", cn.getLeftStart(), "End:", cn.getLeftEnd(), "numbers " + curr.getHouses(Numbers.LEFT));
            log.info("Right:", cn.getRightNumberStyle(), cn.getIndex(), "Start:", cn.getRightStart(), "End:", cn.getRightEnd(), "numbers " + curr.getHouses(Numbers.RIGHT));
        }
    }
    return list;
}
Also used : Numbers(uk.me.parabola.imgfmt.app.net.Numbers) ArrayList(java.util.ArrayList) MapRoad(uk.me.parabola.mkgmap.general.MapRoad)

Example 3 with Numbers

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

the class ExtNumbers method getNumbers.

public Numbers getNumbers() {
    if (numbers == null) {
        numbers = new Numbers();
        numbers.setIndex(nodeIndex);
        fillNumbers(Numbers.LEFT);
        fillNumbers(Numbers.RIGHT);
        if (!numbers.isEmpty()) {
            // TODO : remove
            verify(getHouses(Numbers.LEFT));
            // TODO : remove
            verify(getHouses(Numbers.RIGHT));
        }
    }
    return numbers;
}
Also used : Numbers(uk.me.parabola.imgfmt.app.net.Numbers)

Example 4 with Numbers

use of uk.me.parabola.imgfmt.app.net.Numbers 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 5 with Numbers

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

the class ExtNumbers method findGoodSplitPos.

private void findGoodSplitPos() {
    badNum = -1;
    worstHouse = null;
    boolean multipleZipOrCity = false;
    for (int side = 0; side < 2; side++) {
        boolean left = side == 0;
        List<HousenumberMatch> houses = getHouses(left);
        if (houses.size() <= 1)
            continue;
        if (multipleZipOrCity(left))
            multipleZipOrCity = true;
        for (HousenumberMatch house : houses) {
            int hn = house.getHousenumber();
            if (countOccurence(houses, hn) > 1)
                continue;
            ExtNumbers modIvl = simulateRemovalOfHouseNumber(hn, left);
            if (modIvl.isPlausible()) {
                badNum = hn;
                if (log.isDebugEnabled())
                    log.debug("splitpos details: single remove of", badNum, "results in plausible interval");
                return;
            }
        }
    }
    if (multipleZipOrCity)
        // unlikely
        return;
    // log.debug("did not yet find good split position");
    Numbers ivl = getNumbers();
    int[] firstBad = { -1, -1 };
    int[] lastBad = { -1, -1 };
    for (int side = 0; side < 2; side++) {
        boolean left = (side == 0);
        int step = 2;
        if (ivl.getNumberStyle(left) == NumberStyle.BOTH)
            step = 1;
        int s = ivl.getStart(left);
        int e = ivl.getEnd(left);
        int s2 = ivl.getStart(!left);
        int e2 = ivl.getEnd(!left);
        NumberStyle style2 = ivl.getNumberStyle(!left);
        for (int hn = Math.min(s, e); hn <= Math.max(s, e); hn += step) {
            if (style2 == NumberStyle.EVEN && hn % 2 == 1 || style2 == NumberStyle.ODD && hn % 2 == 0) {
                if (firstBad[side] < 0)
                    firstBad[side] = hn;
                lastBad[side] = hn;
                continue;
            }
            if (hn < Math.min(s2, e2) || hn > Math.max(s2, e2)) {
                if (firstBad[side] < 0)
                    firstBad[side] = hn;
                lastBad[side] = hn;
            }
        }
    }
    if (firstBad[0] == lastBad[0]) {
        badNum = firstBad[0];
        if (badNum >= 0)
            return;
    }
    if (firstBad[1] == lastBad[1]) {
        badNum = firstBad[1];
        if (badNum >= 0)
            return;
    }
    badNum = Math.max(firstBad[0], lastBad[0]);
    if (badNum == -1)
        badNum = Math.min(firstBad[1], lastBad[1]);
    if (log.isDebugEnabled())
        log.debug("splitpos details", Arrays.toString(firstBad), Arrays.toString(lastBad), "gives badNum", badNum);
}
Also used : Numbers(uk.me.parabola.imgfmt.app.net.Numbers) NumberStyle(uk.me.parabola.imgfmt.app.net.NumberStyle)

Aggregations

Numbers (uk.me.parabola.imgfmt.app.net.Numbers)13 ArrayList (java.util.ArrayList)5 Coord (uk.me.parabola.imgfmt.app.Coord)4 NumberStyle (uk.me.parabola.imgfmt.app.net.NumberStyle)4 MapRoad (uk.me.parabola.mkgmap.general.MapRoad)3 CityInfo (uk.me.parabola.mkgmap.general.CityInfo)2 HousenumberMatchByPosComparator (uk.me.parabola.mkgmap.osmstyle.housenumber.HousenumberGenerator.HousenumberMatchByPosComparator)2 NumberReader (func.lib.NumberReader)1 Int2IntOpenHashMap (it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap)1 Int2ObjectOpenHashMap (it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap)1 Long2ObjectOpenHashMap (it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap)1 LongArrayList (it.unimi.dsi.fastutil.longs.LongArrayList)1 BitSet (java.util.BitSet)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1 LinkedHashSet (java.util.LinkedHashSet)1 List (java.util.List)1 TreeMap (java.util.TreeMap)1 BitReader (uk.me.parabola.imgfmt.app.BitReader)1