logo separator

[mkgmap-dev] [PATCH v1] sea polygons

From Dermot McNally dermotm at gmail.com on Sun Aug 2 08:56:04 BST 2009

This exhausted the 2G of heap space I had allocated when I tried it on
a map of Ireland. Are there known practical limits I should try to
stay within?

Dermot

2009/8/1 Christian Gawron <christian.gawron at gmx.de>:
> Hi,
>
> the attached patch adds a sea polygon  (based on the bounding box of the
> map) and a multipolygon relation with all lines tagged as natural=coastline
> as inner elements. The code merges coastline components as far as possible.
> The patch also contains the multipolygon patch by Rudi which wasn't commited
> so far (without this patch, the rendering fails).
>
> The sea polygon is created as "natural=sea", for which I added a mapping to
> garmin type 0x32.
>
> Caveat: I have only tested this for islands (Corsica) so far.
>
> Best wishes
> Christian
>
> Index: src/uk/me/parabola/mkgmap/reader/osm/Way.java
> ===================================================================
> --- src/uk/me/parabola/mkgmap/reader/osm/Way.java       (Revision 1115)
> +++ src/uk/me/parabola/mkgmap/reader/osm/Way.java       (Arbeitskopie)
> @@ -76,6 +76,10 @@
>                }
>        }
>
> +        public boolean isClosed() {
> +           return points.get(0).equals(points.get(points.size()-1));
> +        }
> +
>        /**
>         * A simple representation of this way.
>         * @return A string with the name and start point
> Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
> ===================================================================
> --- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
>  (Revision 1115)
> +++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
>  (Arbeitskopie)
> @@ -5,7 +5,6 @@
>  import java.util.List;
>  import java.util.Map;
>
> -import uk.me.parabola.imgfmt.Utils;
>  import uk.me.parabola.imgfmt.app.Coord;
>
>  /**
> @@ -23,8 +22,9 @@
>         * this because the type of the relation is not known until after all
>         * its tags are read in.
>         * @param other The relation to base this one on.
> +        * @param wayMap Map of all ways.
>         */
> -       public MultiPolygonRelation(Relation other) {
> +       public MultiPolygonRelation(Relation other, Map<Long, Way> wayMap) {
>                setId(other.getId());
>                for (Map.Entry<Element, String> pairs:
> other.getRoles().entrySet()){
>                        addElement(pairs.getValue(), pairs.getKey());
> @@ -33,8 +33,16 @@
>
>                        if (value != null && pairs.getKey() instanceof Way) {
>                                Way way = (Way) pairs.getKey();
> -                               if (value.equals("outer"))
> -                                       outer = way;
> +                               if (value.equals("outer")){
> +                                       // duplicate outer way and remove
> tags for cascaded multipolygons
> +                                       outer = new Way(-way.getId());
> +                                       outer.copyTags(way);
> +                                       for(Coord point: way.getPoints())
> +                                               outer.addPoint(point);
> +                                       wayMap.put(outer.getId(), outer);
> +                                       if (way.getTags() != null)
> +                                               way.getTags().removeAll();
> +                               }
>                                else if (value.equals("inner"))
>                                        inners.add(way);
>                        }
> @@ -52,11 +60,20 @@
>                {
>                        for (Way w: inners) {
>                                if (w != null) {
> -                                       List<Coord> pts = w.getPoints();
> -                                       int[] insert =
> findCpa(outer.getPoints(), pts);
> -                                       if (insert[0] > 0)
> -                                               insertPoints(pts, insert[0],
> insert[1]);
> -                                       pts.clear();
> +                                       int[] insert =
> findCpa(outer.getPoints(), w.getPoints());
> +                                       //if (insert[0] > 0)
> +                                       insertPoints(w, insert[0],
> insert[1]);
> +
> +                                       // remove tags from inner way that
> are available in the outer way
> +                                       if (outer.getTags() != null){
> +                                               for (Map.Entry<String,
> String> mapTags: outer.getTags().getKeyValues().entrySet()){
> +                                                       String key =
> mapTags.getKey();
> +                                                       String value =
> mapTags.getValue();
> +                                                       if (w.getTag(key) !=
> null)
> +                                                               if
> (w.getTag(key).equals(value))
> +
> w.deleteTag(key);
> +                                               }
> +                                       }
>                                }
>                        }
>                }
> @@ -64,22 +81,39 @@
>
>        /**
>         * Insert Coordinates into the outer way.
> -        * @param inList List of Coordinates to be inserted
> +        * @param way Way to be inserted
>         * @param out Coordinates will be inserted after this point in the
> outer way.
>         * @param in Points will be inserted starting at this index,
>         *    then from element 0 to (including) this element;
>         */
> -       private void insertPoints(List<Coord> inList, int out, int in){
> +       private void insertPoints(Way way, int out, int in){
>                List<Coord> outList = outer.getPoints();
> +               List<Coord> inList = way.getPoints();
>                int index = out+1;
>                for (int i = in; i < inList.size(); i++)
>                        outList.add(index++, inList.get(i));
> -               for (int i = 0; i <= in; i++)
> +               for (int i = 0; i < in; i++)
>                        outList.add(index++, inList.get(i));
> -
> -               //with this line commented we get triangles, when
> uncommented some areas disappear
> -               // at least in mapsource, on device itself looks OK.
> -               outList.add(index,outList.get(out));
> +
> +               if (outer.getPoints().size() < 32){
> +                       outList.add(index++, inList.get(in));
> +                       outList.add(index, outList.get(out));
> +               }
> +               else {
> +                       // we shift the nodes to avoid duplicate nodes
> (large areas only)
> +                       int oLat = outList.get(out).getLatitude();
> +                       int oLon = outList.get(out).getLongitude();
> +                       int iLat = inList.get(in).getLatitude();
> +                       int iLon = inList.get(in).getLongitude();
> +                       if ((oLat - iLat) > (oLon - iLon)){
> +                               outList.add(index++, new Coord(iLat-1,
> iLon));
> +                               outList.add(index, new Coord(oLat-1, oLon));
> +                               }
> +                       else{
> +                               outList.add(index++, new Coord(iLat,
> iLon-1));
> +                               outList.add(index, new Coord(oLat, oLon-1));
> +                       }
> +               }
>        }
>
>        /**
> Index: src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
> ===================================================================
> --- src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
>  (Revision 1115)
> +++ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
>  (Arbeitskopie)
> @@ -19,6 +19,7 @@
>  import java.util.ArrayList;
>  import java.util.HashMap;
>  import java.util.IdentityHashMap;
> +import java.util.Iterator;
>  import java.util.LinkedHashMap;
>  import java.util.List;
>  import java.util.Map;
> @@ -65,6 +66,7 @@
>        private final Map<String, Long> fakeIdMap = new HashMap<String,
> Long>();
>        private final List<Node> exits = new ArrayList<Node>();
>        private final List<Way> motorways = new ArrayList<Way>();
> +       private final List<Way> shoreline = new ArrayList<Way>();
>
>        private static final int MODE_NODE = 1;
>        private static final int MODE_WAY = 2;
> @@ -92,6 +94,7 @@
>        private final boolean ignoreTurnRestrictions;
>        private final boolean linkPOIsToWays;
>        private final boolean routing;
> +        private final boolean generateSea;
>        private final Double minimumArcLength;
>        private final String frigRoundabouts;
>
> @@ -105,6 +108,7 @@
>                }
>                linkPOIsToWays = props.getProperty("link-pois-to-ways",
> false);
>                ignoreBounds = props.getProperty("ignore-osm-bounds", false);
> +               generateSea = props.getProperty("generate-sea", false);
>                routing = props.containsKey("route");
>                String rsa = props.getProperty("remove-short-arcs", null);
>                if(rsa != null)
> @@ -370,6 +374,8 @@
>                                if("motorway".equals(highway) ||
>                                   "trunk".equals(highway))
>                                        motorways.add(currentWay);
> +                               if(generateSea &&
> "coastline".equals(currentWay.getTag("natural")))
> +                                   shoreline.add(currentWay);
>                                currentWay = null;
>                                // ways are processed at the end of the
> document,
>                                // may be changed by a Relation class
> @@ -399,7 +405,7 @@
>                String type = currentRelation.getTag("type");
>                if (type != null) {
>                        if ("multipolygon".equals(type))
> -                               currentRelation = new
> MultiPolygonRelation(currentRelation);
> +                               currentRelation = new
> MultiPolygonRelation(currentRelation, wayMap);
>                        else if("restriction".equals(type)) {
>
>                                if(ignoreTurnRestrictions)
> @@ -446,6 +452,10 @@
>                }
>
>                coordMap = null;
> +
> +               if (generateSea)
> +                   generateSeaPolygon(shoreline);
> +
>                for (Relation r : relationMap.values())
>                        converter.convertRelation(r);
>
> @@ -746,4 +756,95 @@
>                        return fakeIdVal;
>                }
>        }
> +
> +        private void generateSeaPolygon(List<Way> shoreline) {
> +           System.out.printf("generating sea\n");
> +           long seaId;
> +           seaId = (1L << 62) + nextFakeId++;
> +           Way sea = new Way(seaId);
> +           wayMap.put(seaId, sea);
> +           Area bbox = mapper.getBounds();
> +           Coord nw = new Coord(bbox.getMinLat(), bbox.getMinLong());
> +           Coord ne = new Coord(bbox.getMinLat(), bbox.getMaxLong());
> +           Coord sw = new Coord(bbox.getMaxLat(), bbox.getMinLong());
> +           Coord se = new Coord(bbox.getMaxLat(), bbox.getMaxLong());
> +           sea.addPoint(nw);
> +           sea.addPoint(ne);
> +           sea.addPoint(se);
> +           sea.addPoint(sw);
> +           sea.addPoint(nw);
> +           sea.addTag("natural", "sea");
> +
> +           Relation seaRelation = new GeneralRelation((1L << 62) +
> nextFakeId++);
> +           seaRelation.addTag("type", "multipolygon");
> +           seaRelation.addElement("outer", sea);
> +
> +           List<Way> islands = new ArrayList();
> +
> +           // handle islands (closes shoreline components) first (they're
> easy)
> +           Iterator<Way> it = shoreline.iterator();
> +           while (it.hasNext()) {
> +               Way w = it.next();
> +               if (w.isClosed()) {
> +                   islands.add(w);
> +                   it.remove();
> +               }
> +           }
> +           concatenateWays(shoreline);
> +           // there may be more islands now
> +           it = shoreline.iterator();
> +           while (it.hasNext()) {
> +               Way w = it.next();
> +               if (w.isClosed()) {
> +                   System.out.println("island after concatenating\n");
> +                   islands.add(w);
> +                   it.remove();
> +               }
> +           }
> +
> +           for (Way w : islands) {
> +               seaRelation.addElement("inner", w);
> +           }
> +           for (Way w : shoreline) {
> +               seaRelation.addElement("inner", w);
> +           }
> +           seaRelation = new MultiPolygonRelation(seaRelation, wayMap);
> +           relationMap.put(seaId, seaRelation);
> +           seaRelation.processElements();
> +        }
> +
> +        public void concatenateWays(List<Way> ways) {
> +           Map<Coord, Way> beginMap = new HashMap();
> +
> +           for (Way w : ways) {
> +               if (!w.isClosed()) {
> +                   List<Coord> points = w.getPoints();
> +                   beginMap.put(points.get(0), w);
> +               }
> +           }
> +
> +           int merged = 1;
> +           while (merged > 0) {
> +               merged = 0;
> +               for (Way w1 : ways) {
> +                   List<Coord> points1 = w1.getPoints();
> +                   Way w2 = beginMap.get(points1.get(points1.size()-1));
> +
> +                   if (w2 != null) {
> +                       System.out.printf("merging: %d %d %d\n",
> ways.size(), w1.getId(), w2.getId());
> +                       List<Coord> points2 = w2.getPoints();
> +                       Way wm = new Way((1L << 62) + nextFakeId++);
> +                       wm.getPoints().addAll(points1);
> +                       wm.getPoints().addAll(points2);
> +                       ways.remove(w1);
> +                       ways.remove(w2);
> +                       beginMap.remove(points2.get(0));
> +                       ways.add(wm);
> +                       beginMap.put(points1.get(0), wm);
> +                       merged++;
> +                       break;
> +                   }
> +               }
> +           }
> +        }
>  }
> Index: src/uk/me/parabola/mkgmap/reader/osm/Element.java
> ===================================================================
> --- src/uk/me/parabola/mkgmap/reader/osm/Element.java   (Revision 1115)
> +++ src/uk/me/parabola/mkgmap/reader/osm/Element.java   (Arbeitskopie)
> @@ -86,6 +86,7 @@
>         * element.
>         */
>        public void copyTags(Element other) {
> +               if (other.tags != null)
>                tags = other.tags.copy();
>        }
>
> @@ -97,4 +98,8 @@
>                if (this.name == null)
>                        this.name = name;
>        }
> +
> +       public Tags getTags() {
> +               return tags;
> +       }
>  }
> Index: src/uk/me/parabola/mkgmap/reader/osm/Tags.java
> ===================================================================
> --- src/uk/me/parabola/mkgmap/reader/osm/Tags.java      (Revision 1115)
> +++ src/uk/me/parabola/mkgmap/reader/osm/Tags.java      (Arbeitskopie)
> @@ -16,7 +16,9 @@
>  */
>  package uk.me.parabola.mkgmap.reader.osm;
>
> +import java.util.HashMap;
>  import java.util.Iterator;
> +import java.util.Map;
>
>  /**
>  * Store the tags that belong to an Element.
> @@ -111,7 +113,7 @@
>                }
>                return null;
>        }
> -
> +
>        /**
>         * Make a deep copy of this object.
>         * @return A copy of this object.
> @@ -262,4 +264,22 @@
>                                        put(e.key, e.value);
>                }
>        }
> -}
> +
> +       public void removeAll() {
> +               for (int i = 0; i < capacity; i++){
> +                       keys[i] = null;
> +                       values[i] = null;
> +               }
> +               size = 0;
> +       }
> +
> +       public Map<String, String> getKeyValues() {
> +               Map<String, String> tagMap = new HashMap<String, String>();
> +               for (int i = 0; i < capacity; i++)
> +                       if (keys[i] != null && values[i] != null)
> +                               tagMap.put(keys[i], values[i]);
> +               return tagMap;
> +       }
> +
> +
> +}
> \ No newline at end of file
> Index: resources/styles/default/polygons
> ===================================================================
> --- resources/styles/default/polygons   (Revision 1115)
> +++ resources/styles/default/polygons   (Arbeitskopie)
> @@ -55,6 +55,7 @@
>  natural=mud [0x51 resolution 20]
>  natural=scrub [0x4f resolution 20]
>  natural=water [0x3c resolution 20]
> +natural=sea [0x32 resolution 10]
>  natural=wood [0x50 resolution 18]
>
>  place=village [0x03 resolution 18]
>
> _______________________________________________
> mkgmap-dev mailing list
> mkgmap-dev at lists.mkgmap.org.uk
> http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev
>



-- 
--------------------------------------
Iren sind menschlich



More information about the mkgmap-dev mailing list