Search in sources :

Example 6 with Area

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

the class ElementQuadTreeNode method split.

/**
 * Splits this quadtree node into 4 subnodes.
 */
private void split() {
    if (bounds.getHeight() <= 5 || bounds.getWidth() <= 5) {
        log.error("Do not split more due to too small bounds: " + bounds);
        return;
    }
    int halfLat = (bounds.getMinLat() + bounds.getMaxLat()) / 2;
    int halfLong = (bounds.getMinLong() + bounds.getMaxLong()) / 2;
    children = new ElementQuadTreeNode[4];
    Area[] childBounds = new Area[4];
    childBounds[0] = new Area(bounds.getMinLat(), bounds.getMinLong(), halfLat, halfLong);
    childBounds[1] = new Area(halfLat, bounds.getMinLong(), bounds.getMaxLat(), halfLong);
    childBounds[2] = new Area(bounds.getMinLat(), halfLong, halfLat, bounds.getMaxLong());
    childBounds[3] = new Area(halfLat, halfLong, bounds.getMaxLat(), bounds.getMaxLong());
    List<Map<Element, List<Coord>>> childElems = new ArrayList<Map<Element, List<Coord>>>(4);
    for (int i = 0; i < 4; i++) {
        childElems.add(new HashMap<Element, List<Coord>>());
    }
    for (Entry<Element, List<Coord>> elem : elementMap.entrySet()) {
        if (elem.getKey() instanceof Node) {
            Node node = (Node) elem.getKey();
            for (int i = 0; i < childBounds.length; i++) {
                if (childBounds[i].contains(node.getLocation())) {
                    childElems.get(i).put(node, EMPTY_LIST);
                    break;
                }
            }
        } else if (elem.getKey() instanceof Way) {
            List<List<Coord>> points = new ArrayList<List<Coord>>(4);
            for (int i = 0; i < 4; i++) {
                // usually ways are quite local
                // therefore there is a high probability that only one child is covered
                // dim the new list as the old list
                points.add(new ArrayList<Coord>(elem.getValue().size()));
            }
            for (Coord c : elem.getValue()) {
                for (int i = 0; i < childBounds.length; i++) {
                    if (childBounds[i].contains(c)) {
                        points.get(i).add(c);
                        break;
                    }
                }
            }
            for (int i = 0; i < 4; i++) {
                if (points.get(i).isEmpty() == false) {
                    childElems.get(i).put(elem.getKey(), points.get(i));
                }
            }
        }
    }
    for (int i = 0; i < 4; i++) {
        children[i] = new ElementQuadTreeNode(childBounds[i], childElems.get(i));
    }
    elementMap = null;
}
Also used : Element(uk.me.parabola.mkgmap.reader.osm.Element) Node(uk.me.parabola.mkgmap.reader.osm.Node) ArrayList(java.util.ArrayList) Way(uk.me.parabola.mkgmap.reader.osm.Way) Coord(uk.me.parabola.imgfmt.app.Coord) Area(uk.me.parabola.imgfmt.app.Area) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map)

Example 7 with Area

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

the class ElementQuadTreeNode method get.

/**
 * Retrieves all elements that intersects the given polygon.
 * @param polygon the polygon
 * @param resultList results are stored in this collection
 * @return the resultList
 */
public Set<Element> get(ElementQuadTreePolygon polygon, Set<Element> resultList) {
    if (isEmpty()) {
        return resultList;
    }
    if (polygon.getBbox().intersects(getBounds())) {
        if (isLeaf()) {
            for (Entry<Element, List<Coord>> elem : elementMap.entrySet()) {
                if (resultList.contains(elem.getKey())) {
                    continue;
                }
                if (elem.getKey() instanceof Node) {
                    Node n = (Node) elem.getKey();
                    Coord c = n.getLocation();
                    if (polygon.getArea().contains(c.getLongitude(), c.getLatitude())) {
                        resultList.add(n);
                    }
                } else if (elem.getKey() instanceof Way) {
                    for (Coord c : elem.getValue()) {
                        if (polygon.getArea().contains(c.getLongitude(), c.getLatitude())) {
                            resultList.add(elem.getKey());
                            break;
                        }
                    }
                }
            }
        } else {
            for (ElementQuadTreeNode child : children) {
                if (child.isEmpty() == false && polygon.getArea().intersects(child.getBoundsAsRectangle())) {
                    java.awt.geom.Area subArea = (java.awt.geom.Area) polygon.getArea().clone();
                    subArea.intersect(Java2DConverter.createBoundsArea(new Area(child.getBounds().getMinLat() - 1, child.getBounds().getMinLong() - 1, child.getBounds().getMaxLat() + 1, child.getBounds().getMaxLong() + 1)));
                    child.get(new ElementQuadTreePolygon(subArea), resultList);
                }
            }
        }
    }
    return resultList;
}
Also used : Element(uk.me.parabola.mkgmap.reader.osm.Element) Node(uk.me.parabola.mkgmap.reader.osm.Node) Way(uk.me.parabola.mkgmap.reader.osm.Way) Coord(uk.me.parabola.imgfmt.app.Coord) Area(uk.me.parabola.imgfmt.app.Area) ArrayList(java.util.ArrayList) List(java.util.List)

