Subject: [mkgmap-dev] [PATCH v1] Better rounding in mkgmap
From: Elrond <[email-masked]>
To: [email-masked]
Date: Tue, 11 Aug 2009 15:50:30 +0200
List-Id: Development list for mkgmap <mkgmap-dev.lists.mkgmap.org.uk>

Hi everyone,

As rounding seems a current topic, I'm throwing in a patch
that is sitting in my tree for a while now:

We used to round coords to the shifted values in a subdiv
by just using the ">>" shift operator. This works. But it's
not the mathematical way of rounding, and the later is
better IMHO.

Let me explain this with an example:

Let's assume the center-Lat of a subdiv is exactly at 0.
Let's assume the shift-value is 4. So we divide by 16, or
truncate to it, however you like to think about it.
So if we have a point at lat=31, it will have the shifted
value of (31-0) >> 4 = _1_. This will be displayed at
0 + (_1_ << 4) = 16. While _2_ would give us 0 + (_2_ << 4)
= 32. 32 is much closer to the real value.

Another more intuitive way of looking at the whole thing is
with classic rounding: Just assume, that the current shift
value is choosen so that we round exactly to "degrees"
(some special sort of degrees). So, 3.9 will currently be
rounded to just 3, not 4.

The solution is add half the rounding distance and
truncate: truncate(3.9 + 0.5) = 4.

PENDING ISSUES:

I am not sure, that I have catched all cases in mkgmap. Any
feedback on this is highly welcome.

Of course, general testing and feedback is also welcome!

    Elrond

p.s.: This is also related to the overview map issue I was
      talking about a while back and wanting to post
      patches for.  This one can be counted as the next
      one.
Index: uk/me/parabola/imgfmt/app/trergn/MapObject.java
===================================================================
--- uk/me/parabola/imgfmt/app/trergn/MapObject.java	(revision 1129)
+++ uk/me/parabola/imgfmt/app/trergn/MapObject.java	(working copy)
@@ -91,10 +91,8 @@
 	 */
 	public void setLatitude(int lat) {
 		Subdivision div = getSubdiv();
-		int shift = div.getShift();
 
-		int centerLat = div.getLatitude() >> shift;
-		int diff = ((lat>>shift) - centerLat);
+		int diff = div.roundLatToLocalShifted(lat);
 
 		setDeltaLat(diff);
 	}
@@ -107,15 +105,13 @@
 	 */
 	public void setLongitude(int lon) {
 		Subdivision div = getSubdiv();
-		int shift = div.getShift();
 
-		int centerLon = div.getLongitude() >> shift;
-		int diff = ((lon>> shift) - centerLon);
+		int diff = div.roundLonToLocalShifted(lon);
 
 		setDeltaLong(diff);
 	}
 	
-    // directly setting shouldn't be done
+	// directly setting shouldn't be done
 	private void setDeltaLat(int deltaLat) {
 		this.deltaLat = deltaLat;
 	}
Index: uk/me/parabola/imgfmt/app/trergn/LinePreparer.java
===================================================================
--- uk/me/parabola/imgfmt/app/trergn/LinePreparer.java	(revision 1129)
+++ uk/me/parabola/imgfmt/app/trergn/LinePreparer.java	(working copy)
@@ -169,9 +169,10 @@
 	 * the lat and long values.
 	 */
 	private void calcDeltas() {
+		Subdivision subdiv = polyline.getSubdiv();
 		if(log.isDebugEnabled())
 			log.debug("label offset", polyline.getLabel().getOffset());
-		int shift = polyline.getSubdiv().getShift();
+		int shift = subdiv.getShift();
 		List<Coord> points = polyline.getPoints();
 
 		// Space to hold the deltas
@@ -196,8 +197,8 @@
 		for (int i = 0; i < points.size(); i++) {
 			Coord co = points.get(i);
 
-			int lat = co.getLatitude() >> shift;
-			int lon = co.getLongitude() >> shift;
+			int lat = subdiv.roundLatToLocalShifted(co.getLatitude());
+			int lon = subdiv.roundLonToLocalShifted(co.getLongitude());
 			if (log.isDebugEnabled())
 				log.debug("shifted pos", lat, lon);
 			if (first) {
Index: uk/me/parabola/imgfmt/app/trergn/Subdivision.java
===================================================================
--- uk/me/parabola/imgfmt/app/trergn/Subdivision.java	(revision 1129)
+++ uk/me/parabola/imgfmt/app/trergn/Subdivision.java	(working copy)
@@ -414,4 +414,24 @@
 
 		rgnFile.setPolygonPtr();
 	}
+
+	/**
+	 * Convert an absolute Lat to a local, shifted value
+	 */
+	public int roundLatToLocalShifted(int absval) {
+		int shift = getShift();
+		int val = absval - getLatitude();
+		val = val + ((1 << shift) / 2);
+		return (val >> shift);
+	}
+
+	/**
+	 * Convert an absolute Lon to a local, shifted value
+	 */
+	public int roundLonToLocalShifted(int absval) {
+		int shift = getShift();
+		int val = absval - getLongitude();
+		val = val + ((1 << shift) / 2);
+		return (val >> shift);
+	}
 }
_______________________________________________
mkgmap-dev mailing list
[email-masked]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev