6

I searched about a day now, but didnt find any example for my problem in Javacode.

I have a worldmap with a size of 2000*1400 Pixels with a 'Mollweide' projection. How can I find out what is the longitude and laltitude of the point (500,300) in my map ? I would like to code this in Java.

I tried to do this with the 'Java Map Projection Library' :

Point2D.Double pointonmap = null;
Point2D.Double latlon = null;
MolleweideProjection molproj=new MolleweideProjection();

pointonmap = new Point2D.Double (1400,1000);  

latlon=molproj.inverseTransform(pointonmap,new Point2D.Double ());

System.out.println("latlon: " + latlon.getX() + ", " + latlon.getY());

Could anyone help me with that ? Codeexample or hint.

thanks and regards

mcfly soft
  • 11,289
  • 26
  • 98
  • 202

2 Answers2

4

Wikipedia has most of the information you need:

enter image description here

These formulas assume a few things, as usual. They speak in projected dimension, which is smaller than the component. [0,0] is at the centre, not top left. Y coordinate goes up rather than goes down. And the result is in radius instead of degree. Fix these and they'll work for you.

Since you didn't provide a link, I assume you are using the Java Map Projection Library on GitHub. Without documentation and with limited time, I can't understand inverseTransform well enough to fix your code; but the bundled MapComponent is simpler to code:

map.addMouseListener( new MouseAdapter() { @Override public void mouseClicked( MouseEvent e ) {

   double x = e.getX() - map.getWidth() / 2, // Mouse X with [0,0] at centre.
          y = e.getY() - map.getHeight() / 2, // Mouse Y with [0,0] at centre.
          // Max Y of projected map, in pixel with [0,0] at centre.
          maxY = map.getMapExtension().getMaxY() *  map.getScaleToShowAll(), 
          sqrt2 = Math.sqrt( 2 ), // Can be optimised away, but let's be faithful.
          R = maxY / sqrt2, // Radius of projection, in pixel.
          theta = Math.asin( y / ( R * sqrt2 ) );
   int    delta_long = -lon0Slider.getValue(); // Longtitude shift from -180 to 180.

          // Find lat long in radius and converts to degree.
   double latInRad  = Math.asin( -( 2 * theta + Math.sin( 2 * theta ) ) / Math.PI ),
          latitude  = Math.toDegrees( latInRad ),
          longInRad = Math.PI * x / ( 2 * R * sqrt2 * Math.cos( theta ) ),
          longitude = Math.toDegrees( longInRad ) + delta_long;

   System.out.println( "Lat: " + latitude + ", Long: " + longitude );
}

You can paste this code into the constructor of ch.ethz.karto.gui.ProjectionSelectionPanel. The IDE should reports that two methods of the map is private, and you need to change them to public first (or use reflection). Then launch it, select Mollweide, click on the globe and watch the console. Feel free to resize the window.

Sheepy
  • 17,324
  • 4
  • 45
  • 69
1

This answer uses information from the English Wikipedia entry on Mollweide projection. I've pretty much transcribed the formula from there verbatim.

The short answer, so you can write your own code:

Get the map's radius, r:
projectionWidth /(2 * √2)

Get theta, the point's angle along the map:
arcsine(y / (r * √2))

Note: Arcsine is the inverse of sine. Use Math.asin(a) in java

Get the latitude:
arcsine((2 * theta + sine(2 * theta)) / PI)

Get the longitude:
PI * x / (2 * R * √2 * cosine(theta)) + central meridian.

Or you can copyPasta this.
It's not very efficient; x and y are spec as doubles becaus too lazy to write typecast avoid narrowing
no-setters no-getters all-vars public
all-world-one-love Dr. Bronner's TV-dinners solve your problems for you
and stuff
enoj

public class MolleweidePoint
{
    public double x, y, latitude, longitude;

    public MolleweidePoint(double projectionWidth, double x, double y)
    {
        double rootTwo = Math.sqrt(2);
        double r = projectionWidth / 2 / rootTwo;
        double theta = Math.asin(y / r / rootTwo);

        this.x = x;
        this.y = y;
        longitude = Math.PI * x / 2 / r / rootTwo / Math.cos(theta);
        latitude = Math.asin(2 * theta + Math.sin(2 * theta) / Math.PI);
    }
}

After calling the constructor like

MolleweidePoint ted = new MolleweidePoint(projection.width, 300, 500)

you can get the latitude and longitude from ted.longitude and ted.latitude. Also, longitude may have to be adjusted based on where the central meridian is placed on your projection.

Mark Peschel
  • 115
  • 3
  • 10