Hi WanMil

As Felix said, the lesscuts patch and the closewaysoutbox patches
conflict. I've attached the patch from applying 'lesscuts' to r1594,
resolving in favour of lesscuts where there was a conflict.

I'll commit that if there are no problems, but could you let me know
what can be done about the mp closeway patch. The code is so completely
different between the two patches that I wouldn't like to guess what to
do (if anything).

..Steve


Hi Steve,

v3 of the patch is taken from r1596.

I have slightly modified it compared to v2. Just some minor improvements and the merging to the patches that have been already committed.

Summary: Reduce number of cuts in multipolygon processing
Reduces the number of cuts performed by multipolygon processing by combining the cut of several polygons in one cut instead of n cuts.
This speeds up the processing for multipolygons consisting of lots polygons.

WanMil


Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java      
(revision 1596)
+++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java      
(working copy)
@@ -7,15 +7,19 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Queue;
 import java.util.Set;
+import java.util.TreeSet;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.logging.Level;
 
@@ -41,7 +45,8 @@
        private Set<JoinedWay> intersectingPolygons;
 
        private final uk.me.parabola.imgfmt.app.Area bbox;
-
+       private Area bboxArea;
+       
        /** 
         * A point that has a lower or equal squared distance from 
         * a line is treated as if it lies one the line.<br/>
@@ -423,10 +428,7 @@
 
                        if (remove) {
                                // check if the polygon contains the complete 
bounding box
-                               Rectangle bboxRect = new 
Rectangle(bbox.getMinLat(), bbox
-                                               .getMinLong(), bbox.getMaxLat() 
- bbox.getMinLat(),
-                                               bbox.getMaxLong() - 
bbox.getMinLong());
-                               if (w.getBounds().contains(bboxRect)) {
+                               if 
(w.getBounds().contains(bboxArea.getBounds())) {
                                        remove = false;
                                }
                        }
@@ -527,6 +529,11 @@
                        }
                }
 
+               // create an Area for the bbox to clip the polygons
+               bboxArea = new Area(new Rectangle(bbox.getMinLong(), bbox
+                       .getMinLat(), bbox.getMaxLong() - bbox.getMinLong(),
+                       bbox.getMaxLat() - bbox.getMinLat()));
+               
                polygons = joinWays(allWays);
                closeWays(polygons);
                removeUnclosedWays(polygons);
@@ -639,15 +646,20 @@
                                        || 
hasPolygonTags(currentPolygon.polygon);
 
                        if (processPolygon) {
+                               List<Way> singularOuterPolygons;
+                               if (holes.isEmpty()) {
+                                       singularOuterPolygons = Collections
+                                                       .singletonList((Way) 
new JoinedWay(currentPolygon.polygon));
+                               } else {
+                                       List<Way> innerWays = new 
ArrayList<Way>(holes.size());
+                                       for (PolygonStatus polygonHoleStatus : 
holes) {
+                                               
innerWays.add(polygonHoleStatus.polygon);
+                                       }
 
-                               List<Way> innerWays = new 
ArrayList<Way>(holes.size());
-                               for (PolygonStatus polygonHoleStatus : holes) {
-                                       
innerWays.add(polygonHoleStatus.polygon);
+                                       singularOuterPolygons = 
cutOutInnerPolygons(currentPolygon.polygon,
+                                               innerWays);
                                }
-
-                               List<Way> singularOuterPolygons = 
cutOutInnerPolygons(
-                                       currentPolygon.polygon, innerWays);
-
+                               
                                if 
(currentPolygon.polygon.getOriginalWays().size() == 1) {
                                        // the original way was a closed 
polygon which
                                        // has been replaced by the new cutted 
polygon
@@ -689,7 +701,7 @@
                        runIntersectionCheck(unfinishedPolygons);
                        runWrongInnerPolygonCheck(unfinishedPolygons, 
innerPolygons);
 
-                       // we have at least one ring that could not be processed
+                       // we have at least one polygon that could not be 
processed
                        // Probably we have intersecting or overlapping polygons
                        // one possible reason is if the relation overlaps the 
tile
                        // bounds
@@ -704,8 +716,7 @@
                cleanup();
        }
 
-       
-       private void runIntersectionCheck(BitSet unfinishedRings) {
+       private void runIntersectionCheck(BitSet unfinishedPolys) {
                if (intersectingPolygons.isEmpty()) {
                        // nothing to do
                        return;
@@ -716,7 +727,7 @@
                boolean oneOufOfBbox = false;
                for (JoinedWay polygon : intersectingPolygons) {
                        int pi = polygons.indexOf(polygon);
-                       unfinishedRings.clear(pi);
+                       unfinishedPolys.clear(pi);
 
                        boolean outOfBbox = false;
                        for (Coord c : polygon.getPoints()) {
@@ -736,7 +747,7 @@
 
        private void runWrongInnerPolygonCheck(BitSet unfinishedPolygons,
                        BitSet innerPolygons) {
-               // find all unfinished inner rings that are not contained by any
+               // find all unfinished inner polygons that are not contained by 
any
                BitSet wrongInnerPolygons = 
findOutmostPolygons(unfinishedPolygons, innerPolygons);
                if (log.isDebugEnabled()) {
                        log.debug("unfinished", unfinishedPolygons);
@@ -780,6 +791,49 @@
                roleMap.clear();
                containsMatrix = null;
                polygons = null;
+               bboxArea = null;
+               intersectingPolygons = null;
+       }
+
+       private CutPoint calcNextCutPoint(AreaCutData areaData) {
+               if (areaData.innerAreas == null || 
areaData.innerAreas.isEmpty()) {
+                       return null;
+               }
+               
+               if (areaData.innerAreas.size() == 1) {
+                       // make it short if there is only one inner area
+                       Rectangle outerBounds = areaData.outerArea.getBounds();
+                       CoordinateAxis axis = (outerBounds.width < 
outerBounds.height ? CoordinateAxis.LONGITUDE : CoordinateAxis.LATITUDE);
+                       CutPoint oneCutPoint = new CutPoint(axis);
+                       oneCutPoint.addArea(areaData.innerAreas.get(0));
+                       return oneCutPoint;
+               }
+               
+               ArrayList<Area> innerStart = new ArrayList<Area>(
+                               areaData.innerAreas);
+               
+               ArrayList<CutPoint> bestCutPoints = new 
ArrayList<CutPoint>(CoordinateAxis.values().length);
+               
+               for (CoordinateAxis axis : CoordinateAxis.values()) {
+                       CutPoint bestCutPoint = new CutPoint(axis);
+                       CutPoint currentCutPoint = new CutPoint(axis);
+
+                       Collections.sort(innerStart, (axis == 
CoordinateAxis.LONGITUDE ? COMP_LONG_START: COMP_LAT_START));
+
+                       Iterator<Area> startIter = innerStart.iterator();
+                       while (startIter.hasNext()) {
+                               Area nextStart = startIter.next();
+                               currentCutPoint.addArea(nextStart);
+
+                               if (currentCutPoint.compareTo(bestCutPoint) > 
0) {
+                                       bestCutPoint = 
currentCutPoint.duplicate();
+                               }
+                       }
+                       bestCutPoints.add(bestCutPoint);
+               }
+
+               return Collections.max(bestCutPoints);
+               
        }
 
        /**
@@ -794,112 +848,166 @@
         *         polygons
         */
        private List<Way> cutOutInnerPolygons(Way outerPolygon, List<Way> 
innerPolygons) {
-               // we use the java.awt.geom.Area class because it's a quick
-               // implementation of what we need
+               if (innerPolygons.isEmpty()) {
+                       Way outerWay = new JoinedWay(outerPolygon);
+                       if (log.isDebugEnabled()) {
+                               log.debug("Way", outerPolygon.getId(), 
"splitted to way", outerWay.getId());
+                       }
+                       return Collections.singletonList(outerWay);
+               }
+
+               // use the java.awt.geom.Area class because it's a quick
+               // implementation of what's needed
 
                // this list contains all non overlapping and singular areas
                // of the outerPolygon
-               List<Area> outerAreas = new ArrayList<Area>();
-
-               // 1st create an Area object of the outerPolygon and put it to 
the list
-               List<Area> oa = createAreas(outerPolygon);
-
-               Area bboxArea = new Area(new Rectangle(bbox.getMinLong(), bbox
-                       .getMinLat(), bbox.getMaxLong() - bbox.getMinLong(),
-                       bbox.getMaxLat() - bbox.getMinLat()));
+               Queue<AreaCutData> areasToCut = new LinkedList<AreaCutData>();
+               Collection<Area> finishedAreas = new 
ArrayList<Area>(innerPolygons.size());
                
-               // clip the bounding box
-               for (Area outerArea : oa) {
-                       if (bboxArea.contains(outerArea.getBounds())) {
-                               // no clipping necessary
-                               outerAreas.add(outerArea);
-                       } else {
-                               // the area might intersect the bounding box
-                               // => clip it to the bounding box
-                               outerArea.intersect(bboxArea);
-                               
outerAreas.addAll(areaToSingularAreas(outerArea));
-                       }
-               }
-
-               List<Area> innerAreas = new ArrayList<Area>();
+               // create a list of Area objects from the outerPolygon (clipped 
to the bounding box)
+               List<Area> outerAreas = createAreas(outerPolygon, true);
+               
+               // create the inner areas
+               List<Area> innerAreas = new 
ArrayList<Area>(innerPolygons.size()+2);
                for (Way innerPolygon : innerPolygons) {
-                       innerAreas.addAll(createAreas(innerPolygon));
+                       // don't need to clip to the bounding box because 
+                       // these polygons are just used to cut out holes
+                       innerAreas.addAll(createAreas(innerPolygon, false));
                }
 
-               // go through all innerPolygons (holes) and cut them from the 
outerPolygon
-               for (Area innerArea : innerAreas) {
-
-                       List<Area> outerAfterThisStep = new ArrayList<Area>();
+               // initialize the cut data queue
+               if (innerAreas.isEmpty()) {
+                       // this is a multipolygon without any inner areas
+                       // nothing to cut
+                       finishedAreas.addAll(outerAreas);
+               } else if (outerAreas.size() == 1) {
+                       // there is one outer area only
+                       // it is checked before that all inner areas are inside 
this outer area
+                       AreaCutData initialCutData = new AreaCutData();
+                       initialCutData.outerArea = outerAreas.get(0);
+                       initialCutData.innerAreas = innerAreas;
+                       areasToCut.add(initialCutData);
+               } else {
+                       // multiple outer areas
                        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().intersects(innerArea.getBounds()) == false) {
-                                       outerAfterThisStep.add(outerArea);
-                                       continue;
+                               AreaCutData initialCutData = new AreaCutData();
+                               initialCutData.outerArea = outerArea;
+                               initialCutData.innerAreas = new 
ArrayList<Area>(innerAreas
+                                               .size());
+                               for (Area innerArea : innerAreas) {
+                                       if (outerArea.getBounds().intersects(
+                                               innerArea.getBounds())) {
+                                               
initialCutData.innerAreas.add(innerArea);
+                                       }
                                }
-
-                               // 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);
+                               
+                               if (initialCutData.innerAreas.isEmpty()) {
+                                       // this is either an error
+                                       // or the outer area has been cut into 
pieces on the tile bounds
+                                       finishedAreas.add(outerArea);
                                } else {
-                                       // 1st cut in two halfs in the middle 
of the inner area
+                                       areasToCut.add(initialCutData);
+                               }
+                       }
+               }
 
