Search in sources :

Example 36 with Area

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

the class SeaGenerator method addPrecompSea.

/**
 * Loads the precompiled sea tiles and adds the data to the
 * element saver.
 */
private void addPrecompSea() {
    log.info("Load precompiled sea tiles");
    // flag if all tiles contains sea or way only
    // this is important for polygon processing
    boolean distinctTilesOnly = true;
    List<Way> landWays = new ArrayList<Way>();
    List<Way> seaWays = new ArrayList<Way>();
    List<java.awt.geom.Area> seaOnlyAreas = new ArrayList<java.awt.geom.Area>();
    List<java.awt.geom.Area> landOnlyAreas = new ArrayList<java.awt.geom.Area>();
    // get the index with assignment key => sea/land/tilename
    ZipFile zipFile = null;
    PrecompData pd = precompIndex.get();
    if (precompSeaDir.getName().endsWith(".zip")) {
        zipFile = pd.zipFile;
    }
    for (String precompKey : getPrecompKeyNames()) {
        String tileName = getTileName(precompKey);
        if (tileName == null) {
            log.error("Precompile sea tile " + precompKey + " is missing in the index. Skipping.");
            continue;
        }
        if ("sea".equals(tileName) || "land".equals(tileName)) {
            // the whole precompiled tile is filled with either land or sea
            // => create a rectangle that covers the whole precompiled tile
            String[] tileCoords = keySplitter.split(precompKey);
            int minLat = Integer.valueOf(tileCoords[0]);
            int minLon = Integer.valueOf(tileCoords[1]);
            Rectangle r = new Rectangle(minLon, minLat, PRECOMP_RASTER, PRECOMP_RASTER);
            if ("sea".equals(tileName)) {
                seaOnlyAreas = addWithoutCreatingHoles(seaOnlyAreas, new java.awt.geom.Area(r));
            } else {
                landOnlyAreas = addWithoutCreatingHoles(landOnlyAreas, new java.awt.geom.Area(r));
            }
        } else {
            distinctTilesOnly = false;
            try {
                InputStream is = null;
                if (zipFile != null) {
                    ZipEntry entry = zipFile.getEntry(pd.precompZipFileInternalPath + tileName);
                    if (entry != null) {
                        is = zipFile.getInputStream(entry);
                    } else {
                        log.error("Preompiled sea tile " + tileName + " not found.");
                    }
                } else {
                    File precompTile = new File(precompSeaDir, tileName);
                    is = new FileInputStream(precompTile);
                }
                if (is != null) {
                    Collection<Way> seaPrecompWays = loadPrecompTile(is, tileName);
                    if (log.isDebugEnabled())
                        log.debug(seaPrecompWays.size(), "precomp sea ways from", tileName, "loaded.");
                    for (Way w : seaPrecompWays) {
                        // set a new id to be sure that the precompiled ids do not
                        // interfere with the ids of this run
                        w.setFakeId();
                        if ("land".equals(w.getTag("natural"))) {
                            landWays.add(w);
                        } else {
                            seaWays.add(w);
                        }
                    }
                }
            } catch (FileNotFoundException exp) {
                log.error("Preompiled sea tile " + tileName + " not found.");
            } catch (Exception exp) {
                log.error(exp);
                exp.printStackTrace();
            }
        }
    }
    landWays.addAll(areaToWays(landOnlyAreas, "land"));
    seaWays.addAll(areaToWays(seaOnlyAreas, "sea"));
    landOnlyAreas = null;
    seaOnlyAreas = null;
    // check if the land tags need to be changed
    if (landTag != null && ("natural".equals(landTag[0]) && "land".equals(landTag[1])) == false) {
        for (Way w : landWays) {
            w.deleteTag("natural");
            w.addTag(landTag[0], landTag[1]);
        }
    }
    if (generateSeaUsingMP || distinctTilesOnly) {
        // also with polygons if all tiles are using either sea or land only
        for (Way w : landWays) {
            saver.addWay(w);
        }
        for (Way w : seaWays) {
            w.setFullArea(seaSize);
            saver.addWay(w);
        }
    } else {
        // using polygons
        Area bounds = saver.getBoundingBox();
        // first add the complete bounding box as sea
        Way sea = new Way(FakeIdGenerator.makeFakeId(), bounds.toCoords());
        sea.addTag("natural", "sea");
        sea.setFullArea(seaSize);
        for (Way w : landWays) {
            saver.addWay(w);
        }
    }
}
Also used : GZIPInputStream(java.util.zip.GZIPInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) ZipEntry(java.util.zip.ZipEntry) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) FileNotFoundException(java.io.FileNotFoundException) FileInputStream(java.io.FileInputStream) ExitException(uk.me.parabola.imgfmt.ExitException) MapFailedException(uk.me.parabola.imgfmt.MapFailedException) IOException(java.io.IOException) FormatException(uk.me.parabola.imgfmt.FormatException) FileNotFoundException(java.io.FileNotFoundException) Area(uk.me.parabola.imgfmt.app.Area) ZipFile(java.util.zip.ZipFile) ZipFile(java.util.zip.ZipFile) File(java.io.File)

