Hi Gerd I'd been doing some investigation of filters ordering (based on trunk). I'd also done the pre-filtering of lines & shapes by minRes.
My conclusions are: Shapes: It is better to run SizeFilter after RemoveObsoleteFilter. It is more efficient to run DP filter after both of these. Lines: LineSplitterFilter should be run after everything that can remove points. It is more efficient to run DP after RemoveObsoleteFilter. I've adapted my changes into a patch for the low-res-opt branch, along with removal of some resolution tests that are now redundant. For the contourFilters, I've left DP as the first filter but moved LineSplitter as for the normalFilters Ticker
Index: src/uk/me/parabola/mkgmap/build/MapBuilder.java =================================================================== --- src/uk/me/parabola/mkgmap/build/MapBuilder.java (revision 4731) +++ src/uk/me/parabola/mkgmap/build/MapBuilder.java (working copy) @@ -915,12 +915,15 @@ processPoints(map, div, points); final int res = z.getResolution(); - lines = lines.stream().filter(l -> l.getMinResolution() <= res).collect(Collectors.toList()); - shapes = shapes.stream().filter(s -> s.getMinResolution() <= res).collect(Collectors.toList()); - + final int level = z.getLevel(); + if (level != 0) { + lines = lines.stream().filter(l -> l.getMinResolution() <= res).collect(Collectors.toList()); + shapes = shapes.stream().filter(s -> s.getMinResolution() <= res).collect(Collectors.toList()); + } + if (mergeLines) { - LineMergeFilter merger = new LineMergeFilter(); - lines = merger.merge(lines, res, !hasNet, allowReverseMerge); + LineMergeFilter lineMergeFilter = new LineMergeFilter(); + lines = lineMergeFilter.merge(lines, res, !hasNet, allowReverseMerge); } if (mergeShapes) { @@ -930,7 +933,7 @@ // recalculate preserved status for all points in lines and shapes shapes.forEach(e -> e.getPoints().forEach(p -> p.preserved(false))); - if (z.getLevel() == 0 && hasNet) { + if (level == 0 && hasNet) { lines.forEach(e -> e.getPoints().forEach(p -> p.preserved(p.isNumberNode()))); } else { lines.forEach(e -> e.getPoints().forEach(p -> p.preserved(false))); @@ -1218,12 +1221,14 @@ * Note that the location and resolution of map elements is relative to the * subdivision that they occur in. * - * @param map The map to add points to. + * @param map The map to add lines to. * @param div The subdivision that the lines belong to. * @param lines The lines to be added. */ private void processLines(Map map, Subdivision div, List<MapLine> lines) { div.startLines(); // Signal that we are beginning to draw the lines. + if (lines.size() == 0) + return; int res = div.getResolution(); @@ -1234,6 +1239,7 @@ LayerFilterChain normalFilters = new LayerFilterChain(config); LayerFilterChain contourFilters = new LayerFilterChain(config); + DouglasPeuckerFilter dp = null; if (enableLineCleanFilters && (res < 24)) { MapFilter rounder = new RoundCoordsFilter(); MapFilter sizeFilter = new SizeFilter(MIN_SIZE_LINE); @@ -1240,32 +1246,33 @@ normalFilters.addFilter(rounder); normalFilters.addFilter(sizeFilter); double errorForRes = dpFilterLineLevelMap.ceilingEntry(res).getValue(); - if(errorForRes > 0) { - DouglasPeuckerFilter dp = new DouglasPeuckerFilter(errorForRes); - normalFilters.addFilter(dp); + if (errorForRes > 0) { + dp = new DouglasPeuckerFilter(errorForRes); contourFilters.addFilter(dp); + // normalFilter dp is run after removeObsolete. Should be more efficient } contourFilters.addFilter(rounder); contourFilters.addFilter(sizeFilter); } + RemoveObsoletePointsFilter removeObsolete = new RemoveObsoletePointsFilter(); + normalFilters.addFilter(removeObsolete); + contourFilters.addFilter(removeObsolete); + if (dp != null) + normalFilters.addFilter(dp); for (MapFilter filter : Arrays.asList( - new LineSplitterFilter(), new RemoveEmpty(), - new RemoveObsoletePointsFilter(), - new LinePreparerFilter(div), + new LineSplitterFilter(), + new LinePreparerFilter(div), new LineAddFilter(div, map))) { normalFilters.addFilter(filter); contourFilters.addFilter(filter); } - - for (MapLine line : lines) { - if (line.getMinResolution() <= res) { - if (GType.isContourLine(line)) - contourFilters.startFilter(line); - else - normalFilters.startFilter(line); - } - } + + for (MapLine line : lines) + if (GType.isContourLine(line)) + contourFilters.startFilter(line); + else + normalFilters.startFilter(line); } /** @@ -1281,6 +1288,8 @@ */ private void processShapes(Map map, Subdivision div, List<MapShape> shapes) { div.startShapes(); // Signal that we are beginning to draw the shapes. + if (shapes.size() == 0) + return; int res = div.getResolution(); @@ -1288,36 +1297,34 @@ config.setResolution(res); config.setLevel(div.getZoom().getLevel()); config.setHasNet(hasNet); - + if (orderByDecreasingArea && shapes.size() > 1) { // sort so that the shape with the largest area is processed first shapes.sort((s1,s2) -> Long.compare(Math.abs(s2.getFullArea()), Math.abs(s1.getFullArea()))); } - LayerFilterChain filters = new LayerFilterChain(config); - filters.addFilter(new PolygonSplitterFilter()); + filters.addFilter(new PolygonSplitterFilter()); // must be before RoundCoordsFilter. This only splits shape if later filter (ie LinePreparerFilter) raises MustSplitException if (enableLineCleanFilters && (res < 24)) { filters.addFilter(new RoundCoordsFilter()); - int sizefilterVal = getMinSizePolygonForResolution(res); + } + filters.addFilter(new RemoveObsoletePointsFilter()); + if (enableLineCleanFilters && (res < 24)) { + int sizefilterVal = getMinSizePolygonForResolution(res); if (sizefilterVal > 0) - filters.addFilter(new SizeFilter(sizefilterVal)); + filters.addFilter(new SizeFilter(sizefilterVal)); // best after possible spike removal //DouglasPeucker behaves at the moment not really optimal at low zooms, but acceptable. //Is there a similar algorithm for polygons? double errorForRes = dpFilterShapeLevelMap.ceilingEntry(res).getValue(); - if(errorForRes > 0) + if (errorForRes > 0) filters.addFilter(new DouglasPeuckerFilter(errorForRes)); } - filters.addFilter(new RemoveObsoletePointsFilter()); filters.addFilter(new RemoveEmpty()); filters.addFilter(new LinePreparerFilter(div)); filters.addFilter(new ShapeAddFilter(div, map)); - for (MapShape shape : shapes) { - if (shape.getMinResolution() <= res) { - filters.startFilter(shape); - } - } + for (MapShape shape : shapes) + filters.startFilter(shape); } /** @@ -1331,11 +1338,7 @@ * @param shapes list of shapes */ private static void preserveHorizontalAndVerticalLines(int res, List<MapShape> shapes) { - if (res == 24) - return; for (MapShape shape : shapes) { - if (shape.getMinResolution() > res) - continue; int minLat = shape.getBounds().getMinLat(); int maxLat = shape.getBounds().getMaxLat(); int minLon = shape.getBounds().getMinLong();
_______________________________________________ mkgmap-dev mailing list mkgmap-dev@lists.mkgmap.org.uk https://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev