Author Topic: [Solved] Converting cartesian coordinates to polar coordinates  (Read 19307 times)

Offline SupSuper

  • Lazy Developer
  • Administrator
  • Commander
  • *****
  • Posts: 2162
    • View Profile
The X-Com game world consists of a flat map with a series of polygons representing the land masses, like so:


(image from Ufopaedia.org)

Every point on the map has a latitude and a longitude, just like the real thing. To turn the map into a pseudo-globe, every point is converted from lat/lon to X/Y, like so:

x = radius * sin(lon) * cos(lat)
y = radius * (sin(lat) * cos(rotLat) + cos(lat) * sin(rotLat) * cos(lon))

(radius = globe radius, lon = longitude, lat = latitude, rotLat = rotation on the latitude, sin = sine, cos = cosine)

Now I need to invert these formulas to reverse the process (turn points on the globe into points on the flat map), so they become something like:

lat = ...
lon = ...

So... anyone have any ideas how to solve this?
« Last Edit: July 03, 2010, 03:54:36 am by SupSuper »

Offline pmprog

  • Commander
  • *****
  • Posts: 647
  • Contributor
    • View Profile
    • Polymath Programming
Re: [TASK] Converting cartesian coordinates to polar coordinates
« Reply #1 on: June 18, 2010, 11:02:09 am »
Untested, but I think you need something like

Quote
z = sqrt( radius2 - x2 - y2 )
lon = arccos( z / radius )
lat = atan2( y, x )

Used quotes, cos I couldn't superscript in code  ;D

Reference: https://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates

Edit: Hmmm, just thinking, this might actually be expecting an (X, Y, Z) in 3D cartesian space, not on the 2D map...

Edit 2: But then again, your original equations were from the same page, and you don't calculate z (hence why I added the reverse calculation)
« Last Edit: June 18, 2010, 03:52:27 pm by pmprog »

Offline mewse

  • Sergeant
  • **
  • Posts: 10
    • View Profile
Re: [TASK] Converting cartesian coordinates to polar coordinates
« Reply #2 on: June 18, 2010, 06:31:48 pm »
So... anyone have any ideas how to solve this?

I've thought about this before and I'm not sure if my idea is going to make any sense after typing it out, but here goes:

The geoscape screen is always going to be 320x200, and you already (obviously) have done the math to project the globe into screen coordinates. What I am thinking is do a projection with (0,0,0) rotation and then save a "mapping" of which lat/long gets drawn at each location in the 320x200 screen space. Then when the mouse interacts with it, you have the latitude and longitude as if the globe were at (0,0,0) and you can "rotate" the mouse click based on how the globe is being displayed.

Actually if you update the mapping every frame that you display then you don't even have to "rotate" the lat/long you get from the mouse interaction

edit: ummm I just read your OP again and are you converting to a sphere before you do any drawing? because maybe you can build the map i've described by doing the polar coordinate -> sphere -> screen pixel calculation for each pixel with a test program and then just make the mapping a struct

edit: haha I just read someone elses solution to your polygon problem and that solution is similar.. store meta-info for screen coords
« Last Edit: June 18, 2010, 06:34:28 pm by mewse »

Offline serge

  • Squaddie
  • *
  • Posts: 7
    • View Profile
Re: [TASK] Converting cartesian coordinates to polar coordinates
« Reply #3 on: June 20, 2010, 01:25:06 pm »
x = radius * sin(lon) * cos(lat)
y = radius * (sin(lat) * cos(rotLat) + cos(lat) * sin(rotLat) * cos(lon))

(radius = globe radius, lon = longitude, lat = latitude, rotLat = rotation on the latitude, sin = sine, cos = cosine)

Now I need to invert these formulas to reverse the process (turn points on the globe into points on the flat map), so they become something like:

lat = ...
lon = ...

So... anyone have any ideas how to solve this?

Obviously, solving these equations should give zero, one or two distinct lat,lon pairs as a result for each x,y on input. Don't know if it's easy to solve these equations analytically (my math skills got a bit rusty nowadays). But being lazy, one can easily solve the problem numerically, by using Newton's method for example ;)

Offline SupSuper

  • Lazy Developer
  • Administrator
  • Commander
  • *****
  • Posts: 2162
    • View Profile
Re: [TASK] Converting cartesian coordinates to polar coordinates
« Reply #4 on: June 30, 2010, 05:30:13 pm »
I can't say math is exactly my forte either, so so far all the solutions are scaring the crap out of me. :P But I'll give in and try them if nothing better comes along.

For the curious, this is the current formula:

lat = asin((y - cenY) / r);
lon = asin((x - cenX) / (r * cos(lat))) - rotLon;

Which works fine... as long as you don't rotate the globe vertically (no rotLat in there), that's the real problem. ;)

Typically spherical coordinates (r, lat, lon) convert into cartesian (x, y, z) easily (Wikipedia has the formulas as posted earlier), but in this case the sphere can be rotated which changes the axis, and they need to be flattened for the screen into (x, y). Also the radius is constant since we always want the sphere's surface. But if it's easier for you, you can think of the process as:

(r, lat, lon) -> (x, y, z) -> (x, y)
(r, lat, lon) <- (x, y, z) <- (x, y)

Early on I did try drawing the globe with (x, y, z) through 3D rendering but that just caused a whole lot more problems, so... here we are. :P

Offline pmprog

  • Commander
  • *****
  • Posts: 647
  • Contributor
    • View Profile
    • Polymath Programming
Re: [TASK] Converting cartesian coordinates to polar coordinates
« Reply #5 on: June 30, 2010, 09:01:00 pm »
SupSuper: Longitude is thrown out wildly with that - _rotLon

If anybody else is looking at this, my code segment so far is

Code: [Select]
void Globe::cartToPolar(Sint16 x, Sint16 y, double *lon, double *lat)
{
  double dr = (_radius * _zoom);
  double dx = (double)(x - _cenX);
  double dy = (double)(y - _cenY);
  double dz = sqrt( (dr * dr) - (dx * dx) - (dy * dy) );

  *lon = asin( dx / (dr * dz) );
  *lat = asin( dy / dr ) - _rotLat;

  https:// Check for errors
  if (!(*lat == *lat && *lon == *lon))
  {
    *lat = COORD_OUT_OF_BOUNDS;
    *lon = COORD_OUT_OF_BOUNDS;
  }
  else
  {
    *lon = longitudeLoop(*lon - _rotLon);
  }

  https:// Debug
  https:// cout << x << ", " << y << ": " << _rotLon << ", " << _rotLat << endl;
}

With this, you can rotate it any way you wish and the selection will remain central (X axis) to the planet.
« Last Edit: June 30, 2010, 09:09:17 pm by pmprog »

Offline SupSuper

  • Lazy Developer
  • Administrator
  • Commander
  • *****
  • Posts: 2162
    • View Profile
Re: [TASK] Converting cartesian coordinates to polar coordinates
« Reply #6 on: July 02, 2010, 02:43:37 am »
I found the solution! https://en.wikipedia.org/wiki/Orthographic_projection_(cartography)

The functions are frightening but, they work ;D, and now that I got these issues out of the way I can finally work on giving the globe more functionality. Case closed!

Offline pmprog

  • Commander
  • *****
  • Posts: 647
  • Contributor
    • View Profile
    • Polymath Programming
Re: [TASK] Converting cartesian coordinates to polar coordinates
« Reply #7 on: July 02, 2010, 08:14:23 am »
Excellent news!