Example 8 with Area

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

the class LineClipperTest method testAllInside.

/**
 * If all the lines are inside, then it should just return null to indicate that.
 */
@Test
public void testAllInside() {
    Area a = new Area(100, 100, 200, 200);
    List<Coord> l = Arrays.asList(new Coord(102, 110), new Coord(150, 150), new Coord(190, 195));
    List<List<Coord>> list = LineClipper.clip(a, l);
    assertNull("all lines inside", list);
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) Area(uk.me.parabola.imgfmt.app.Area) List(java.util.List) Test(org.junit.Test)

Example 9 with Area

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

the class LineClipperTest method testExampleClip.

/**
 * This is the example as given on the referenced web page.
 * We now use integers instead of floats so the 101.425 from the
 * example is just 101 here.
 */
@Test
public void testExampleClip() {
    Area a = new Area(60, 70, 150, 230);
    Coord[] co = { new Coord(20, 30), new Coord(160, 280) };
    List<List<Coord>> listList = LineClipper.clip(a, Arrays.asList(co));
    assertTrue("list should be empty", !listList.isEmpty());
    Coord[] result = { new Coord(60, 101), new Coord(132, 230) };
    assertArrayEquals("example result", result, listList.get(0).toArray());
}
Also used : Coord(uk.me.parabola.imgfmt.app.Coord) Area(uk.me.parabola.imgfmt.app.Area) List(java.util.List) Test(org.junit.Test)

Example 10 with Area

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

the class MapArea method split.

/**
 * Split this area into several pieces. All the map elements are reallocated
 * to the appropriate subarea.  Usually this instance would now be thrown
 * away and the new sub areas used instead.
 * <p>
 * This code is dealing with a lot of factors that govern the splitting, eg:
 *  splitPolygonsIntoArea,
 *  tooSmallToDivide,
 *  item.minResolution vs. areaResolution,
 *  number/size of items and the limits of a subDivision,
 *  items that exceed maximum subDivision on their own,
 *  items that extend up to 50% outside the current area,
 *  items bigger than this.
 *
 * @param nx The number of pieces in the x (longitude) direction.
 * @param ny The number of pieces in the y direction.
 * @param bounds the bounding box that is used to create the areas.
 * @param tooSmallToDivide the area is small and data overflows; split into overflow areas
 *
 * @return An array of the new MapArea's or null if can't split.
 */
public MapArea[] split(int nx, int ny, Area bounds, boolean tooSmallToDivide) {
    int resolutionShift = MAX_RESOLUTION - areaResolution;
    Area[] areas = bounds.split(nx, ny, resolutionShift);
    if (areas == null) {
        // Failed to split!
        if (log.isDebugEnabled()) {
            // see what is here
            for (MapLine e : this.lines) if (e.getMinResolution() <= areaResolution)
                log.debug("line. locn=", e.getPoints().get(0).toOSMURL(), " type=", uk.me.parabola.mkgmap.reader.osm.GType.formatType(e.getType()), " name=", e.getName(), " min=", e.getMinResolution(), " max=", e.getMaxResolution());
            for (MapShape e : this.shapes) if (e.getMinResolution() <= areaResolution)
                log.debug("shape. locn=", e.getPoints().get(0).toOSMURL(), " type=", uk.me.parabola.mkgmap.reader.osm.GType.formatType(e.getType()), " name=", e.getName(), " min=", e.getMinResolution(), " max=", e.getMaxResolution(), " full=", e.getFullArea(), " calc=", uk.me.parabola.mkgmap.filters.ShapeMergeFilter.calcAreaSizeTestVal(e.getPoints()));
        // the main culprits are lots of bits of sea and coastline in an overview map (res 12)
        }
        return null;
    }
    MapArea[] mapAreas = new MapArea[nx * ny];
    log.info("Splitting area " + bounds + " into " + nx + "x" + ny + " pieces at resolution " + areaResolution, tooSmallToDivide);
    List<MapArea> addedAreas = new ArrayList<>();
    for (int i = 0; i < mapAreas.length; i++) {
        mapAreas[i] = new MapArea(areas[i], areaResolution, splitPolygonsIntoArea);
        if (log.isDebugEnabled())
            log.debug("area before", mapAreas[i].getBounds());
    }
    int xbaseHp = areas[0].getMinLong() << Coord.DELTA_SHIFT;
    int ybaseHp = areas[0].getMinLat() << Coord.DELTA_SHIFT;
    int dxHp = areas[0].getWidth() << Coord.DELTA_SHIFT;
    int dyHp = areas[0].getHeight() << Coord.DELTA_SHIFT;
    // Some of the work done by PolygonSubdivSizeSplitterFilter now done here
    final int maxSize = Math.min((1 << 24) - 1, Math.max(MapSplitter.MAX_DIVISION_SIZE << (MAX_RESOLUTION - areaResolution), 0x8000));
    /**
     * These constants control when an item (shape unless splitPolygonsIntoArea or line) is shifted into its own MapArea/SubDivision.
     * Generally, an item is allowed into the MapArea chosen by centre provided it is no bigger than the MapArea.
     * This means that there could be big items near the edges of the MapArea that stick out by almost half, so must
     * ensure that this doesn't cause the mapArea to exceed subDivision size limits.
     * When the MapArea get small, we don't want to shift lots if items into their own areas;
     * The *2 of LARGE_OBJECT_DIM is to keep to the same behaviour as earlier versions.
     */
    final int maxWidth = Math.max(Math.min(areas[0].getWidth(), maxSize / 2), LARGE_OBJECT_DIM * 2);
    final int maxHeight = Math.max(Math.min(areas[0].getHeight(), maxSize / 2), LARGE_OBJECT_DIM * 2);
    // and don't have a good tooSmallToDivide strategy when not splitPolygonsIntoArea.
    if (tooSmallToDivide) {
        distShapesIntoNewAreas(addedAreas, mapAreas[0]);
    } else {
        for (MapShape e : this.shapes) {
            Area shapeBounds = e.getBounds();
            if (splitPolygonsIntoArea || shapeBounds.getMaxDimension() > maxSize) {
                splitIntoAreas(mapAreas, e);
                continue;
            }
            int areaIndex = pickArea(mapAreas, e, xbaseHp, ybaseHp, nx, ny, dxHp, dyHp);
            if ((shapeBounds.getHeight() > maxHeight || shapeBounds.getWidth() > maxWidth) && !areas[areaIndex].contains(shapeBounds)) {
                // use splitIntoAreas to deal with overflow
                MapArea largeObjectArea = new MapArea(shapeBounds, areaResolution, true);
                largeObjectArea.addShape(e);
                addedAreas.add(largeObjectArea);
                continue;
            }
            mapAreas[areaIndex].addShape(e);
        }
    }
    if (tooSmallToDivide) {
        distPointsIntoNewAreas(addedAreas, mapAreas[0]);
    } else {
        for (MapPoint p : this.points) {
            int areaIndex = pickArea(mapAreas, p, xbaseHp, ybaseHp, nx, ny, dxHp, dyHp);
            mapAreas[areaIndex].addPoint(p);
        }
    }
    if (tooSmallToDivide) {
        distLinesIntoNewAreas(addedAreas, mapAreas[0]);
    } else {
        for (MapLine l : this.lines) {
            // Drop any zero sized lines.
            if (l instanceof MapRoad == false && l.getRect().height <= 0 && l.getRect().width <= 0)
                continue;
            Area lineBounds = l.getBounds();
            int areaIndex = pickArea(mapAreas, l, xbaseHp, ybaseHp, nx, ny, dxHp, dyHp);
            if ((lineBounds.getHeight() > maxHeight || lineBounds.getWidth() > maxWidth) && !areas[areaIndex].contains(lineBounds)) {
                MapArea largeObjectArea = new MapArea(lineBounds, areaResolution, false);
                largeObjectArea.addLine(l);
                addedAreas.add(largeObjectArea);
                continue;
            }
            mapAreas[areaIndex].addLine(l);
        }
    }
    if (!addedAreas.isEmpty()) {
        // combine list and array
        int pos = mapAreas.length;
        mapAreas = Arrays.copyOf(mapAreas, mapAreas.length + addedAreas.size());
        for (MapArea ma : addedAreas) {
            if (// distShapesIntoNewAreas etc didn't know how big it was going to be
            ma.getBounds() == null)
                // so set to bounds of all elements
                ma.setBounds(ma.getFullBounds());
            mapAreas[pos++] = ma;
        }
    }
    return mapAreas;
}
Also used : Area(uk.me.parabola.imgfmt.app.Area) MapLine(uk.me.parabola.mkgmap.general.MapLine) MapPoint(uk.me.parabola.mkgmap.general.MapPoint) ArrayList(java.util.ArrayList) MapRoad(uk.me.parabola.mkgmap.general.MapRoad) MapShape(uk.me.parabola.mkgmap.general.MapShape) MapPoint(uk.me.parabola.mkgmap.general.MapPoint)

Aggregations

Area (uk.me.parabola.imgfmt.app.Area)49 Test (org.junit.Test)26 Coord (uk.me.parabola.imgfmt.app.Coord)14 ArrayList (java.util.ArrayList)9 List (java.util.List)7 MapShape (uk.me.parabola.mkgmap.general.MapShape)4 MapPoint (uk.me.parabola.mkgmap.general.MapPoint)3 Way (uk.me.parabola.mkgmap.reader.osm.Way)3 Rectangle (java.awt.Rectangle)2 File (java.io.File)2 IOException (java.io.IOException)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 ExitException (uk.me.parabola.imgfmt.ExitException)2 MapFailedException (uk.me.parabola.imgfmt.MapFailedException)2 Point (uk.me.parabola.imgfmt.app.trergn.Point)2 Zoom (uk.me.parabola.imgfmt.app.trergn.Zoom)2 Element (uk.me.parabola.mkgmap.reader.osm.Element)2 Node (uk.me.parabola.mkgmap.reader.osm.Node)2 Long2ObjectOpenHashMap (it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap)1