-                                       // Cut the bounding box into two 
rectangles
-                                       Rectangle r1;
-                                       Rectangle r2;
+               while (areasToCut.isEmpty() == false) {
+                       AreaCutData areaCutData = areasToCut.poll();
+                       CutPoint cutPoint = calcNextCutPoint(areaCutData);
+                       
+                       if (cutPoint == null) {
+                               finishedAreas.add(areaCutData.outerArea);
+                               continue;
+                       }
+                       
+                       assert cutPoint.getNumberOfAreas() > 0 : "Number of cut 
areas == 0 in mp "+getId();
+                       
+                       // cut out the holes
+                       for (Area cutArea : cutPoint.getAreas()) {
+                               areaCutData.outerArea.subtract(cutArea);
+                       }
+                       
+                       if (areaCutData.outerArea.isEmpty()) {
+                               // this outer area space can be abandoned
+                               continue;
+                       } 
+                       
+                       // the inner areas of the cut point have been processed
+                       // they are no longer needed
+                       areaCutData.innerAreas.removeAll(cutPoint.getAreas());
 
-                                       // 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);
-                                       }
+                       if (areaCutData.outerArea.isSingular()) {
+                               // the area is singular
+                               // => no further splits necessary
+                               if (areaCutData.innerAreas.isEmpty()) {
+                                       // this area is finished and needs no 
further cutting
+                                       
finishedAreas.add(areaCutData.outerArea);
+                               } else {
+                                       // readd this area to further processing
+                                       areasToCut.add(areaCutData);
+                               }
+                       } else {
+                               // we need to cut the area into two halfs to 
get singular areas
+                               Rectangle r1 = 
cutPoint.getCutRectangleForArea(areaCutData.outerArea, true);
+                               Rectangle r2 = 
cutPoint.getCutRectangleForArea(areaCutData.outerArea, false);
 
-                                       // 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));
+                               // 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 = areaCutData.outerArea;
+                               Area a2 = (Area) a1.clone();
+                               a1.intersect(new Area(r1));
+                               a2.intersect(new Area(r2));
 
-                                       
outerAfterThisStep.addAll(areaToSingularAreas(a1));
-                                       
outerAfterThisStep.addAll(areaToSingularAreas(a2));
+                               if (areaCutData.innerAreas.isEmpty()) {
+                                       
finishedAreas.addAll(areaToSingularAreas(a1));
+                                       
finishedAreas.addAll(areaToSingularAreas(a2));
+                               } else {
+                                       ArrayList<Area> cuttedAreas = new 
ArrayList<Area>();
+                                       
cuttedAreas.addAll(areaToSingularAreas(a1));
+                                       
cuttedAreas.addAll(areaToSingularAreas(a2));
+                                       
+                                       for (Area nextOuterArea : cuttedAreas) {
+                                               ArrayList<Area> nextInnerAreas 
= null;
+                                               // go through all remaining 
inner areas and check if they
+                                               // must be further processed 
with the nextOuterArea 
+                                               for (Area nonProcessedInner : 
areaCutData.innerAreas) {
+                                                       if 
(nextOuterArea.intersects(nonProcessedInner.getBounds2D())) {
+                                                               if 
(nextInnerAreas == null) {
+                                                                       
nextInnerAreas = new ArrayList<Area>();
+                                                               }
+                                                               
nextInnerAreas.add(nonProcessedInner);
+                                                       }
+                                               }
+                                               
+                                               if (nextInnerAreas == null || 
nextInnerAreas.isEmpty()) {
+                                                       
finishedAreas.add(nextOuterArea);
+                                               } else {
+                                                       AreaCutData outCutData 
= new AreaCutData();
+                                                       outCutData.outerArea = 
nextOuterArea;
+                                                       outCutData.innerAreas= 
nextInnerAreas;
+                                                       
areasToCut.add(outCutData);
+                                               }
+                                       }
                                }
                        }
-                       outerAreas = outerAfterThisStep;
+                       
                }
-
+               
                // convert the java.awt.geom.Area back to the mkgmap way
-               List<Way> cutOuterPolygon = new 
ArrayList<Way>(outerAreas.size());
-               for (Area area : outerAreas) {
+               List<Way> cuttedOuterPolygon = new 
ArrayList<Way>(finishedAreas.size());
+               for (Area area : finishedAreas) {
                        Way w = singularAreaToWay(area, 
FakeIdGenerator.makeFakeId());
                        if (w != null) {
                                w.copyTags(outerPolygon);
-                               cutOuterPolygon.add(w);
+                               cuttedOuterPolygon.add(w);
+                               if (log.isDebugEnabled()) {
+                                       log.debug("Way", outerPolygon.getId(), 
"splitted to way", w.getId());
+                               }
                        }
                }
 
-               return cutOuterPolygon;
+               return cuttedOuterPolygon;
        }
 
        /**
@@ -986,22 +1094,18 @@
         * erroneous cases properly the method might return a list of areas.
         * 
         * @param w a closed way
+        * @param clipBbox true if the areas should be clipped to the bounding 
box; false else
         * @return a list of enclosed ares
         */
-       private List<Area> createAreas(Way w) {
+       private List<Area> createAreas(Way w, boolean clipBbox) {
                Area area = new Area(createPolygon(w.getPoints()));
+               if (clipBbox && bboxArea.contains(area.getBounds())==false) {
+                       // the area intersects the bounding box => clip it
+                       area.intersect(bboxArea);
+               }
                List<Area> areaList = areaToSingularAreas(area);
-               if (areaList.size() > 1) {
-                       if (bbox.allInsideBoundary(w.getPoints())) {
-                               log.warn("Polygon", w.getId(), "intersects 
itself. It is splitted into", areaList.size(), "polygons.");
-                               log.warn("The polygon is composed of");
-                               logWayURLs(Level.WARNING, "-", w);
-                       } else {
-                               log.info("Polygon", w.getId(),
-                                       "intersects itself and the tile bounds. 
Maybe the polygon is not completely contained in the tile.");
-                               log.info("The polygon is composed of");
-                               logWayURLs(Level.INFO, "-", w);
-                       }
+               if (log.isDebugEnabled()) {
+                       log.debug("Bbox clipped 
way",w.getId()+"=>",areaList.size(),"distinct area(s).");
                }
                return areaList;
        }
@@ -1182,7 +1286,7 @@
        }
 
        /**
-        * Checks if the polygon with polygonIndex1 contains the ring with 
polygonIndex2.
+        * Checks if the polygon with polygonIndex1 contains the polygon with 
polygonIndex2.
         * 
         * @return true if polygon(polygonIndex1) contains 
polygon(polygonIndex2)
         */
@@ -1644,7 +1748,7 @@
                                }
                        }
                }
-               
+
                public List<Long> getOriginalIds() {
                        ArrayList<Long> idList = new 
ArrayList<Long>(getOriginalWays().size());
                        for (Way w : getOriginalWays()) {
@@ -1688,4 +1792,167 @@
                        this.polygon = polygon;
                }
        }
+
+       private static class AreaCutData {
+               Area outerArea;
+               List<Area> innerAreas;
+       }
+
+       private static class CutPoint implements Comparable<CutPoint>{
+               int startPoint = Integer.MAX_VALUE;
+               int stopPoint = Integer.MIN_VALUE;
+               TreeSet<Area> areas;
+               private final CoordinateAxis axis;
+
+               public CutPoint(CoordinateAxis axis) {
+                       this.axis = axis;
+                       this.areas = new TreeSet<Area>(
+                                       (axis == CoordinateAxis.LONGITUDE ? 
COMP_LONG_STOP : COMP_LAT_STOP));
+               }
+               
+               public CutPoint duplicate() {
+                       CutPoint newCutPoint = new CutPoint(this.axis);
+                       newCutPoint.areas.addAll(areas);
+                       newCutPoint.startPoint = startPoint;
+                       newCutPoint.stopPoint = stopPoint;
+                       return newCutPoint;
+               }
+
+               public int getCutPoint() {
+                       return startPoint + (stopPoint - startPoint) / 2;
+               }
+
+               public Rectangle getCutRectangleForArea(Area toCut, boolean 
firstRect) {
+                       Rectangle areaRect = toCut.getBounds();
+                       if (axis == CoordinateAxis.LONGITUDE) {
+                               int newWidth = getCutPoint()-areaRect.x;
+                               if (firstRect) {
+                                       return new Rectangle(areaRect.x, 
areaRect.y, newWidth, areaRect.height); 
+                               } else {
+                                       return new 
Rectangle(areaRect.x+newWidth, areaRect.y, areaRect.width-newWidth, 
areaRect.height); 
+                               }
+                       } else {
+                               int newHeight = getCutPoint()-areaRect.y;
+                               if (firstRect) {
+                                       return new Rectangle(areaRect.x, 
areaRect.y, areaRect.width, newHeight); 
+                               } else {
+                                       return new Rectangle(areaRect.x, 
areaRect.y+newHeight, areaRect.width, areaRect.height-newHeight); 
+                               }
+                       }
+               }
+               
+               public Collection<Area> getAreas() {
+                       return areas;
+               }
+
+               public void addArea(Area area) {
+                       // remove all areas that do not overlap with the new 
area
+                       while (areas.isEmpty() == false
+                                       && axis.getStop(areas.first()) < axis
+                                                       .getStart(area)) {
+                               // remove the first area
+                               areas.pollFirst();
+                       }
+
+                       areas.add(area);
+                       startPoint = axis.getStart(Collections.max(areas,
+                               (axis == CoordinateAxis.LONGITUDE ? 
COMP_LONG_START
+                                               : COMP_LAT_START)));
+                       stopPoint = axis.getStop(areas.first());
+               }
+
+               public int getNumberOfAreas() {
+                       return this.areas.size();
+               }
+
+               @Override
+               public int compareTo(CutPoint o) {
+                       if (this == o) {
+                               return 0;
+                       }
+                       int ndiff = getNumberOfAreas()-o.getNumberOfAreas();
+                       if (ndiff != 0) {
+                               return ndiff;
+                       }
+                       // prefer the larger area that is splitted
+                       return 
(stopPoint-startPoint)-(o.stopPoint-o.startPoint); 
+               }
+
+               @Override
+               public String toString() {
+                       return axis +" "+getNumberOfAreas()+" "+startPoint+" 
"+stopPoint+" "+getCutPoint();
+               }
+               
+       }
+
+       private static enum CoordinateAxis {
+               LATITUDE(false), LONGITUDE(true);
+
+               private CoordinateAxis(boolean useX) {
+                       this.useX = useX;
+               }
+
+               private final boolean useX;
+
+               public int getStart(Area area) {
+                       return getStart(area.getBounds());
+               }
+
+               public int getStart(Rectangle rect) {
+                       return (useX ? rect.x : rect.y);
+               }
+
+               public int getStop(Area area) {
+                       return getStop(area.getBounds());
+               }
+
+               public int getStop(Rectangle rect) {
+                       return (useX ? rect.x + rect.width : rect.y + 
rect.height);
+               }
+
+       }
+
+       private static final AreaComparator COMP_LONG_START = new 
AreaComparator(
+                       true, CoordinateAxis.LONGITUDE);
+       private static final AreaComparator COMP_LONG_STOP = new AreaComparator(
+                       false, CoordinateAxis.LONGITUDE);
+       private static final AreaComparator COMP_LAT_START = new AreaComparator(
+                       true, CoordinateAxis.LATITUDE);
+       private static final AreaComparator COMP_LAT_STOP = new AreaComparator(
+                       false, CoordinateAxis.LATITUDE);
+
+       private static class AreaComparator implements Comparator<Area> {
+
+               private final CoordinateAxis axis;
+               private final boolean startPoint;
+
+               public AreaComparator(boolean startPoint, CoordinateAxis axis) {
+                       this.startPoint = startPoint;
+                       this.axis = axis;
+               }
+
+               @Override
+               public int compare(Area o1, Area o2) {
+                       if (o1 == o2) {
+                               return 0;
+                       }
+
+                       if (startPoint) {
+                               int cmp = axis.getStart(o1) - axis.getStart(o2);
+                               if (cmp == 0) {
+                                       return axis.getStop(o1) - 
axis.getStop(o2);
+                               } else {
+                                       return cmp;
+                               }
+                       } else {
+                               int cmp = axis.getStop(o1) - axis.getStop(o2);
+                               if (cmp == 0) {
+                                       return axis.getStart(o1) - 
axis.getStart(o2);
+                               } else {
+                                       return cmp;
+                               }
+                       }
+               }
+
+       }
 }
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to