Search in sources :

Example 21 with MapShape

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

the class MapArea method addSize.

/**
 * Add an estimate of the size that will be required to hold this element
 * if it should be displayed at the given resolution.  We also keep track
 * of the number of <i>active</i> elements here ie elements that will be
 * shown because they are at a resolution at least as great as the resolution
 * of the area.
 *
 * @param el The element containing the minimum resolution that it will be
 * displayed at.
 * @param kind What kind of element this is KIND_POINT etc.
 */
private void addSize(MapElement el, int kind) {
    int res = el.getMinResolution();
    if (res > areaResolution || res > MAX_RESOLUTION)
        return;
    ++splittableCount;
    int numPoints;
    int numElements;
    switch(kind) {
        case POINT_KIND:
        case XT_POINT_KIND:
            // Points are predictably less than 10 bytes.
            sizes[kind] += 9;
            if (!el.hasExtendedType()) {
                if (((MapPoint) el).isCity())
                    nActiveIndPoints++;
                else
                    nActivePoints++;
            }
            break;
        case LINE_KIND:
        case XT_LINE_KIND:
            // Estimate the size taken by lines and shapes as a constant plus
            // a factor based on the number of points.
            numPoints = PredictFilterPoints.predictedMaxNumPoints(((MapLine) el).getPoints(), areaResolution, // assume MapBuilder.doRoads is true. subDiv.getZoom().getLevel() == 0 is maximum resolution
            ((MapLine) el).isRoad() && areaResolution == MAX_RESOLUTION);
            if (numPoints <= 1 && !((MapLine) el).isRoad())
                return;
            numElements = 1 + ((numPoints - 1) / LineSplitterFilter.MAX_POINTS_IN_LINE);
            // very pessimistic, typically less than 2 bytes are needed for one point
            sizes[kind] += numElements * 11 + numPoints * 4;
            if (!el.hasExtendedType())
                nActiveLines += numElements;
            break;
        case SHAPE_KIND:
        case XT_SHAPE_KIND:
            // see canSplit() above
            ++splittableCount;
            // Estimate the size taken by lines and shapes as a constant plus
            // a factor based on the number of points.
            numPoints = PredictFilterPoints.predictedMaxNumPoints(((MapShape) el).getPoints(), areaResolution, false);
            if (numPoints <= 3)
                return;
            numElements = 1 + ((numPoints - 1) / PolygonSplitterFilter.MAX_POINT_IN_ELEMENT);
            // very pessimistic, typically less than 2 bytes are needed for one point
            sizes[kind] += numElements * 11 + numPoints * 4;
            if (!el.hasExtendedType())
                nActiveShapes += numElements;
            break;
        default:
            log.error("should not be here");
            assert false;
            break;
    }
}
Also used : MapLine(uk.me.parabola.mkgmap.general.MapLine) MapPoint(uk.me.parabola.mkgmap.general.MapPoint) MapShape(uk.me.parabola.mkgmap.general.MapShape) MapPoint(uk.me.parabola.mkgmap.general.MapPoint)

Example 22 with MapShape

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

the class OverviewBuilder method addMapCoverageArea.

/**
 * Add an area that shows the area covered by a detailed map.  This can
 * be an arbitary shape, although at the current time we only support
 * rectangles.
 *
 * @param finfo Information about a detail map.
 */
private void addMapCoverageArea(FileInfo finfo) {
    Area bounds = finfo.getBounds();
    List<Coord> points = bounds.toCoords();
    for (Coord co : points) {
        overviewSource.addToBounds(co);
    }
    // Create the tile coverage rectangle
    MapShape bg = new MapShape();
    bg.setType(0x4a);
    bg.setPoints(points);
    bg.setMinResolution(0);
    bg.setName(finfo.getDescription() + '\u001d' + finfo.getMapname());
    overviewSource.addShape(bg);
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) Area(uk.me.parabola.imgfmt.app.Area) MapShape(uk.me.parabola.mkgmap.general.MapShape)

Example 23 with MapShape

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

the class LinePreparerFilter method doFilter.

/**
 * @param element A map element that will be a line or a polygon.
 * @param next This is used to pass the element onward.
 */
