[josm-dev] Change JOSM default projection from EPSG:4326 to Mercartor?

Gabriel Ebner ge at gabrielebner.at
Fri Nov 30 13:35:20 GMT 2007


On Fri, Nov 30, 2007 at 01:04:55PM +0100, Gabriel Ebner wrote:
> > (Some WMS servers can return Mercator-projected images but the WMS
> > plugin is not smart enough to detect that and request them if it is
> > required. Anyway the Landsat server cannot return Mercator; the image
> > would have to be reprojected by the WMS plugin, and that's rather more
> > difficult than just stretching it a bit...)
> 
> If you don't want any anti-aliasing, you just need to rearrange the rows a
> bit, i.e. figure out how high the image is going to be under Mercator, and
> then figure out for every row the corresponding row in the image in longlat
> projection and pick that.  Maybe I'll hack up something tonight...

I've hacked up a proof-of-concept implementation now, but I can't really test
it since NASA seems to have shut down general WMS service, and just allows
"Tiled WMS" in order to reduce server load.  Tiled WMS is apparently a subset
of WMS that just allows some standardized bboxes and sizes.

Anybody know of a WMS proxy (mapserver?) that can talk Tiled WMS?

In any case, I guess we need a way now to specify the projection of WMS
sources?  Large Yahoo tiles look so... different when you reproject them over
again.

  Gabriel.

P.S.: In order to try the patch, you'll need a JOSM checkout as of half an
hour ago.
-------------- next part --------------
Index: src/wmsplugin/WMSImage.java
===================================================================
--- src/wmsplugin/WMSImage.java	(revision 5828)
+++ src/wmsplugin/WMSImage.java	(working copy)
@@ -23,17 +23,22 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.data.projection.Epsg4326;
+import org.openstreetmap.josm.data.projection.Mercator;
 import org.openstreetmap.josm.gui.NavigatableComponent;
 import org.openstreetmap.josm.io.ProgressInputStream;
 
 public class WMSImage implements Serializable
 {
 	String constURL;
-	protected BufferedImage theImage;
 	protected double grabbedScale;
 	protected EastNorth topLeft, bottomRight;
 	double dEast, dNorth;	
 
+	private BufferedImage fetchedImage, projImage;
+	private Projection fetchedProj = new Epsg4326(), proj;
+
 	public WMSImage(String constURL)
 	{
 		this.constURL = constURL;
@@ -46,18 +51,18 @@
 		dEast = in.readDouble();
 		dNorth = in.readDouble();
 		grabbedScale = in.readDouble();
-		theImage = (BufferedImage) ImageIO.read(ImageIO.createImageInputStream(in));
+		fetchedImage = (BufferedImage) ImageIO.read(ImageIO.createImageInputStream(in));
 	}
 	
 	private void writeObject(ObjectOutputStream out) throws IOException {
-		System.out.println("writ" + theImage.getWidth(null));
+		System.out.println("writ" + fetchedImage.getWidth(null));
 		out.writeObject(constURL);
 		out.writeObject(topLeft);
 		out.writeObject(bottomRight);
 		out.writeDouble(dEast);
 		out.writeDouble(dNorth);
 		out.writeDouble(grabbedScale);
-		ImageIO.write(theImage, "png", ImageIO.createImageOutputStream(out));
+		ImageIO.write(fetchedImage, "png", ImageIO.createImageOutputStream(out));
 	}
 
 	public void grab(NavigatableComponent nc) throws IOException
@@ -130,7 +135,7 @@
 	{
 		InputStream is = new ProgressInputStream(
 			url.openConnection(), Main.pleaseWaitDlg);
-		theImage = ImageIO.read(is);
+		fetchedImage = ImageIO.read(is);
 		is.close();
 		Main.map.repaint();
 	}
@@ -153,25 +158,64 @@
 		return b;
 	}
 
+	private static BufferedImage reprojMerc(
+			BufferedImage img, double minlat, double maxlat) {
+		// Convert the coords into a sensible format.
+		minlat *= Math.PI / 180;
+		maxlat *= Math.PI / 180;
+		double dlat = maxlat - minlat;
+
+		// Convert to mercator.
+		double minmerc = Math.log(Math.tan(Math.PI/4 + minlat/2));
+		double maxmerc = Math.log(Math.tan(Math.PI/4 + maxlat/2));
+		double dmerc = maxmerc - minmerc;
+
+		// Allocate the new image.
+		int gw = img.getWidth(), gh = img.getHeight();
+		int pw = gw, ph = (int) (gh * dmerc / dlat);
+		BufferedImage pimg = new BufferedImage(pw, ph, img.getType());
+		
+		// Copy the lines.
+		for (int py = 0; py < ph; py++) {
+			double merc = maxmerc - dmerc * ((double) py) / ph;
+			double lat = 2*Math.atan(Math.exp(merc)) - Math.PI/2;
+			int gy = (int) (gh * (maxlat - lat) / dlat);
+
+			int[] rgb = img.getRGB(0, gy, gw, 1, null, 0, 4*gw);
+			pimg.setRGB(0, py, pw, 1, rgb, 0, 4*pw);
+		}
+
+		return pimg;
+	}
+
 	public void paint(Graphics g,NavigatableComponent nc) 
 	{
-		if (theImage != null)
-		{
-			double zoomInFactor = grabbedScale / nc.getScale();
+		if (fetchedImage == null) return;
 
-			// Find the image x and y of the supplied bottom left
-			// This will be the difference in EastNorth units, divided by the
-			// grabbed scale in EastNorth/pixel.
+		if (proj == null || !proj.equals(Main.proj)) {
+			if (Main.proj.equals(fetchedProj)) {
+				projImage = fetchedImage;
+			} else if (Main.proj instanceof Mercator) {
+				double lat1 = Main.proj.eastNorth2latlon(topLeft).lat();
+				double lat2 = Main.proj.eastNorth2latlon(bottomRight).lat();
+				projImage = reprojMerc(fetchedImage,
+					Math.min(lat1, lat2),
+					Math.max(lat1, lat2));
+				proj = Main.proj;
+			} else {
+				// FIXME: We'll need to add every projection that is added to
+				// JOSM here too.
+				projImage = fetchedImage;
+			}
+		}
 
-			int w = theImage.getWidth(null), h=theImage.getHeight(null);
-			EastNorth topLeftDisplaced  = 
-				new EastNorth(topLeft.east()+dEast, topLeft.north()+dNorth);
-			Point displacement = Main.map.mapView.getPoint(topLeftDisplaced);
-			g.drawImage(theImage,displacement.x,displacement.y,
-					(int)(displacement.x+w*zoomInFactor),
-					(int)(displacement.y+h*zoomInFactor),
-					0,0,w,h,null);
-		}
+		Point ulP = Main.map.mapView.getPoint(topLeft.add(dEast, dNorth));
+		Point lrP = Main.map.mapView.getPoint(bottomRight.add(dEast, dNorth));
+		int w = projImage.getWidth(null), h = projImage.getHeight(null);
+		g.drawImage(projImage,
+			ulP.x, ulP.y, lrP.x, lrP.y,
+			0, 0, w, h,
+			null);
 	}
 
 }


More information about the josm-dev mailing list