Search in sources :

Example 21 with MapLine

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

the class LineSplitterFilterTest method test.

private void test(List<Coord> points) {
    MapLine l = new MapLine();
    l.setPoints(points);
    FilterConfig config = new FilterConfig() {

        {
            setResolution(24);
            setLevel(0);
        }
    };
    LayerFilterChain chain = new LayerFilterChain(config);
    LineSplitterFilter filter = new LineSplitterFilter();
    filter.init(config);
    chain.addFilter(filter);
    TestFilter testFilter = new TestFilter(l);
    chain.addFilter(testFilter);
    chain.doFilter(l);
    testFilter.check();
}
Also used : MapLine(uk.me.parabola.mkgmap.general.MapLine) LayerFilterChain(uk.me.parabola.mkgmap.build.LayerFilterChain)

Example 22 with MapLine

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

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

the class MapArea method addLines.

/**
 * Add the lines, making sure that they are not too big for resolution
 * that we are working with.
 * @param src The map data.
 * @param resolution The current resolution of the layer.
 */
private void addLines(MapDataSource src, final int resolution) {
    // Split lines for size, such that it is appropriate for the
    // resolution that it is at.
    MapFilterChain chain = new MapFilterChain() {

        public void doFilter(MapElement element) {
            MapLine line = (MapLine) element;
            addLine(line);
        }
    };
    LineSizeSplitterFilter filter = new LineSizeSplitterFilter();
    FilterConfig config = new FilterConfig();
    config.setResolution(resolution);
    config.setBounds(bounds);
    filter.init(config);
    for (MapLine l : src.getLines()) {
        if (l.getMaxResolution() < resolution)
            continue;
        // %%% ??? if not appearing at this level no need to filter
        filter.doFilter(l, chain);
    }
}
Also used : MapElement(uk.me.parabola.mkgmap.general.MapElement) MapLine(uk.me.parabola.mkgmap.general.MapLine) LineSizeSplitterFilter(uk.me.parabola.mkgmap.filters.LineSizeSplitterFilter) FilterConfig(uk.me.parabola.mkgmap.filters.FilterConfig) MapFilterChain(uk.me.parabola.mkgmap.filters.MapFilterChain)

Example 24 with MapLine

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

the class OverviewBuilder method readLines.

/**
 * Read the lines from the .img file and add them to the overview map.
 * We read from the least detailed level (apart from the empty one).
 *
 * @param mapReader Map reader on the detailed .img file.
 */
private void readLines(MapReader mapReader) {
    Zoom[] levels = mapReader.getLevels();
    for (int l = 1; l < levels.length; l++) {
        int min = levels[l].getLevel();
        int res = levels[l].getResolution();
        List<Polyline> lineList = mapReader.linesForLevel(min);
        // System.out.println(lineList.size() + " lines in lowest resolution " + levels[1].getResolution());
        for (Polyline line : lineList) {
            if (log.isDebugEnabled())
                log.debug("got line", line);
            MapLine ml = new MapLine();
            List<Coord> points = line.getPoints();
            if (log.isDebugEnabled())
                log.debug("line point list", points);
            if (points.size() < 2)
                continue;
            ml.setType(line.getType());
            if (line.getLabel() != null)
                ml.setName(line.getLabel().getText());
            ml.setMaxResolution(res);
            ml.setMinResolution(res);
            ml.setPoints(points);
            overviewSource.addLine(ml);
        }
    }
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) MapLine(uk.me.parabola.mkgmap.general.MapLine) Polyline(uk.me.parabola.imgfmt.app.trergn.Polyline) Zoom(uk.me.parabola.imgfmt.app.trergn.Zoom) Point(uk.me.parabola.imgfmt.app.trergn.Point) MapPoint(uk.me.parabola.mkgmap.general.MapPoint)

Example 25 with MapLine

use of uk.me.parabola.mkgmap.general.MapLine 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)

Aggregations

MapLine (uk.me.parabola.mkgmap.general.MapLine)29 Coord (uk.me.parabola.imgfmt.app.Coord)16 MapPoint (uk.me.parabola.mkgmap.general.MapPoint)15 ArrayList (java.util.ArrayList)12 MapShape (uk.me.parabola.mkgmap.general.MapShape)10 MapRoad (uk.me.parabola.mkgmap.general.MapRoad)6 MapExitPoint (uk.me.parabola.mkgmap.general.MapExitPoint)4 Point (uk.me.parabola.imgfmt.app.trergn.Point)3 CoordNode (uk.me.parabola.imgfmt.app.CoordNode)2 FilterConfig (uk.me.parabola.mkgmap.filters.FilterConfig)2 Area (uk.me.parabola.imgfmt.app.Area)1 City (uk.me.parabola.imgfmt.app.lbl.City)1 LBLFile (uk.me.parabola.imgfmt.app.lbl.LBLFile)1 Zip (uk.me.parabola.imgfmt.app.lbl.Zip)1 GeneralRouteRestriction (uk.me.parabola.imgfmt.app.net.GeneralRouteRestriction)1 Numbers (uk.me.parabola.imgfmt.app.net.Numbers)1 ExtTypeAttributes (uk.me.parabola.imgfmt.app.trergn.ExtTypeAttributes)1 Polyline (uk.me.parabola.imgfmt.app.trergn.Polyline)1 Subdivision (uk.me.parabola.imgfmt.app.trergn.Subdivision)1 Zoom (uk.me.parabola.imgfmt.app.trergn.Zoom)1