Hi,

some more experiments, see attached patch. I have tried to optimize rounding of coordinates for lowest distance to line. This is not good for polygons, because can creates gaps between adjacent polygons.

--
Best regards,
Andrzej
Index: src/uk/me/parabola/mkgmap/build/MapBuilder.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/MapBuilder.java     (revision 4685)
+++ src/uk/me/parabola/mkgmap/build/MapBuilder.java     (working copy)
@@ -87,6 +87,7 @@
 import uk.me.parabola.mkgmap.filters.RemoveEmpty;
 import uk.me.parabola.mkgmap.filters.RemoveObsoletePointsFilter;
 import uk.me.parabola.mkgmap.filters.RoundCoordsFilter;
+import uk.me.parabola.mkgmap.filters.RoundCoordsFilter2;
 import uk.me.parabola.mkgmap.filters.ShapeMergeFilter;
 import uk.me.parabola.mkgmap.filters.SizeFilter;
 import uk.me.parabola.mkgmap.general.CityInfo;
@@ -1188,10 +1189,10 @@
                
                LayerFilterChain filters = new LayerFilterChain(config);
                if (enableLineCleanFilters && (res < 24)) {
-                       filters.addFilter(new RoundCoordsFilter());
                        filters.addFilter(new SizeFilter(MIN_SIZE_LINE));
                        if(reducePointError > 0)
                                filters.addFilter(new 
DouglasPeuckerFilter(reducePointError));
+                       filters.addFilter(new RoundCoordsFilter2());
                }
                filters.addFilter(new LineSplitterFilter());
                filters.addFilter(new RemoveEmpty());
@@ -1243,7 +1244,6 @@
                LayerFilterChain filters = new LayerFilterChain(config);
                filters.addFilter(new PolygonSplitterFilter());
                if (enableLineCleanFilters && (res < 24)) {
-                       filters.addFilter(new RoundCoordsFilter());
                        int sizefilterVal =  
getMinSizePolygonForResolution(res);
                        if (sizefilterVal > 0)
                                filters.addFilter(new 
SizeFilter(sizefilterVal));
@@ -1251,6 +1251,7 @@
                        //Is there an similar algorithm for polygons?
                        if(reducePointErrorPolygon > 0)
                                filters.addFilter(new 
DouglasPeuckerFilter(reducePointErrorPolygon));
+                       filters.addFilter(new RoundCoordsFilter());
                }
                filters.addFilter(new RemoveObsoletePointsFilter());
                filters.addFilter(new RemoveEmpty());
Index: src/uk/me/parabola/mkgmap/filters/RoundCoordsFilter2.java
===================================================================
--- src/uk/me/parabola/mkgmap/filters/RoundCoordsFilter2.java   (nonexistent)
+++ src/uk/me/parabola/mkgmap/filters/RoundCoordsFilter2.java   (working copy)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007 Steve Ratcliffe
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ * 
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapRoad;
+
+public class RoundCoordsFilter2 implements MapFilter {
+
+       private int shift;
+       private boolean keepNodes;
+       private int level;
+
+       @Override
+       public void init(FilterConfig config) {
+               shift = config.getShift();
+               level = config.getLevel();
+               keepNodes = level == 0 && config.hasNet();
+       }
+
+       /**
+        * @param element A map element that will be a line or a polygon.
+        * @param next This is used to pass the possibly transformed element 
onward.
+        */
+       @Override
+       public void doFilter(MapElement element, MapFilterChain next) {
+               if (shift == 0) {
+                       // do nothing
+                       next.doFilter(element);
+               } else {
+                       MapLine line = (MapLine) element;
+                       int full = 1 << shift;
+                       int half = 1 << (shift - 1);    // 0.5 shifted
+                       int mask = ~((1 << shift) - 1); // to remove fraction 
bits
+                       
+                       // round lat/lon values to nearest for shift
+                       List<Coord> newPoints = new 
ArrayList<>(line.getPoints().size());
+
+                       List<Coord> coords = line.getPoints();
+                       int endIndex = coords.size() -1;
+
+                       Coord lastP = null;
+                       boolean hasNumbers = level == 0 && line.isRoad() && 
((MapRoad) line).getRoadDef().hasHouseNumbers();
+                       for(int i = 0; i <= endIndex; i++) {
+                               Coord p = coords.get(i);
+                               if (level > 0 && p.isAddedNumberNode()) {
+                                       // ignore nodes added by housenumber 
processing for levels > 0   
+                                       continue;
+                               }
+
+                               Coord newP;
+                               if (p instanceof CoordNode && keepNodes) {
+                                       int lat = (p.getLatitude() + half) & 
mask;
+                                       int lon = (p.getLongitude() + half) & 
mask;
+                                       newP = new CoordNode(lat, lon, 
p.getId(), p.getOnBoundary(), p.getOnCountryBorder());
+                               } else if (i == 0 || i == endIndex) {
+                                       int lat = (p.getLatitude() + half) & 
mask;
+                                       int lon = (p.getLongitude() + half) & 
mask;
+                                       newP = new Coord(lat, lon);
+                                       newP.preserved(p.preserved());
+                                       newP.setNumberNode(hasNumbers && 
p.isNumberNode());
+                               } else { // find best match
+                                       Coord a = coords.get(i -1);
+                                       Coord b = coords.get(i +1);
+
+                                       // point 0,0
+                                       int lat = p.getLatitude() & mask;
+                                       int lon = p.getLongitude() & mask;
+                                       newP = new Coord(lat, lon);
+                                       double distance = 
newP.shortestDistToLineSegment(a, p) + newP.shortestDistToLineSegment(p, b);
+
+                                       Coord testP;
+                                       double testDistance;
+
+                                       // point 0,1
+                                       lon = (p.getLongitude() + full) & mask;
+                                       testP = new Coord(lat, lon);
+                                       testDistance = 
testP.shortestDistToLineSegment(a, p) + testP.shortestDistToLineSegment(p, b);
+                                       if (testDistance < distance) {
+                                               distance = testDistance;
+                                               newP = testP;
+                                       }
+
+                                       // point 1,1
+                                       lat = (p.getLatitude() + full) & mask;
+                                       testP = new Coord(lat, lon);
+                                       testDistance = 
testP.shortestDistToLineSegment(a, p) + testP.shortestDistToLineSegment(p, b);
+                                       if (testDistance < distance) {
+                                               distance = testDistance;
+                                               newP = testP;
+                                       }
+
+                                       // point 1,0
+                                       lon = p.getLongitude() & mask;
+                                       testP = new Coord(lat, lon);
+                                       testDistance = 
testP.shortestDistToLineSegment(a, p) + testP.shortestDistToLineSegment(p, b);
+                                       if (testDistance < distance) {
+                                               distance = testDistance;
+                                               newP = testP;
+                                       }
+
+                                       newP.preserved(p.preserved());
+                                       newP.setNumberNode(hasNumbers && 
p.isNumberNode());
+                               }
+                               
+                               // only add the new point if it has different
+                               // coordinates to the last point or if it's a
+                               // special node
+                               if (lastP == null || !lastP.equals(newP) || 
newP.getId() > 0 || (hasNumbers && newP.isNumberNode())) {
+                                       newPoints.add(newP);
+                                       lastP = newP;
+                               } else if (newP.preserved()) {
+                                       // this point is not going to be used 
because it
+                                       // has the same (rounded) coordinates 
as the last
+                                       // node but it has been marked as being 
"preserved" -
+                                       // transfer that property to the 
previous point so
+                                       // that it's not lost in further filters
+                                       lastP.preserved(true);
+                               }
+                       }
+                       if (newPoints.size() > 1) {
+                               MapLine newLine = line.copy();
+                               newLine.setPoints(newPoints);
+                               next.doFilter(newLine);
+                       }
+               }
+       }
+}
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
https://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to