public void doFilter(MapElement element, MapFilterChain next) {
    MapLine line = (MapLine) element;
    int numPoints = line.getPoints().size();
    if (line instanceof MapShape && numPoints >= PolygonSplitterFilter.MAX_POINT_IN_ELEMENT)
        throw new MustSplitException();
    boolean first = true;
    int minPointsRequired = (element instanceof MapShape) ? 3 : 2;
    if (minPointsRequired == 3 && line.getPoints().get(0).equals(line.getPoints().get(numPoints - 1)))
        ++minPointsRequired;
    int lastLat = 0;
    int lastLong = 0;
    int numPointsEncoded = 1;
    // fields to keep track of the largest delta values
    int[] maxBits = { 0, 0 };
    int[] maxBits2nd = { 0, 0 };
    int[] maxBitsPos = { 0, 0 };
    for (int i = 0; i < numPoints; i++) {
        Coord co = line.getPoints().get(i);
        int lat = subdiv.roundLatToLocalShifted(co.getLatitude());
        int lon = subdiv.roundLonToLocalShifted(co.getLongitude());
        if (first) {
            lastLat = lat;
            lastLong = lon;
            first = false;
            continue;
        }
        // compute normalized differences
        // -2^(shift-1) <= dx, dy < 2^(shift-1)
        // XXX: relies on the fact that java integers are 32 bit signed
        final int offset = 8 + shift;
        int dx = (lon - lastLong) << offset >> offset;
        int dy = (lat - lastLat) << offset >> offset;
        lastLong = lon;
        lastLat = lat;
        if (dx == 0 && dy == 0) {
            if (!line.isRoad() || (co.getId() == 0 && co.isNumberNode() == false))
                continue;
        }
        ++numPointsEncoded;
        if (numPointsEncoded >= minPointsRequired && element instanceof MapShape == false)
            break;
        // find out largest and 2nd largest delta for both dx and dy
        for (int k = 0; k < 2; k++) {
            int nBits = LinePreparer.bitsNeeded((k == 0) ? dx : dy);
            if (nBits > maxBits2nd[k]) {
                if (nBits > maxBits[k]) {
                    maxBits2nd[k] = maxBits[k];
                    maxBits[k] = nBits;
                    maxBitsPos[k] = i;
                } else
                    maxBits2nd[k] = nBits;
            }
        }
    }
    if (numPointsEncoded < minPointsRequired)
        return;
    if (minPointsRequired >= 3) {
        // check if we can optimise shape by rotating
        // so that the line segment that requires the highest number of bits
        // is not encoded and thus fewer bits
        // are required for all points
        // TODO: maybe add additional points to further reduce max. delta values
        // or reverse order if largest delta is negative
        int maxReduction = 0;
        int rotation = 0;
        for (int k = 0; k < 2; k++) {
            int delta = maxBits[k] - maxBits2nd[k];
            // prefer largest delta, then smallest rotation
            if (delta > maxReduction || delta == maxReduction && rotation > maxBitsPos[k]) {
                maxReduction = delta;
                rotation = maxBitsPos[k];
            }
        }
        /*
			int savedBits = (numPoints-1 * maxReduction);
			if (savedBits > 100){
				System.out.println("rotation of shape saves " + savedBits + " bits");
			}
			*/
        if (rotation != 0) {
            List<Coord> points = line.getPoints();
            if (minPointsRequired == 4)
                points.remove(numPoints - 1);
            Collections.rotate(points, -rotation);
            if (minPointsRequired == 4)
                points.add(points.get(0));
        }
    }
    next.doFilter(element);
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) MapLine(uk.me.parabola.mkgmap.general.MapLine) MapShape(uk.me.parabola.mkgmap.general.MapShape)

Example 24 with MapShape

use of uk.me.parabola.mkgmap.general.MapShape 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 25 with MapShape

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

the class PolygonSplitterBase method split.

/**
 * Split the given shape and place the resulting shapes in the outputs list.
 * @param shape The original shape (that is too big).
 * @param outputs The output list.
 */
protected void split(MapShape shape, List<MapShape> outputs) {
    int dividingLine = 0;
    boolean isLongitude = false;
    Area bounds = shape.getBounds();
    if (bounds.getWidth() > bounds.getHeight()) {
        isLongitude = true;
        Area[] tmpAreas = bounds.split(2, 1, shift);
        dividingLine = tmpAreas != null ? tmpAreas[0].getMaxLong() : (bounds.getMinLong() + bounds.getWidth() / 2);
    } else {
        Area[] tmpAreas = bounds.split(1, 2, shift);
        dividingLine = tmpAreas != null ? tmpAreas[0].getMaxLat() : (bounds.getMinLat() + bounds.getHeight() / 2);
    }
    List<List<Coord>> subShapePoints = new ArrayList<>();
    ShapeSplitter.splitShape(shape.getPoints(), dividingLine << Coord.DELTA_SHIFT, isLongitude, subShapePoints, subShapePoints, null);
    for (List<Coord> subShape : subShapePoints) {
        MapShape s = shape.copy();
        s.setPoints(subShape);
        outputs.add(s);
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) Area(uk.me.parabola.imgfmt.app.Area) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList) MapShape(uk.me.parabola.mkgmap.general.MapShape)

Aggregations

MapShape (uk.me.parabola.mkgmap.general.MapShape)27 Coord (uk.me.parabola.imgfmt.app.Coord)15 MapPoint (uk.me.parabola.mkgmap.general.MapPoint)14 ArrayList (java.util.ArrayList)11 MapLine (uk.me.parabola.mkgmap.general.MapLine)10 Point (uk.me.parabola.imgfmt.app.trergn.Point)5 Area (uk.me.parabola.imgfmt.app.Area)4 MapRoad (uk.me.parabola.mkgmap.general.MapRoad)4 MapExitPoint (uk.me.parabola.mkgmap.general.MapExitPoint)3 IntArrayList (it.unimi.dsi.fastutil.ints.IntArrayList)2 Long2ObjectOpenHashMap (it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap)2 List (java.util.List)2 FilterConfig (uk.me.parabola.mkgmap.filters.FilterConfig)2 IdentityHashMap (java.util.IdentityHashMap)1 GeneralRouteRestriction (uk.me.parabola.imgfmt.app.net.GeneralRouteRestriction)1 Polygon (uk.me.parabola.imgfmt.app.trergn.Polygon)1 Subdivision (uk.me.parabola.imgfmt.app.trergn.Subdivision)1 Zoom (uk.me.parabola.imgfmt.app.trergn.Zoom)1 DouglasPeuckerFilter (uk.me.parabola.mkgmap.filters.DouglasPeuckerFilter)1 LinePreparerFilter (uk.me.parabola.mkgmap.filters.LinePreparerFilter)1