This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository mkgmap-splitter.
commit ae5312526df0d44b2d64fd80df523487be93894f Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Thu Nov 17 07:35:35 2016 +0100 Imported Upstream version 0.0.0+svn440 --- resources/splitter-version.properties | 4 +- src/uk/me/parabola/splitter/Area.java | 16 ++- src/uk/me/parabola/splitter/Main.java | 150 ++++++++++++--------- .../me/parabola/splitter/ProblemListProcessor.java | 11 +- src/uk/me/parabola/splitter/SplitProcessor.java | 22 +-- 5 files changed, 116 insertions(+), 87 deletions(-) diff --git a/resources/splitter-version.properties b/resources/splitter-version.properties index cfac89c..0c859d8 100644 --- a/resources/splitter-version.properties +++ b/resources/splitter-version.properties @@ -1,2 +1,2 @@ -svn.version: 439 -build.timestamp: 2016-08-14T12:27:57+0100 +svn.version: 440 +build.timestamp: 2016-11-16T11:19:34+0000 diff --git a/src/uk/me/parabola/splitter/Area.java b/src/uk/me/parabola/splitter/Area.java index 27c15dc..b730a81 100644 --- a/src/uk/me/parabola/splitter/Area.java +++ b/src/uk/me/parabola/splitter/Area.java @@ -188,12 +188,16 @@ public class Area { ); } - public boolean isResultOfSplitting() { - return isResultOfSplitting; - } - - public void setResultOfSplitting(boolean isResultOfSplitting) { - this.isResultOfSplitting = isResultOfSplitting; + /** + * + * @param other an area + * @return true if the other area is inside the Area (it may touch the boundary) + */ + public final boolean contains(Area other) { + return other.getMinLat() >= minLat + && other.getMaxLat() <= maxLat + && other.getMinLong() >= minLong + && other.getMaxLong() <= maxLong; } public boolean isPseudoArea() { diff --git a/src/uk/me/parabola/splitter/Main.java b/src/uk/me/parabola/splitter/Main.java index 186f25a..deca79b 100644 --- a/src/uk/me/parabola/splitter/Main.java +++ b/src/uk/me/parabola/splitter/Main.java @@ -24,6 +24,7 @@ import uk.me.parabola.splitter.geo.City; import uk.me.parabola.splitter.geo.CityFinder; import uk.me.parabola.splitter.geo.CityLoader; import uk.me.parabola.splitter.geo.DefaultCityFinder; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.shorts.ShortArrayList; @@ -41,11 +42,13 @@ import java.io.PrintWriter; import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import java.util.regex.Pattern; @@ -133,7 +136,7 @@ public class Main { private TreeSet<Long> calculatedProblemRels = new TreeSet<>(); // map with relations that should be complete and are written to only one tile - private final OSMId2ObjectMap<Short> oneTileOnlyRels = new OSMId2ObjectMap<>(); + private final Long2ObjectOpenHashMap<Integer> oneTileOnlyRels = new Long2ObjectOpenHashMap<>(); // for faster access on blocks in pbf files private final HashMap<String, ShortArrayList> blockTypeMap = new HashMap<>(); @@ -314,15 +317,17 @@ public class Main { System.out.println(); } + List<Area> distinctAreas = null; if (keepComplete){ - partitionAreasForProblemListGenerator(areas); + distinctAreas = genProblemLists(areas); if ("gen-problem-list".equals(stopAfter)){ try {Thread.sleep(1000);}catch (InterruptedException e) {} System.err.println("stopped after " + stopAfter); throw new StopNoErrorException("stopped after " + stopAfter); } + } - writeAreas(areas); + writeAreas(areas, distinctAreas); } private int getAreasPerPass(int areaCount) { @@ -691,13 +696,35 @@ public class Main { /** * Calculate lists of ways and relations that will be split for a given list * of areas. - * @param areas the list of areas - * @param partition used for informational messages + * @param distinctAreas the list of areas + * @return * @throws IOException * @throws XmlPullParserException */ - private void genProblemLists(List<Area> areas, int partition) throws IOException, XmlPullParserException { - List<Area> workAreas = addPseudoWriters(areas); + private ArrayList<Area> genProblemLists(List<Area> realAreas) throws IOException, XmlPullParserException { + long startProblemListGenerator = System.currentTimeMillis(); + + ArrayList<Area> distinctAreas = getNonOverlappingAreas(realAreas); + if (distinctAreas.size() > realAreas.size()) { + System.err.println("Waring: The areas given in --split-file are overlapping. Support for this might be removed in future versions."); + Set<Integer> overlappingTiles = new TreeSet<>(); + for (int i = 0; i < realAreas.size(); i++) { + Area a1 = realAreas.get(i); + for (int j = i+1; j < realAreas.size(); j++) { + Area a2 = realAreas.get(j); + if (a1.getRect().intersects(a2.getRect())) { + overlappingTiles.add(a1.getMapId()); + overlappingTiles.add(a2.getMapId()); + } + } + } + if (!overlappingTiles.isEmpty()) { + System.out.println("Overlaping tiles: " + overlappingTiles.toString()); + } + } + System.out.println("Generating problem list for " + distinctAreas.size() + " distinct areas"); + List<Area> workAreas = addPseudoWriters(distinctAreas); + // debugging /* @@ -712,9 +739,9 @@ public class Main { int numPasses = getAreasPerPass(workAreas.size()); int areasPerPass = (int) Math.ceil((double) workAreas.size() / (double) numPasses); if (numPasses > 1) { - System.out.println("Processing " + areas.size() + " areas in " + numPasses + " passes, " + areasPerPass + " areas at a time"); + System.out.println("Processing " + distinctAreas.size() + " areas in " + numPasses + " passes, " + areasPerPass + " areas at a time"); } else { - System.out.println("Processing " + areas.size() + " areas in a single pass"); + System.out.println("Processing " + distinctAreas.size() + " areas in a single pass"); } OSMWriter [] writers = new OSMWriter[workAreas.size()]; @@ -729,12 +756,12 @@ public class Main { System.out.println("Pseudo area " + area.getMapId() + " covers " + area); } DataStorer dataStorer = new DataStorer(writers); - System.out.println("Starting problem-list-generator pass(es) for partition " + partition); + System.out.println("Starting problem-list-generator pass(es)"); LongArrayList problemWaysThisPart = new LongArrayList(); LongArrayList problemRelsThisPart = new LongArrayList(); for (int pass = 0; pass < numPasses; pass++) { System.out.println("-----------------------------------"); - System.out.println("Starting problem-list-generator pass " + (pass+1) + " of " + numPasses + " for partition " + partition); + System.out.println("Starting problem-list-generator pass " + (pass+1) + " of " + numPasses); long startThisPass = System.currentTimeMillis(); int writerOffset = pass * areasPerPass; int numWritersThisPass = Math.min(areasPerPass, workAreas.size() - pass * areasPerPass); @@ -747,62 +774,33 @@ public class Main { while (!done){ done = processMap(processor); } - System.out.println("Problem-list-generator pass " + (pass+1) + " for partition " + partition+ " took " + (System.currentTimeMillis() - startThisPass) + " ms"); + System.out.println("Problem-list-generator pass " + (pass+1) + " took " + (System.currentTimeMillis() - startThisPass) + " ms"); } //writeProblemList("problem-candidates-partition-" + partition + ".txt", problemWaysThisPart, problemRelsThisPart); calculatedProblemWays.addAll(problemWaysThisPart); calculatedProblemRels.addAll(problemRelsThisPart); - } - - /** - * Separate a list of areas into parts so that no part has overlapping areas. - * If the areas were read from a split-file, they might overlap. - * For the problem-list processing we need disjoint areas. - * @param realAreas the list of areas (either from file or calculated by 1st pass) - * @throws IOException - * @throws XmlPullParserException - */ - private void partitionAreasForProblemListGenerator(List<Area> realAreas) throws IOException, XmlPullParserException{ - long startProblemListGenerator = System.currentTimeMillis(); - - List<Area> remainingAreas = new ArrayList<>(realAreas); - List<Area> distinctAreas; - int partition = 0; - while (remainingAreas.size() > 0){ - ++partition; - List<Area> workingSet = new ArrayList<>(remainingAreas); - distinctAreas = getNonOverlappingAreas(workingSet, true); - if (distinctAreas.size() * 1.25 > maxAreasPerPass){ - workingSet = new ArrayList<>(remainingAreas); - distinctAreas = getNonOverlappingAreas(workingSet, false); - } - System.out.println("Generating problem list for " + distinctAreas.size() + " distinct areas"); - genProblemLists(distinctAreas, partition); - remainingAreas = workingSet; - - } System.out.println("Problem-list-generator pass(es) took " + (System.currentTimeMillis() - startProblemListGenerator) + " ms"); - if (partition > 1){ + if (distinctAreas.size() > realAreas.size()) { // correct wrong entries caused by partitioning for (Long id: calculatedProblemRels){ oneTileOnlyRels.remove(id); } - System.err.println("Waring: The areas given in --split-file are overlapping. Support for this will be removed in future versions."); } if (problemReport != null){ writeProblemList(problemReport, calculatedProblemWays, calculatedProblemRels); } + return distinctAreas; } - - + /** * Final pass(es), we have the areas so parse the file(s) again. * * @param areas Area list determined on the first pass. + * @param distinctAreas */ - private void writeAreas(List<Area> areas) throws IOException, XmlPullParserException { + private void writeAreas(List<Area> areas, List<Area> distinctAreas) throws IOException, XmlPullParserException { OSMWriter[] allWriters = new OSMWriter[areas.size()]; Map<String, byte[]> wellKnownTagKeys = null; Map<String, byte[]> wellKnownTagVals = null; @@ -867,6 +865,7 @@ public class Main { int numPasses = getAreasPerPass(areas.size()); int areasPerPass = (int) Math.ceil((double) areas.size() / (double) numPasses); DataStorer dataStorer = new DataStorer(allWriters); + translateDistinctToRealAreas (dataStorer, distinctAreas, areas); // add the user given problem polygons problemWays.addAll(calculatedProblemWays); calculatedProblemWays = null; @@ -931,6 +930,39 @@ public class Main { } + /** + * If the Bitset ids in oneTileOnlyRels were produced with a different set of + * writers we have to translate the values + * @param dataStorer DataStorer instance used by split processor + * @param distinctAreas list of distinct (non-overlapping) areas + * @param areas list of areas from split-file (or calculation) + */ + private void translateDistinctToRealAreas(DataStorer dataStorer, List<Area> distinctAreas, List<Area> areas) { + if (oneTileOnlyRels.isEmpty() || distinctAreas.size() == areas.size()) + return; + Map<Area, Integer> map = new HashMap<>(); + for (Area distinctArea : distinctAreas) { + if (distinctArea.getMapId() < 0 && !distinctArea.isPseudoArea()) { + BitSet w = new BitSet(); + for (int i = 0; i < areas.size(); i++) { + if (areas.get(i).contains(distinctArea)) { + w.set(i); + } + } + int id = dataStorer.getMultiTileWriterDictionary().translate(w); + map.put(distinctArea, id); + } + } + if (!map.isEmpty()) { + + for ( Entry<Long, Integer> e: oneTileOnlyRels.entrySet()) { + if (e.getValue() >= 0) { + e.setValue(map.get(distinctAreas.get(e.getValue()))); + } + } + } + } + private boolean processMap(MapProcessor processor) throws XmlPullParserException { boolean done = processOSMFiles(processor, fileNameList); return done; @@ -1085,37 +1117,24 @@ public class Main { * Create a list of areas that do not overlap. If areas in the original * list are overlapping, they can be replaced by up to 5 disjoint areas. * This is done if parameter makeDisjoint is true - * @param realAreas the list of areas (is modified in this method) - * @param makeDisjoint if true, replace overlapping areas by disjoint ones + * @param realAreas the list of areas * @return the new list */ - private static ArrayList<Area> getNonOverlappingAreas(List<Area> realAreas, boolean makeDisjoint){ + private static ArrayList<Area> getNonOverlappingAreas(final List<Area> realAreas){ java.awt.geom.Area covered = new java.awt.geom.Area(); ArrayList<Area> splitList = new ArrayList<>(); int artificialId = -99999999; boolean foundOverlap = false; - Iterator<Area> realAreaIter = realAreas.iterator(); - - while (realAreaIter.hasNext()){ - Area area1 = realAreaIter.next(); + for (Area area1 : realAreas) { Rectangle r1 = area1.getRect(); if (covered.intersects(r1) == false){ splitList.add(area1); - realAreaIter.remove(); } else { - if (makeDisjoint == false) - continue; - //check if area is completely within covered area - java.awt.geom.Area copyArea = new java.awt.geom.Area(area1.getJavaArea()); - copyArea.subtract(covered); - if (copyArea.isEmpty()) - continue; - if (makeDisjoint && foundOverlap == false){ + if (foundOverlap == false){ foundOverlap = true; System.out.println("Removing overlaps from tiles..."); } - realAreaIter.remove(); //String msg = "splitting " + area1.getMapId() + " " + (i+1) + "/" + realAreas.size() + " overlapping "; // find intersecting areas in the already covered part ArrayList<Area> splitAreas = new ArrayList<>(); @@ -1134,7 +1153,6 @@ public class Main { //msg += area2.getMapId() + " "; Area aNew = new Area(ro.y, ro.x, (int)ro.getMaxY(),(int)ro.getMaxX()); aNew.setMapId(artificialId++); - aNew.setResultOfSplitting(true); aNew.setName("" + area1.getMapId()); aNew.setJoinable(false); covered.subtract(area2.getJavaArea()); @@ -1186,7 +1204,6 @@ public class Main { if (k==1 || covered.intersects(test) == false){ aNew = new Area(test.y,test.x,(int)test.getMaxY(),(int)test.getMaxX()); aNew.setMapId(areaPair[k].getMapId()); - aNew.setResultOfSplitting(true); splitAreas.add(aNew); covered.add(aNew.getJavaArea()); } @@ -1216,7 +1233,6 @@ public class Main { if (doJoin){ splitArea = area.add(splitArea); splitArea.setMapId(area.getMapId()); - splitArea.setResultOfSplitting(true); splitList.set(j, splitArea); splitArea = null; // don't add later break; @@ -1465,4 +1481,6 @@ public class Main { boolean done = processor.endMap(); return done; } + + } diff --git a/src/uk/me/parabola/splitter/ProblemListProcessor.java b/src/uk/me/parabola/splitter/ProblemListProcessor.java index 40f11dd..11511a1 100644 --- a/src/uk/me/parabola/splitter/ProblemListProcessor.java +++ b/src/uk/me/parabola/splitter/ProblemListProcessor.java @@ -13,7 +13,7 @@ package uk.me.parabola.splitter; import uk.me.parabola.splitter.Relation.Member; - +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArrayList; import java.util.Arrays; @@ -43,7 +43,7 @@ class ProblemListProcessor extends AbstractMapProcessor { private final DataStorer dataStorer; private LongArrayList problemWays; private LongArrayList problemRels; - private final OSMId2ObjectMap<Short> oneTileOnlyRels; + private final Long2ObjectOpenHashMap<Integer> oneTileOnlyRels; private BitSet writerSet; @@ -63,7 +63,7 @@ class ProblemListProcessor extends AbstractMapProcessor { ProblemListProcessor(DataStorer dataStorer, int writerOffset, int numWritersThisPass, LongArrayList problemWays, - LongArrayList problemRels, OSMId2ObjectMap<Short> oneTileOnlyRels, + LongArrayList problemRels, Long2ObjectOpenHashMap<Integer> oneTileOnlyRels, String[] boundaryTagList) { this.dataStorer = dataStorer; this.writerDictionary = dataStorer.getWriterDictionary(); @@ -209,6 +209,7 @@ class ProblemListProcessor extends AbstractMapProcessor { maybeChanged = true; } } + if (!isFirstPass && maybeChanged || isLastPass){ wayWriterIdx = ways.get(way.getId()); if (wayWriterIdx != UNASSIGNED) @@ -328,7 +329,7 @@ class ProblemListProcessor extends AbstractMapProcessor { } } // find out if it was already processed in a previous partition of tiles - Short writerInOtherPartition = oneTileOnlyRels.get(rel.getId()); + Integer writerInOtherPartition = oneTileOnlyRels.get(rel.getId()); if (newWriterIdx >= 0){ // the relation is written to a real tile in this partition @@ -342,7 +343,7 @@ class ProblemListProcessor extends AbstractMapProcessor { // store the info that the rel is only in one tile, but // don't overwrite the info when it was a real tile if (writerInOtherPartition == null || writerInOtherPartition < 0){ - oneTileOnlyRels.put(rel.getId(), (short) newWriterIdx); + oneTileOnlyRels.put(rel.getId(), new Integer(newWriterIdx)); } } return; diff --git a/src/uk/me/parabola/splitter/SplitProcessor.java b/src/uk/me/parabola/splitter/SplitProcessor.java index 959ff99..33ac5b5 100644 --- a/src/uk/me/parabola/splitter/SplitProcessor.java +++ b/src/uk/me/parabola/splitter/SplitProcessor.java @@ -21,6 +21,8 @@ import java.util.Date; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; + /** * Splits a map into multiple areas. */ @@ -34,7 +36,7 @@ class SplitProcessor extends AbstractMapProcessor { private final Long2IntClosedMapFunction nodeWriterMap; private final Long2IntClosedMapFunction wayWriterMap; private final Long2IntClosedMapFunction relWriterMap; - private final OSMId2ObjectMap<Short> oneTileOnlyRels; + private final Long2ObjectOpenHashMap<Integer> oneTileOnlyRels; // for statistics private long countQuickTest = 0; @@ -59,7 +61,7 @@ class SplitProcessor extends AbstractMapProcessor { private BitSet usedWriters; - SplitProcessor(DataStorer dataStorer, OSMId2ObjectMap<Short> oneTileOnlyRels, + SplitProcessor(DataStorer dataStorer, Long2ObjectOpenHashMap<Integer> oneTileOnlyRels, int writerOffset, int numWritersThisPass, int maxThreads){ this.dataStorer = dataStorer; this.oneTileOnlyRels = oneTileOnlyRels; @@ -161,18 +163,24 @@ class SplitProcessor extends AbstractMapProcessor { @Override public void processRelation(Relation rel) { currentRelAreaSet.clear(); - Short singleTileWriterIdx = oneTileOnlyRels.get(rel.getId()); + Integer singleTileWriterIdx = oneTileOnlyRels.get(rel.getId()); if (singleTileWriterIdx != null){ - if (singleTileWriterIdx < writerOffset || singleTileWriterIdx > lastWriter) + if (singleTileWriterIdx < 0) { return; - currentRelAreaSet.set(singleTileWriterIdx); + } + + BitSet wl = dataStorer.getMultiTileWriterDictionary().getBitSet(singleTileWriterIdx); + // set only active writer bits + for (int i = wl.nextSetBit(writerOffset); i >= 0 && i <= lastWriter; i = wl.nextSetBit(i + 1)) { + currentRelAreaSet.set(i); + } } else { int multiTileWriterIdx = (relWriterMap != null) ? relWriterMap.getSeq(rel.getId()): WriterDictionaryInt.UNASSIGNED; if (multiTileWriterIdx != WriterDictionaryInt.UNASSIGNED){ BitSet cl = dataStorer.getMultiTileWriterDictionary().getBitSet(multiTileWriterIdx); // set only active writer bits - for(int i=cl.nextSetBit(writerOffset); i>=0 && i <= lastWriter; i=cl.nextSetBit(i+1)){ + for (int i = cl.nextSetBit(writerOffset); i >= 0 && i <= lastWriter; i = cl.nextSetBit(i + 1)) { currentRelAreaSet.set(i); } } @@ -191,9 +199,7 @@ class SplitProcessor extends AbstractMapProcessor { currentRelAreaSet.or(wl); } oldclIndex = clIdx; - } - } else if (mem.getType().equals("way")) { short wlIdx = ways.get(id); -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mkgmap-splitter.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel