I have made some improvements to the multipolygon branch.

Changes:
* Polygons with inner polygons are now divided into several polygons. It's much faster and the PolygonSplitter cannot destroy them any more. * Improved tag handling. The tags from original ways are removed. This has the disadvantage that non polygon tags like highway are destroyed. This must be fixed within one of the next patches. * Added a FakeIdGenerator that creates unique fake ids for elements created by mkgmap. The Osm5XmlHandler has been adapted to that.

As before I am happy about any (good and bad) feedback!!
WanMil

Note: The code is not ready for the trunk. Some documentation and better method naming will be applied in one of the next patch.
Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java      
(revision 1471)
+++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java      
(working copy)
@@ -1,8 +1,10 @@
 package uk.me.parabola.mkgmap.reader.osm;
 
 import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.geom.Area;
 import java.awt.geom.Line2D;
-import java.util.AbstractMap;
+import java.awt.geom.PathIterator;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -26,8 +28,6 @@
        private static final Logger log = Logger
                        .getLogger(MultiPolygonRelation.class);
 
-       // private final List<Way> outerSegments = new ArrayList<Way>();
-       // private final List<Way> innerSegments = new ArrayList<Way>();
        private final Map<Long, Way> myWayMap;
 
        private final ArrayList<BitSet> containsMatrix = new 
ArrayList<BitSet>();
@@ -54,25 +54,26 @@
        public MultiPolygonRelation(Relation other, Map<Long, Way> wayMap) {
                myWayMap = wayMap;
                setId(other.getId());
+
                for (Map.Entry<String, Element> pair : other.getElements()) {
                        String role = pair.getKey();
                        Element el = pair.getValue();
                        addElement(role, el);
-
-                       // if (role != null && el instanceof Way) {
-                       //      Way way = (Way) el;
-                       //      if ("outer".equals(role)) {
-                       //              outerSegments.add(way);
-                       //      } else if ("inner".equals(role)) {
-                       //              innerSegments.add(way);
-                       //      }
-                       // }
                }
 
                setName(other.getName());
                copyTags(other);
        }
 
+       private String getRole(Element element) {
+               for (Map.Entry<String, Element> r_e : getElements()) {
+                       if (r_e.getValue() == element) {
+                               return r_e.getKey();
+                       }
+               }
+               return null;
+       }
+
        /**
         * Combine a list of way segments to a list of maximally joined ways
         * 
@@ -80,7 +81,7 @@
         *            a list of closed or unclosed ways
         * @return a list of closed ways
         */
-       private ArrayList<JoinedWay> joinWays(List<Map.Entry<String,Way>> 
segments) {
+       private ArrayList<JoinedWay> joinWays(List<Way> segments) {
                // this method implements RA-1 to RA-4
                // TODO check if the closed polygon is valid and implement a
                // backtracking algorithm to get other combinations
@@ -93,14 +94,11 @@
                // go through all segments and categorize them to closed and 
unclosed
                // list
                ArrayList<JoinedWay> unclosedWays = new ArrayList<JoinedWay>();
-               for (Map.Entry<String,Way> orgSegment : segments) {
-                       String role = orgSegment.getKey();
-                       Way way = orgSegment.getValue();
-
-                       if (way.isClosed()) {
-                               joinedWays.add(new JoinedWay(role, way));
+               for (Way orgSegment : segments) {
+                       if (orgSegment.isClosed()) {
+                               joinedWays.add(new JoinedWay(orgSegment));
                        } else {
-                               unclosedWays.add(new JoinedWay(role, way));
+                               unclosedWays.add(new JoinedWay(orgSegment));
                        }
                }
 
@@ -127,7 +125,6 @@
                                        continue;
                                }
 
-                               // TODO: compare roles too
                                // use == or equals as comparator??
                                if (joinWay.getPoints().get(0) == 
tempWay.getPoints().get(0)) {
                                        for (Coord point : 
tempWay.getPoints().subList(1,
@@ -208,11 +205,9 @@
                                        log.warn("Unclosed polygons in 
multipolygon relation "
                                                        + getId() + ":");
                                }
-                               for (Map.Entry<String,Way> rw : 
tempWay.getOriginalRoleWays()) {
-                                       String role = rw.getKey();
-                                       Way way = rw.getValue();
-                                       log.warn(" - way:", way.getId(), 
"role:", role,
-                                                       "osm:", 
way.toBrowseURL());
+                               for (Way orgWay : tempWay.getOriginalWays()) {
+                                       log.warn(" - way:", orgWay.getId(), 
"role:",
+                                                       getRole(orgWay), 
"osm:", orgWay.toBrowseURL());
                                }
 
                                it.remove();
@@ -277,19 +272,16 @@
         * ways with the role "inner" to the way with the role "outer"
         */
        public void processElements() {
-               ArrayList<Map.Entry<String,Way>> allWays =
-                               new ArrayList<Map.Entry<String,Way>>();
-
-               for (Map.Entry<String,Element> r_el : getElements()) {
-                       String role = r_el.getKey();
-                       Element element = r_el.getValue();
+               // don't care about outer and inner declaration
+               // because this is a first
+               ArrayList<Way> allWays = new ArrayList<Way>();
 
-                       if (element instanceof Way) {
-                               allWays.add(new 
AbstractMap.SimpleEntry<String,Way>
-                                               (role, (Way) element));
+               for (Map.Entry<String, Element> r_e : getElements()) {
+                       if (r_e.getValue() instanceof Way) {
+                               allWays.add((Way) r_e.getValue());
                        } else {
-                               log.warn("Non way element", element.getId(), 
"in multipolygon",
-                                               getId());
+                               log.warn("Non way element", 
r_e.getValue().getId(),
+                                               "in multipolygon", getId());
                        }
                }
 
@@ -297,23 +289,6 @@
                removeUnclosedWays(rings);
                // now we have closed ways == rings only
 
-               /*
-                * ===== start considering outer and inner ways ====
-                * ArrayList<JoinedWay> joinedOuterWays = joinWays(outerWays);
-                * ArrayList<JoinedWay> joinedInnerWays = joinWays(innerWays);
-                * 
-                * removeUnclosedWays(joinedOuterWays);
-                * removeUnclosedWays(joinedInnerWays);
-                * 
-                * // at this point we don't care about outer and inner // in 
the end we
-                * will compare if outer and inner tags are matching // what we 
detect
-                * here and issue some warnings and errors ArrayList<JoinedWay>
-                * completeJoinedWays = new ArrayList<JoinedWay>();
-                * completeJoinedWays.addAll(joinedOuterWays);
-                * completeJoinedWays.addAll(joinedInnerWays); ===== end 
considering
-                * outer and inner ways ====
-                */
-
                // check if we have at least one ring left
                if (rings.isEmpty()) {
                        // do nothing
@@ -341,7 +316,7 @@
                        // QA: check that all ways carry the role "outer/inner" 
and
                        // issue
                        // warnings
-                       checkRoles(currentRing.ring.getOriginalRoleWays(),
+                       checkRoles(currentRing.ring.getOriginalWays(),
                                        (currentRing.outer ? "outer" : 
"inner"));
 
                        // this ring is now processed and should not be used by 
any
@@ -371,46 +346,44 @@
                                        || hasUsefulTags(currentRing.ring);
 
                        if (processRing) {
-                               // now construct the ring polygon with its holes
+
+                               List<Way> innerWays = new 
ArrayList<Way>(holes.size());
                                for (RingStatus holeRingStatus : holes) {
-                                       int[] insert = 
findCpa(currentRing.ring.getPoints(),
-                                                       
holeRingStatus.ring.getPoints());
-                                       if (insert[0] >= 0 && insert[1] >= 0) {
-                                               insertPoints(currentRing.ring, 
holeRingStatus.ring,
-                                                               insert[0], 
insert[1]);
+                                       innerWays.add(holeRingStatus.ring);
+                               }
+
+                               List<Way> singularOuterPolygons = 
processRing(currentRing.ring,
+                                               innerWays);
+
+                               // check if the original way has been changed
+                               if (singularOuterPolygons.size() == 1
+                                               && singularOuterPolygons.get(0) 
== currentRing.ring) {
+                                       if 
(currentRing.ring.getOriginalWays().size() == 1) {
+                                               singularOuterPolygons = 
Collections
+                                                               
.singletonList(currentRing.ring
+                                                                               
.getOriginalWays().get(0));
                                        } else {
-                                               // this must not happen
-                                               log.error("Cannot find cpa in 
multipolygon "
-                                                               + 
toBrowseURL());
+                                               singularOuterPolygons = 
Collections
+                                                               
.singletonList((Way) currentRing.ring);
+                                               
currentRing.ring.removeOriginalTags();
                                        }
+                               } else {
+                                       // remove all tags so that the original 
way does not
+                                       // appear twice in the map
+                                       currentRing.ring.removeAllTagsDeep();
                                }
 
                                boolean useRelationTags = currentRing.outer
                                                && hasUsefulTags(this);
-
                                if (useRelationTags) {
                                        // the multipolygon contains tags that 
overwhelm the
-                                       // tags
-                                       // out the outer ring
-                                       currentRing.ring.copyTags(this);
-                               } else {
-                                       // the multipolygon does not contain 
any relevant tag
-                                       // use the segments of the ring and 
merge the tags
-                                       for (Map.Entry<String,Way> roleway : 
currentRing.ring.getOriginalRoleWays()) {
-                                               String role = roleway.getKey();
-                                               Way ringSegment = 
roleway.getValue();
-                                               // TODO uuh, this is bad => the 
last of the
-                                               // ring segments win
-                                               // => any better idea?
-                                               for (Map.Entry<String, String> 
outSegmentTag : ringSegment
-                                                               
.getEntryIteratable()) {
-                                                       
currentRing.ring.addTag(outSegmentTag.getKey(),
-                                                                       
outSegmentTag.getValue());
-                                               }
+                                       // tags of the outer ring
+                                       for (Way p : singularOuterPolygons) {
+                                               p.copyTags(this);
                                        }
                                }
 
-                               polygonResults.add(currentRing.ring);
+                               polygonResults.addAll(singularOuterPolygons);
                        }
                }
 
@@ -429,16 +402,220 @@
 
                // the polygonResults contain all polygons that should be used 
in the
                // map
-               // TODO remove the input stuff? inner ways and outer segments?
+               log.warn(toBrowseURL());
+               StringBuilder sb = new StringBuilder();
                for (Way resultWay : polygonResults) {
+                       sb.append("Way: " + resultWay.getId() + " Points: "
+                                       + resultWay.getPoints().size() + " 
Closed: "
+                                       + resultWay.isClosed() + " Tags: ");
+                       for (Map.Entry<String, String> entry : resultWay
+                                       .getEntryIteratable()) {
+                               sb.append(entry.getKey() + "=" + 
entry.getValue() + "; ");
+                       }
+                       log.warn(sb.toString());
+                       sb.setLength(0);
                        myWayMap.put(resultWay.getId(), resultWay);
                }
 
        }
 
+       private List<Way> processRing(Way outerWay, List<Way> innerWays) {
+               if (innerWays == null || innerWays.isEmpty()) {
+                       return Collections.singletonList(outerWay);
+               }
+               // this list contains all non overlapping and singular areas
+               // of the outer way
+               List<Area> outerAreas = new ArrayList<Area>();
+
+               // 1st create an Area object of the outerWay and put it to the 
list
+               outerAreas.add(wayToArea(outerWay));
+
+               for (Way innerWay : innerWays) {
+                       Area innerArea = wayToArea(innerWay);
+
+                       List<Area> outerAfterThisStep = new ArrayList<Area>();
+                       for (Area outerArea : outerAreas) {
+                               // check if this outerArea is probably 
intersected by the inner area
+                               // to save computation time in case it is not
+                               if (outerArea.getBounds().createIntersection(
+                                               
innerArea.getBounds()).isEmpty()) {
+                                       outerAfterThisStep.add(outerArea);
+                                       continue;
+                               }
+
+                               // cut the hole
+                               outerArea.subtract(innerArea);
+                               if (outerArea.isEmpty()) {
+                                       // this outer area space can be 
abandoned
+                               } else if (outerArea.isSingular()) {
+                                       // the area is singular
+                                       // => no further splits necessary
+                                       outerAfterThisStep.add(outerArea);
+                               } else {
+                                       // 1st cut in two halfs in the middle 
of the inner area
+
+                                       // Cut the bounding box into two 
rectangles
+                                       Rectangle r1;
+                                       Rectangle r2;
+
+                                       // Get the bounds of this polygon
+                                       Rectangle innerBounds = 
innerArea.getBounds();
+                                       Rectangle outerBounds = 
outerArea.getBounds();
+                                       if (outerBounds.width > 
outerBounds.height) {
+                                               int cutWidth = (innerBounds.x - 
outerBounds.x)
+                                                               + 
innerBounds.width / 2;
+                                               r1 = new 
Rectangle(outerBounds.x, outerBounds.y,
+                                                               cutWidth, 
outerBounds.height);
+                                               r2 = new 
Rectangle(outerBounds.x + cutWidth,
+                                                               outerBounds.y, 
outerBounds.width - cutWidth,
+                                                               
outerBounds.height);
+                                       } else {
+                                               int cutHeight = (innerBounds.y 
- outerBounds.y)
+                                                               + 
innerBounds.height / 2;
+                                               r1 = new 
Rectangle(outerBounds.x, outerBounds.y,
+                                                               
outerBounds.width, cutHeight);
+                                               r2 = new 
Rectangle(outerBounds.x, outerBounds.y
+                                                               + cutHeight, 
outerBounds.width,
+                                                               
outerBounds.height - cutHeight);
+                                       }
+
+                                       // Now find the intersection of these 
two boxes with the
+                                       // original
+                                       // polygon. This will make two new 
areas, and each area will
+                                       // be one
+                                       // (or more) polygons.
+                                       Area a1 = outerArea;
+                                       Area a2 = (Area) a1.clone();
+                                       a1.intersect(new Area(r1));
+                                       a2.intersect(new Area(r2));
+
+                                       
outerAfterThisStep.addAll(areaToSingularAreas(a1));
+                                       
outerAfterThisStep.addAll(areaToSingularAreas(a2));
+                               }
+                       }
+                       outerAreas = outerAfterThisStep;
+               }
+
+               List<Way> outerWays = new ArrayList<Way>(outerAreas.size());
+               for (Area area : outerAreas) {
+                       Way w = singularAreaToWay(area, 
FakeIdGenerator.getFakeId());
+                       w.copyTags(outerWay);
+                       outerWays.add(w);
+               }
+
+               return outerWays;
+       }
+
+       private List<Area> areaToSingularAreas(Area area) {
+               if (area.isEmpty()) {
+                       return Collections.emptyList();
+               } else if (area.isSingular()) {
+                       return Collections.singletonList(area);
+               } else {
+                       List<Area> singularAreas = new ArrayList<Area>();
+
+                       // all ways in the area MUST define outer areas
+                       // it is not possible that one of the areas define an 
inner segment
+
+                       float[] res = new float[6];
+                       PathIterator pit = area.getPathIterator(null);
+                       float[] prevPoint = new float[6];
+
+                       Polygon p = null;
+                       while (!pit.isDone()) {
+                               int type = pit.currentSegment(res);
+
+                               switch (type) {
+                               case PathIterator.SEG_LINETO:
+                                       if (Arrays.equals(res, prevPoint) == 
false) {
+                                               p.addPoint(Math.round(res[0]), 
Math.round(res[1]));
+                                       }
+                                       break;
+                               case PathIterator.SEG_CLOSE:
+                                       p.addPoint(p.xpoints[0], p.ypoints[0]);
+                                       Area a = new Area(p);
+                                       if (a.isEmpty() == false) {
+                                               singularAreas.add(a);
+                                       }
+                                       p = null;
+                                       break;
+                               case PathIterator.SEG_MOVETO:
+                                       if (p != null) {
+                                               Area a2 = new Area(p);
+                                               if (a2.isEmpty() == false) {
+                                                       singularAreas.add(a2);
+                                               }
+                                       }
+                                       p = new Polygon();
+                                       p.addPoint(Math.round(res[0]), 
Math.round(res[1]));
+                                       break;
+                               default:
+                                       log.warn(toBrowseURL(), "Unsupported 
path iterator type"
+                                                       + type, ". This is an 
mkgmap error.");
+                               }
+
+                               System.arraycopy(res, 0, prevPoint, 0, 6);
+                               pit.next();
+                       }
+                       return singularAreas;
+               }
+       }
+
+       private Area wayToArea(Way way) {
+               Polygon polygon = new Polygon();
+               for (Coord co : way.getPoints()) {
+                       polygon.addPoint(co.getLongitude(), co.getLatitude());
+               }
+               return new Area(polygon);
+       }
+
+       private Way singularAreaToWay(Area area, long wayId) {
+               if (area.isSingular() == false) {
+                       log
+                                       .warn(
+                                                       "singularAreaToWay 
called with non singular area. Multipolygon ",
+                                                       toBrowseURL());
+               }
+               if (area.isEmpty()) {
+                       log.warn("Empty area.", toBrowseURL());
+                       return null;
+               }
+
+               Way w = null;
+
+               float[] res = new float[6];
+               PathIterator pit = area.getPathIterator(null);
+
+               while (!pit.isDone()) {
+                       int type = pit.currentSegment(res);
+
+                       // System.out.println("T" + type + " " + res[0] + "," + 
res[1] + " "
+                       // + res[2] + "," + res[3] + " " + res[4] + "," + 
res[5]);
+
+                       switch (type) {
+                       case PathIterator.SEG_MOVETO:
+                               w = new Way(wayId);
+                               w.addPoint(new Coord(Math.round(res[1]), 
Math.round(res[0])));
+                               break;
+                       case PathIterator.SEG_LINETO:
+                               w.addPoint(new Coord(Math.round(res[1]), 
Math.round(res[0])));
+                               break;
+                       case PathIterator.SEG_CLOSE:
+                               w.addPoint(w.getPoints().get(0));
+                               return w;
+                       default:
+                               log.warn(toBrowseURL(),
+                                               "Unsupported path iterator 
type" + type,
+                                               ". This is an mkgmap error.");
+                       }
+                       pit.next();
+               }
+               return w;
+       }
+
        private boolean hasUsefulTags(JoinedWay way) {
-               for (Map.Entry<String,Way> segment : way.getOriginalRoleWays()) 
{
-                       if (hasUsefulTags(segment.getValue())) {
+               for (Way segment : way.getOriginalWays()) {
+                       if (hasUsefulTags(segment)) {
                                return true;
                        }
                }
@@ -461,14 +638,12 @@
         * @param wayList
         * @param checkRole
         */
-       private void checkRoles(List<Map.Entry<String,Way>> wayList,
-                                                       String checkRole) {
+       private void checkRoles(List<Way> wayList, String checkRole) {
                // QA: check that all ways carry the role "inner" and issue 
warnings
-               for (Map.Entry<String,Way> rw : wayList) {
-                       String role = rw.getKey();
-                       Way way = rw.getValue();
-                       if (!checkRole.equals(role) == false) {
-                               log.warn("Way", way.getId(), "carries role", 
role,
+               for (Way tempWay : wayList) {
+                       String realRole = getRole(tempWay);
+                       if (checkRole.equals(realRole) == false) {
+                               log.warn("Way", tempWay.getId(), "carries 
role", realRole,
                                                "but should carry role", 
checkRole);
                        }
                }
@@ -499,9 +674,60 @@
                                }
                        }
                }
-
        }
 
+       // private void createContainsMatrix(List<JoinedWay> wayList) {
+       // long t1 = System.currentTimeMillis();
+       //              
+       // for (int i = 0; i < wayList.size(); i++) {
+       // containsMatrix.add(new BitSet());
+       // }
+       //
+       // // use this matrix to check which matrix element has been
+       // // calculated
+       // ArrayList<BitSet> finishedMatrix = new 
ArrayList<BitSet>(wayList.size());
+       //
+       // for (int i = 0; i < wayList.size(); i++) {
+       // BitSet matrixRow = new BitSet();
+       // // an element does not contain itself
+       // matrixRow.set(i);
+       // finishedMatrix.add(matrixRow);
+       // }
+       //
+       // for (int rowIndex = 0; rowIndex < wayList.size(); rowIndex++) {
+       // Way potentialOuterRing = wayList.get(rowIndex);
+       // BitSet containsColumns = containsMatrix.get(rowIndex);
+       // BitSet finishedCol = finishedMatrix.get(rowIndex);
+       //
+       // // get all non calculated columns of the matrix
+       // for (int colIndex = finishedCol.nextClearBit(0); colIndex >= 0 &&
+       // colIndex < wayList.size(); colIndex = finishedCol
+       // .nextClearBit(colIndex + 1)) {
+       //
+       // boolean contains = contains(potentialOuterRing, 
wayList.get(colIndex));
+       //
+       // if (contains) {
+       // containsColumns.set(colIndex);
+       //                                      
+       // // we also know that the inner ring does not contain the outer ring
+       // // so we can set the finished bit for this matrix element
+       // finishedMatrix.get(colIndex).set(rowIndex);
+       //                                      
+       // // additionally we know that the outer ring contains all rings
+       // // that are contained by the inner ring
+       // containsColumns.or(containsMatrix.get(colIndex));
+       // finishedCol.or(containsColumns);
+       // }
+       //
+       // // this matrix element is calculated now
+       // finishedCol.set(colIndex);
+       // }
+       // }
+       //              
+       // long t2 = System.currentTimeMillis();
+       // log.warn("createMatrix",(t2-t1),"ms");
+       // }
+
        /**
         * Checks if the ring with ringIndex1 contains the ring with ringIndex2.
         * 
@@ -573,213 +799,63 @@
        }
 
        /**
-        * Insert Coordinates into the outer way.
-        * 
-        * @param outer
-        *            the outer way
-        * @param inner
-        *            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;
+        * This is a helper class that stores that gives access to the original
+        * segments of a joined way.
         */
-       private void insertPoints(Way outer, Way inner, int out, int in) {
-               // TODO this algorithm may generate a self intersecting polygon
-               // because it does not consider the direction of both ways
-               // don't know if that's a problem
-
-               List<Coord> outList = outer.getPoints();
-               List<Coord> inList = inner.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++) {
-                       outList.add(index++, inList.get(i));
-               }
+       private static class JoinedWay extends Way {
+               private final List<Way> originalWays;
 
-               // Investigate and see if we can do the first alternative here 
by
-               // changing the polygon splitter. If not then always do the 
alternative
-               // and remove unused code.
-               if (outer.getPoints().size() < 0 /* Always use alternative 
method for now */) {
-                       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 (Math.abs(oLat - iLat) > Math.abs(oLon - iLon)) {
-                               int delta = (oLon > iLon) ? -1 : 1;
-                               outList.add(index++, new Coord(iLat + delta, 
iLon));
-                               outList.add(index, new Coord(oLat + delta, 
oLon));
-                       } else {
-                               int delta = (oLat > iLat) ? 1 : -1;
-                               outList.add(index++, new Coord(iLat, iLon + 
delta));
-                               outList.add(index, new Coord(oLat, oLon + 
delta));
-                       }
+               public JoinedWay(Way originalWay) {
+                       super(FakeIdGenerator.getFakeId(), new 
ArrayList<Coord>(originalWay
+                                       .getPoints()));
+                       this.originalWays = new ArrayList<Way>();
+                       addWay(originalWay);
                }
-       }
 
-       private static final class DistIndex implements Comparable<DistIndex> {
-               int index1;
-               int index2;
-               double distance;
-
-               public DistIndex(int index1, int index2, double distance) {
-                       super();
-                       this.index1 = index1;
-                       this.index2 = index2;
-                       this.distance = distance;
+               public void addPoint(int index, Coord point) {
+                       getPoints().add(index, point);
                }
 
-               @Override
-               public int compareTo(DistIndex o) {
-                       if (distance < o.distance)
-                               return -1;
-                       else if (distance > o.distance) {
-                               return 1;
+               public void addWay(Way way) {
+                       if (way instanceof JoinedWay) {
+                               for (Way w : ((JoinedWay) 
way).getOriginalWays()) {
+                                       addWay(w);
+                               }
                        } else {
-                               return 0;
-                       }
-               }
-       }
-
-       /**
-        * find the Closest Point of Approach between two coordinate-lists This 
will
-        * probably be moved to a Utils class. Note: works only if l2 lies into 
l1.
-        * 
-        * @param l1
-        *            First list of points.
-        * @param l2
-        *            Second list of points.
-        * @return The first element is the index in l1, the second in l2 which 
are
-        *         the closest together.
-        */
-       private static int[] findCpa(List<Coord> l1, List<Coord> l2) {
-               // calculate and sort all distances first before
-               // to avoid the very costly calls of intersect
-               // Limit the size of this list to 500000 entries to
-               // avoid extreme memory consumption
-               int maxEntries = 500000;
-               ArrayList<DistIndex> distList = new 
ArrayList<DistIndex>(Math.min(l1
-                               .size()
-                               * l2.size(), maxEntries));
-
-               DistIndex minDistance = null;
-
-               int index1 = 0;
-               for (Coord c1 : l1) {
-                       int index2 = 0;
-                       for (Coord c2 : l2) {
-                               double distance = 
c1.distanceInDegreesSquared(c2);
-                               distList.add(new DistIndex(index1, index2, 
distance));
-                               index2++;
-
-                               if (distList.size() == maxEntries) {
-                                       Collections.sort(distList);
-                                       for (DistIndex newDistance : distList) {
-                                               if (minDistance == null
-                                                               || 
minDistance.distance > newDistance.distance) {
-                                                       // this is a new minimum
-                                                       // test if a line 
between c1 and c2 intersects
-                                                       // the outer polygon l1.
-                                                       if (intersects(l1, 
l1.get(newDistance.index1), l2
-                                                                       
.get(newDistance.index2)) == false) {
-                                                               minDistance = 
newDistance;
-                                                               break;
-                                                       }
-                                               } else {
-                                                       break;
-                                               }
-                                       }
-                                       distList.clear();
+                               this.originalWays.add(way);
+                               addTagsOf(way);
+                               if (getName() == null && way.getName() != null) 
{
+                                       setName(way.getName());
                                }
                        }
-                       index1++;
+                       log.debug("Joined", this.getId(), "with", way.getId());
                }
 
-               Collections.sort(distList);
-               for (DistIndex newDistance : distList) {
-                       if (minDistance == null
-                                       || minDistance.distance > 
newDistance.distance) {
-                               // this is a new minimum
-                               // test if a line between c1 and c2 intersects
-                               // the outer polygon l1.
-                               if (intersects(l1, l1.get(newDistance.index1), 
l2
-                                               .get(newDistance.index2)) == 
false) {
-                                       minDistance = newDistance;
-                                       break;
+               private void addTagsOf(Way way) {
+                       for (Map.Entry<String, String> tag : 
way.getEntryIteratable()) {
+                               if (getTag(tag.getKey()) == null) {
+                                       addTag(tag.getKey(), tag.getValue());
                                }
-                       } else {
-                               break;
                        }
                }
 
-               if (minDistance == null) {
-                       // this should not happen
-                       return new int[] { -1, -1 };
-               } else {
-                       return new int[] { minDistance.index1, 
minDistance.index2 };
+               public List<Way> getOriginalWays() {
+                       return originalWays;
                }
-       }
-
-       private static boolean intersects(List<Coord> lc, Coord lp1, Coord lp2) 
{
-               Coord c11 = null;
-               Coord c12 = null;
-               for (Coord c : lc) {
-                       c12 = c11;
-                       c11 = c;
-                       if (c12 == null) {
-                               continue;
-                       }
 
-                       // in case the line intersects in a well known point 
this is not an
-                       // inline intersection
-                       if (c11.equals(lp1) || c11.equals(lp2) || 
c12.equals(lp1)
-                                       || c12.equals(lp2)) {
-                               continue;
-                       }
-
-                       if (Line2D.linesIntersect(c11.getLatitude(), 
c11.getLongitude(),
-                                       c12.getLatitude(), c12.getLongitude(), 
lp1.getLatitude(),
-                                       lp1.getLongitude(), lp2.getLatitude(), 
lp2.getLongitude())) {
-                               return true;
-                       }
+               public void removeAllTagsDeep() {
+                       removeOriginalTags();
+                       removeAllTags();
                }
-               return false;
-       }
 
-       /**
-        * This is a helper class that stores that gives access to the original
-        * segments of a joined way.
-        */
-       private static class JoinedWay extends Way {
-               private final List<Map.Entry<String,Way>> originalRoleWays;
-
-               public JoinedWay(String role, Way originalWay) {
-                       super(-originalWay.getId(), new 
ArrayList<Coord>(originalWay
-                                       .getPoints()));
-                       this.originalRoleWays = new 
ArrayList<Map.Entry<String,Way>>();
-                       this.originalRoleWays.add(new 
AbstractMap.SimpleEntry<String,Way>
-                                                                         
(role, originalWay));
-               }
-
-               public void addPoint(int index, Coord point) {
-                       getPoints().add(index, point);
-               }
-
-               public void addWay(JoinedWay way) {
-                       originalRoleWays.addAll(way.originalRoleWays);
-                       log.debug("Joined", this.getId(), "with", way.getId());
-               }
-
-               public List<Map.Entry<String, Way>> getOriginalRoleWays() {
-                       return originalRoleWays;
+               public void removeOriginalTags() {
+                       for (Way w : getOriginalWays()) {
+                               if (w instanceof JoinedWay) {
+                                       ((JoinedWay) w).removeAllTagsDeep();
+                               } else {
+                                       w.removeAllTags();
+                               }
+                       }
                }
 
        }
Index: src/uk/me/parabola/mkgmap/reader/osm/FakeIdGenerator.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/FakeIdGenerator.java   (revision 0)
+++ src/uk/me/parabola/mkgmap/reader/osm/FakeIdGenerator.java   (revision 0)
@@ -0,0 +1,24 @@
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class FakeIdGenerator {
+
+       public static final long START_ID = 1L << 62;
+       
+       private static final AtomicLong fakeId = new AtomicLong(START_ID);
+
+       /**
+        * Retrieves a unique id that can be used to fake OSM ids.
+        * 
+        * @return a unique id
+        */
+       public static long getFakeId() {
+               return fakeId.incrementAndGet();
+       }
+
+       public static boolean isFakeId(long id) {
+               return id >= START_ID;
+       }
+       
+}
Index: src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java        
(revision 1471)
+++ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java        
(working copy)
@@ -46,6 +46,7 @@
 import uk.me.parabola.mkgmap.general.RoadNetwork;
 import uk.me.parabola.mkgmap.reader.osm.CoordPOI;
 import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.FakeIdGenerator;
 import uk.me.parabola.mkgmap.reader.osm.GeneralRelation;
 import uk.me.parabola.mkgmap.reader.osm.MultiPolygonRelation;
 import uk.me.parabola.mkgmap.reader.osm.Node;
@@ -104,8 +105,6 @@
        private Area bbox;
        private Runnable endTask;
 
-       private long nextFakeId = 1;
-
        private final boolean reportUndefinedNodes;
        private final boolean makeOppositeCycleways;
        private final boolean makeCycleways;
@@ -1053,7 +1052,7 @@
        }
 
        public long makeFakeId() {
-               return (1L << 62) + nextFakeId++;
+               return FakeIdGenerator.getFakeId();
        }
 
        private long idVal(String id) {
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to