Hi Gerd

You might consider the some of the ideas here as improvements to the
initial parts of MP processing.

This is a patch based on trunk rather than the new branch. It isn't
structured as for final usage, rather for minimising the spread of
changes, working in parallel with the existing code so I could see if
found the same MP problems as the existing code and having clearly
identifiable diagnostics in the log file.

Ticker
Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java	(revision 4614)
+++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java	(working copy)
@@ -37,6 +37,8 @@
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.logging.Level;
 import java.util.stream.Collectors;
+//%%%RWB
+import uk.me.parabola.util.MultiIdentityHashMap;
 
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.log.Logger;
@@ -61,6 +63,7 @@
 	private static final short TKM_MP_ROLE = TagDict.getInstance().xlate("mkgmap:mp_role");
 	private static final short TKM_CACHE_AREA_SIZEKEY = TagDict.getInstance().xlate("mkgmap:cache_area_size");
 	private final Map<Long, Way> tileWayMap;
+	//%%%RWB get rid of following
 	private final Map<Long, String> roleMap = new HashMap<>();
  
 	private Map<Long, Way> mpPolygons = new LinkedHashMap<>();
@@ -120,6 +123,7 @@
 			log.debug("Construct multipolygon", toBrowseURL(), toTagString());
 		}
 
+		//%%%RWB just copy the whole thing (need to make protected), there are duplicates, but sometimes these are needed
 		for (Map.Entry<String, Element> pair : other.getElements()) {
 			String role = pair.getKey();
 			Element el = pair.getValue();
@@ -764,6 +768,9 @@
 	public void processElements() {
 		log.info("Processing multipolygon", toBrowseURL());
 		
+		//%%%RWB
+		makePolygons();
+
 		List<Way> allWays = getSourceWays();
 		
 		// check if it makes sense to process the mp 
@@ -1952,7 +1959,157 @@
 		return Math.abs(areaSize);
 	}
 
+	/* %%%RWB
+alternate logic for:
+  getSourceWays()
+  joinWays() * 2
+  +
+  getRole()
+  closeWays (partial)
+  removeUnclosedWays()
 
+maybe not needed now:
+  connectUnclosedWays
+  etc
+	 */
+	private void makePolygons() {
+		log.warn("%%%RWB make", toBrowseURL(), toTagString());
+		MultiIdentityHashMap<Coord, JoinedWay> endPoints = new MultiIdentityHashMap<>();
+		ArrayList<JoinedWay> polygons = new ArrayList<>();
+		ArrayList<JoinedWay> unclosedWays = new ArrayList<>(); // these are probably errors
+		int waysInCoordMap = 0;
+
+		// go through relation elements. For "ways" add both ends to coord map. For "nodes" note label
+		for (Map.Entry<String, Element> entry : getElements()) {
+			String role = entry.getKey();
+			Element el = entry.getValue();
+			if (el instanceof Way) {
+				Way wayEl = (Way) el;
+				if (wayEl.getPoints().size() <= 1) {
+					log.warn("%%%RWB Way", wayEl, "has", wayEl.getPoints().size(),
+							 "points and cannot be used for the multipolygon", toBrowseURL());
+				} else {
+					JoinedWay jw = new JoinedWay(wayEl);
+					if ("outer".equals(role))
+						jw.outerCount = 1;
+					else if ("inner".equals(role))
+						jw.innerCount = 1;
+					else if (role != null && !"".equals(role)) // blank/missing is normally assumed to be outer
+						log.warn("%%%RWB Way role not inner/outer", role, el.toBrowseURL(),
+								 "in multipolygon", toBrowseURL(), toTagString());
+					if (wayEl.isClosed()) { // single closed way, bypass endPoints map
+						polygons.add(jw);
+					} else {
+						++waysInCoordMap;
+						endPoints.add(jw.firstCoord, jw);
+						endPoints.add(jw.lastCoord, jw);
+					}
+				}
+			} else if (el instanceof Node) {
+				if ("admin_centre".equals(role) || "label".equals(role))
+					cOfG = ((Node) el).getLocation();
+				else
+					log.warn("%%%RWB Node with unknown role", role, el.toBrowseURL(),
+							 "in multipolygon", toBrowseURL(), toTagString());
+			} else {
+				log.warn("%%%RWB Non Way/Node member with role", role, el.toBrowseURL(),
+						 "in multipolygon", toBrowseURL(), toTagString());
+			}
+		}
+
+		// start joining ways that share end-points
+		int iterCount = 0;
+		while (waysInCoordMap > 0) {
+			++iterCount;
+			int initialCount = waysInCoordMap;
+			log.warn("%%%RWB iter", iterCount, "waysInMap", waysInCoordMap, "mapSize", endPoints.size(), "#Poly", polygons.size(), "#Lines", unclosedWays.size());
+			Iterator<Entry<Coord, List<JoinedWay>>> iter = endPoints.entrySet().iterator();
+			while (iter.hasNext()) {
+				Entry<Coord, List<JoinedWay>> entry = iter.next();
+				Coord theCoord = entry.getKey();
+				List<JoinedWay> waysAtCoord = entry.getValue();
+				int numHere = waysAtCoord.size();
+				if (numHere == 0) { // previous operation emptied list
+					iter.remove();
+				} else if (numHere == 2) { // have to join them regardless
+					JoinedWay jw = waysAtCoord.get(0);
+					JoinedWay jwNext = waysAtCoord.get(1);
+					// going to append jwNext to jw, so ensure both in correct direction
+					if (jw.lastCoord != theCoord)
+						jw.flip();
+					if (jwNext.firstCoord != theCoord)
+						jwNext.flip();
+					jw.addWay(jwNext);
+					--waysInCoordMap;
+					List<JoinedWay> otherEnd = endPoints.get(jwNext.lastCoord);
+					if (jw.firstCoord == jw.lastCoord) { // now it is closed
+						polygons.add(jw);
+						//endPoints.removeMapping(jw.firstCoord, jw);
+						//endPoints.removeMapping(jw.firstCoord, jwNext);
+						// best not to do above because it might do endPoints:remove() in iterator
+						otherEnd.remove(jw);
+						otherEnd.remove(jwNext);
+						--waysInCoordMap;
+					} else { // replace ref to jwNext (now gone) with jw
+						otherEnd.remove(jwNext);
+						otherEnd.add(jw);
+					}
+					iter.remove();
+				} else if (iterCount == 1) { // ignore all but the simplest processing in first iteration
+					continue; // then we get unclosedWays fully joined, etc
+				} else if (numHere == 1) { // an unattached end
+					JoinedWay jw = waysAtCoord.get(0);
+					List<JoinedWay> otherEnd = endPoints.get(jw.firstCoord == theCoord ? jw.lastCoord
+															                           : jw.firstCoord);
+					if (otherEnd.size() % 2 == 1) { // either unconnected or a spur - remove
+						unclosedWays.add(jw);
+						otherEnd.remove(jw); // again, best to avoid removeMapping()
+						--waysInCoordMap;
+						iter.remove();
+					}
+				}
+ 				// >=4 ways at a node is more complicated. Often double-touching polygons.
+				// %%% can add some code to resolve if have just 2 of the same role
+				// but these are invalid and can be ignored here and flagged as errors later
+			}
+			if (iterCount > 1 && initialCount == waysInCoordMap)
+				break; // stop if nothing resolved
+		}
+		log.warn("%%%RWB stop", "waysInMap", waysInCoordMap, "mapSize", endPoints.size(), "#Poly", polygons.size(), "#Lines", unclosedWays.size());
+		/*%%%
+Above logic resolves almost all relations in britain-and-ireland-latest.osm.pbf into polygons or lines.
+
+more processing needed?:
+  distinguish between line that touches polygon and one on own
+  complex points with even # of ways. normally double touching.
+  if above is inner and outer, should be able to resolve in the main logic
+  single lines - should it attempt to join outside the box
+		*/
+		if (waysInCoordMap != 0) { // mostly diagnostics, but moves remaining ways to the unclosed list
+			log.error("%%%RWB err", toBrowseURL(), toTagString(), "waysInMap", waysInCoordMap, "mapSize", endPoints.size(), "#Poly", polygons.size(), "#Lines", unclosedWays.size());
+			for (Entry<Coord, List<JoinedWay>> entry : endPoints.entrySet()) {
+				Coord theCoord = entry.getKey();
+				List<JoinedWay> waysAtCoord = entry.getValue();
+				log.warn("%%%RWB map", theCoord, "#ends", waysAtCoord.size());
+				for (JoinedWay jw : waysAtCoord) {
+					log.warn("%%%RWB way", jw, "first", jw.firstCoord, "last", jw.lastCoord, jw.outerCount, jw.innerCount);
+					unclosedWays.add(jw);
+					List<JoinedWay> otherEnd = endPoints.get(jw.firstCoord == theCoord ? jw.lastCoord
+															                           : jw.firstCoord);
+					otherEnd.remove(jw);
+				}
+			}
+		}
+		/*
+validation:
+  not mixed inner / outer
+  don't have only inner
+  the matrix of contained for polygon by polygon
+  etc
+		*/
+	} // makePolygons
+
+
 	/**
 	 * This is a helper class that gives access to the original
 	 * segments of a joined way.
@@ -1966,6 +2123,9 @@
 		private int minLon;
 		private int maxLon;
 		private Rectangle bounds;
+		//%%%RWB haven't bothered with actual ways (reversing points when ness), just keep list in consistent order. add attributes:
+		Coord firstCoord, lastCoord;
+		int outerCount, innerCount;
 
 		public JoinedWay(Way originalWay) {
 			super(originalWay.getOriginalId(), originalWay.getPoints());
@@ -1979,6 +2139,9 @@
 			minLon = maxLon = c0.getLongitude();
 
 			updateBounds(originalWay.getPoints());
+			//%%%RWB
+			firstCoord = c0;
+			lastCoord = originalWay.getLastPoint();
 		}
 
 		public void addPoint(int index, Coord point) {
@@ -2065,6 +2228,10 @@
 					addWay(w);
 				}
 				updateBounds((JoinedWay) way);
+				//%%%RWB
+				this.lastCoord = ((JoinedWay) way).lastCoord;
+				this.outerCount += ((JoinedWay) way).outerCount;
+				this.innerCount += ((JoinedWay) way).innerCount;
 			} else {
 				if (log.isDebugEnabled()) {
 					log.debug("Joined", this.getId(), "with", way.getId());
@@ -2073,6 +2240,14 @@
 			}
 		}
 
+		//%%%RWB
+		public void flip() {
+			Coord tempCoord = firstCoord;
+			firstCoord = lastCoord;
+			lastCoord = tempCoord;
+			Collections.reverse(originalWays);
+		}
+
 		public void closeWayArtificially() {
 			addPoint(getPoints().get(0));
 			closedArtificially = true;
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to