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