Example 37 with Area

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

the class SeaGenerator method getPrecompKeyNames.

/**
 * Calculates the key names of the precompiled sea tiles for the bounding box.
 * The key names are compiled of {@code lat+"_"+lon}.
 * @return the key names for the bounding box
 */
private List<String> getPrecompKeyNames() {
    Area bounds = saver.getBoundingBox();
    List<String> precompKeys = new ArrayList<String>();
    for (int lat = getPrecompTileStart(bounds.getMinLat()); lat < getPrecompTileEnd(bounds.getMaxLat()); lat += PRECOMP_RASTER) {
        for (int lon = getPrecompTileStart(bounds.getMinLong()); lon < getPrecompTileEnd(bounds.getMaxLong()); lon += PRECOMP_RASTER) {
            precompKeys.add(lat + "_" + lon);
        }
    }
    return precompKeys;
}
Also used : Area(uk.me.parabola.imgfmt.app.Area) ArrayList(java.util.ArrayList)

Example 38 with Area

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

the class SeaGenerator method end.

/**
 * All done, process the saved shoreline information and construct the polygons.
 */
public void end() {
    // if it is set do not perform any other algorithm
    if (precompSeaDir != null) {
        addPrecompSea();
        return;
    }
    final Area seaBounds = saver.getBoundingBox();
    if (coastlineFilenames == null) {
        log.info("Shorelines before join", shoreline.size());
        shoreline = joinWays(shoreline);
    } else {
        shoreline.addAll(CoastlineFileLoader.getCoastlineLoader().getCoastlines(seaBounds));
        log.info("Shorelines from extra file:", shoreline.size());
    }
    int closedS = 0;
    int unclosedS = 0;
    for (Way w : shoreline) {
        if (w.hasIdenticalEndPoints()) {
            closedS++;
        } else {
            unclosedS++;
        }
    }
    log.info("Closed shorelines", closedS);
    log.info("Unclosed shorelines", unclosedS);
    // clip all shoreline segments
    clipShorlineSegments(shoreline, seaBounds);
    log.info("generating sea, seaBounds=", seaBounds);
    int minLat = seaBounds.getMinLat();
    int maxLat = seaBounds.getMaxLat();
    int minLong = seaBounds.getMinLong();
    int maxLong = seaBounds.getMaxLong();
    Coord nw = new Coord(minLat, minLong);
    Coord ne = new Coord(minLat, maxLong);
    Coord sw = new Coord(maxLat, minLong);
    Coord se = new Coord(maxLat, maxLong);
    if (shoreline.isEmpty()) {
        // no sea required
        // even though there is no sea, generate a land
        // polygon so that the tile's background colour will
        // match the land colour on the tiles that do contain
        // some sea
        long landId = FakeIdGenerator.makeFakeId();
        Way land = new Way(landId, seaBounds.toCoords());
        land.addTag(landTag[0], landTag[1]);
        // no matter if the multipolygon option is used it is
        // only necessary to create a land polygon
        saver.addWay(land);
        // nothing more to do
        return;
    }
    long multiId = FakeIdGenerator.makeFakeId();
    Relation seaRelation = null;
    if (generateSeaUsingMP) {
        log.debug("Generate seabounds relation", multiId);
        seaRelation = new GeneralRelation(multiId);
        seaRelation.addTag("type", "multipolygon");
        seaRelation.addTag("natural", "sea");
    }
    List<Way> islands = new ArrayList<Way>();
    // handle islands (closed shoreline components) first (they're easy)
    handleIslands(shoreline, seaBounds, islands);
    // the remaining shoreline segments should intersect the boundary
    // find the intersection points and store them in a SortedMap
    NavigableMap<EdgeHit, Way> hitMap = findIntesectionPoints(shoreline, seaBounds, seaRelation);
    // now construct inner ways from these segments
    boolean shorelineReachesBoundary = createInnerWays(seaBounds, islands, hitMap);
    if (!shorelineReachesBoundary && roadsReachBoundary) {
        // try to avoid tiles being flooded by anti-lakes or other
        // bogus uses of natural=coastline
        generateSeaBackground = false;
    }
    List<Way> antiIslands = removeAntiIslands(seaRelation, islands);
    if (islands.isEmpty()) {
        // the tile doesn't contain any islands so we can assume
        // that it's showing a land mass that contains some
        // enclosed sea areas - in which case, we don't want a sea
        // coloured background
        generateSeaBackground = false;
    }
    if (generateSeaBackground) {
        for (Way ai : antiIslands) {
            boolean containedByLand = false;
            for (Way i : islands) {
                if (i.containsPointsOf(ai)) {
                    containedByLand = true;
                    break;
                }
            }
            if (!containedByLand) {
                // found an anti-island that is not contained by
                // land so convert it back into an island
                ai.deleteTag("natural");
                ai.addTag(landTag[0], landTag[1]);
                if (generateSeaUsingMP) {
                    // create a "inner" way for the island
                    assert seaRelation != null;
                    seaRelation.addElement("inner", ai);
                }
                log.warn("Converting anti-island starting at", ai.getPoints().get(0).toOSMURL(), "into an island as it is surrounded by water");
            }
        }
        long seaId = FakeIdGenerator.makeFakeId();
        Way sea = new Way(seaId);
        // the sea background area must be a little bigger than all
        // inner land areas. this is a workaround for a mp shortcoming:
        // mp is not able to combine outer and inner if they intersect
        // or have overlaying lines
        // the added area will be clipped later by the style generator
        sea.addPoint(new Coord(nw.getLatitude() - 1, nw.getLongitude() - 1));
        sea.addPoint(new Coord(sw.getLatitude() + 1, sw.getLongitude() - 1));
        sea.addPoint(new Coord(se.getLatitude() + 1, se.getLongitude() + 1));
        sea.addPoint(new Coord(ne.getLatitude() - 1, ne.getLongitude() + 1));
        // close shape
        sea.addPoint(sea.getPoints().get(0));
        sea.addTag("natural", "sea");
        sea.setFullArea(seaSize);
        log.info("sea: ", sea);
        saver.addWay(sea);
        if (generateSeaUsingMP) {
            assert seaRelation != null;
            seaRelation.addElement("outer", sea);
        }
    } else {
        // background is land
        // generate a land polygon so that the tile's
        // background colour will match the land colour on the
        // tiles that do contain some sea
        long landId = FakeIdGenerator.makeFakeId();
        Way land = new Way(landId, seaBounds.toCoords());
        land.addTag(landTag[0], landTag[1]);
        saver.addWay(land);
        if (generateSeaUsingMP) {
            seaRelation.addElement("inner", land);
        }
    }
    if (generateSeaUsingMP) {
        SeaPolygonRelation coastRel = saver.createSeaPolyRelation(seaRelation);
        coastRel.setFloodBlocker(floodblocker);
        if (floodblocker) {
            coastRel.setFloodBlockerGap(fbGap);
            coastRel.setFloodBlockerRatio(fbRatio);
            coastRel.setFloodBlockerThreshold(fbThreshold);
            coastRel.setFloodBlockerRules(fbRules.getWayRules());
            coastRel.setLandTag(landTag[0], landTag[1]);
            coastRel.setDebug(fbDebug);
        }
        saver.addRelation(coastRel);
    }
    shoreline = null;
}
Also used : ArrayList(java.util.ArrayList) Coord(uk.me.parabola.imgfmt.app.Coord) Area(uk.me.parabola.imgfmt.app.Area)

Example 39 with Area

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

the class UnusedElementsRemoverHook method end.

public void end() {
    long t1 = System.currentTimeMillis();
    log.info("Removing unused elements");
    final Area bbox = saver.getBoundingBox();
    long nodes = saver.getNodes().size();
    // go through all nodes
    for (Node node : new ArrayList<Node>(saver.getNodes().values())) {
        // nodes without tags can be removed
        if (node.getTagCount() == 0) {
            saver.getNodes().remove(node.getId());
            continue;
        }
        // check if the node is within the tile bounding box
        if (bbox.contains(node.getLocation()) == false) {
            boolean removeNode = true;
            // check if the node has no tag of the blacklist
            if (nodeTagBlacklist.isEmpty() == false) {
                for (String tag : nodeTagBlacklist) {
                    if (node.getTag(tag) != null) {
                        // the node contains one tag that might be interesting for the POIGeneratorHook
                        // do not remove it
                        removeNode = false;
                        break;
                    }
                }
            }
            if (removeNode) {
                saver.getNodes().remove(node.getId());
            } else {
                log.debug("Keep node", node, "because it contains a tag which might be required for the area-to-poi function.");
            }
        }
    }
    long tr1 = System.currentTimeMillis();
    // store all way ids that are referenced by a relation
    // all tags without a tag must not be removed if they are referenced by a relation
    Set<Long> relationWays = new HashSet<Long>();
    for (Relation rel : saver.getRelations().values()) {
        for (Entry<String, Element> relEntry : rel.getElements()) {
            if (relEntry.getValue() instanceof Way) {
                relationWays.add(relEntry.getValue().getId());
            }
        }
    }
    log.debug("Collecting way ids from relations took", (System.currentTimeMillis() - tr1), "ms");
    Rectangle bboxRect = new Rectangle(bbox.getMinLong(), bbox.getMinLat(), bbox.getWidth(), bbox.getHeight());
    long relWays = 0;
    long ways = saver.getWays().size();
    for (Way way : new ArrayList<Way>(saver.getWays().values())) {
        if (way.getPoints().isEmpty()) {
            // empty way will not appear in the map => remove it
            saver.getWays().remove(way.getId());
            continue;
        }
        // a relation might be used to add tags to the way using the style file
        if (way.getTagCount() == 0) {
            if (relationWays.contains(way.getId())) {
                relWays++;
            } else {
                saver.getWays().remove(way.getId());
                continue;
            }
        }
        // check if the way is completely outside the tile bounding box
        boolean coordInBbox = false;
        Coord prevC = null;
        // It is possible that the way is larger than the bounding box and therefore
        // contains the bbox completely. Especially this is true for the sea polygon
        // when using --generate-sea=polygon
        // So need the calc the bbox of the way
        Coord firstC = way.getPoints().get(0);
        int minLat = firstC.getLatitude();
        int maxLat = firstC.getLatitude();
        int minLong = firstC.getLongitude();
        int maxLong = firstC.getLongitude();
        for (Coord c : way.getPoints()) {
            if (bbox.contains(c)) {
                coordInBbox = true;
                break;
            } else if (prevC != null) {
                // check if the line intersects the bounding box
                if (bboxRect.intersectsLine(prevC.getLongitude(), prevC.getLatitude(), c.getLongitude(), c.getLatitude())) {
                    if (log.isDebugEnabled()) {
                        log.debug("Intersection!");
                        log.debug("Bbox:", bbox);
                        log.debug("Way coords:", prevC, c);
                    }
                    coordInBbox = true;
                    break;
                }
            }
            if (minLat > c.getLatitude()) {
                minLat = c.getLatitude();
            } else if (maxLat < c.getLatitude()) {
                maxLat = c.getLatitude();
            }
            if (minLong > c.getLongitude()) {
                minLong = c.getLongitude();
            } else if (maxLong < c.getLongitude()) {
                maxLong = c.getLongitude();
            }
            prevC = c;
        }
        if (coordInBbox == false) {
            // no coord of the way is within the bounding box
            // check if the way possibly covers the bounding box completely
            Area wayBbox = new Area(minLat, minLong, maxLat, maxLong);
            if (wayBbox.intersects(saver.getBoundingBox())) {
                log.debug(way, "possibly covers the bbox completely. Keep it.", way.toTagString());
            } else {
                saver.getWays().remove(way.getId());
            }
        }
    }
    log.info("Relation referenced ways:", relationWays.size(), "Used:", relWays);
    log.info("Nodes: before:", nodes, "after:", saver.getNodes().size());
    log.info("Ways: before:", ways, "after:", saver.getWays().size());
    log.info("Removing unused elements took", (System.currentTimeMillis() - t1), "ms");
}
Also used : ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) Coord(uk.me.parabola.imgfmt.app.Coord) Area(uk.me.parabola.imgfmt.app.Area) HashSet(java.util.HashSet)

Example 40 with Area

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

the class HGTConverterTest method testLon0Right.

@Test
public void testLon0Right() throws Exception {
    Area bbox = new Area(0, 0.1, 0.1, 0.0);
    HGTConverter hgtConverter = new HGTConverter(HGT_PATH, bbox, null, DEMFile.EXTRA);
    assertEquals(0, hgtConverter.getElevation(bbox.getMaxLat() * 256, bbox.getMinLong() * 256));
    assertEquals(0, hgtConverter.getElevation(bbox.getMaxLat() * 256, bbox.getMaxLong() * 256));
    assertEquals(0, hgtConverter.getElevation(bbox.getMinLat() * 256, bbox.getMinLong() * 256));
    assertEquals(0, hgtConverter.getElevation(bbox.getMinLat() * 256, bbox.getMaxLong() * 256));
}
Also used : Area(uk.me.parabola.imgfmt.app.Area) Test(org.junit.Test)

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