[mkgmap-dev] mkgmap-dev Digest, Vol 153, Issue 40 Resolution 23 raster problems
From Andrzej Popowski popej at poczta.onet.pl on Tue Apr 27 16:16:31 BST 2021
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 -------------- next part -------------- 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); + } + } + } +}
- Previous message: [mkgmap-dev] mkgmap-dev Digest, Vol 153, Issue 40 Resolution 23 raster problems
- Next message: [mkgmap-dev] mkgmap-dev Digest, Vol 153, Issue 40 Resolution 23 raster problems
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the mkgmap-dev mailing list