3

I'm trying to convert coordinates from any given coordinate system (be they the coordinates of a graph figure or a map, meaning they can span across both negative and positive values across any of the four +- quadrants), over to screen coordinates. I also want an easy way as part of the solution to be able to zoom to a small area within the coordinate system.

I already tried an algorithm of my own, which was overly complicated and would fail on occasion (for simplicity I have now removed it from the post).

Update

Thanks to the helpful answers below, especially by Martin F, I now have a solution that works as expected with all types of coordinate systems, be they drawing, geographical, negative, flipped, etc. Specifically this has been a great addition to three Python libraries I've been working on: for autozooming to a geographical entity in Shapy, for drawing any kind of coordinates on an image in PyDraw, and for map zooming in GeoVis.

Martin's answer describes the theoretical ideal of how to do it, but here's how I did it for my case. The user specifies the topleft and bottomright xy corners in the coordinate system of their data which they want to appear in the same corners on a graphical image, thus allowing zooming and flipping sides/updown. In my case the graphics drawer has its 0,0 coordinate in the topleft corner. To prepare the equation I just needed a single scalex/y variable.

Update2:

I also added how I constrained the dimensions to keep them the same size, which can be useful in many cases.

#input
IMG = ...
XLEFT,YTOP,XRIGHT,YBOTTOM = ...
CONSTRAIN = True

#constrain dimensions to avoid distortion
if CONSTRAIN:
    xwidth = max(XLEFT,XRIGHT) - min(XLEFT,XRIGHT)
    yheight = max(YTOP,YBOTTOM) - min(YTOP,YBOTTOM)
    if xwidth > yheight:
        YBOTTOM = YTOP+xwidth
    elif yheight > xwidth:
        XRIGHT = XLEFT+yheight

#prepare scale values
imgwidth = float(IMG.width)
imgheight = float(IMG.height)
scalex = imgwidth / (XRIGHT - XLEFT)
scaley = 0 - imgheight / (YTOP - YBOTTOM)

With that, the coordinate conversion of inx and iny is calculated as:

newx = scalex * (inx - XLEFT)
newy = imgheight + scaley * (iny - YBOTTOM)
  • 1
    I have a very untrained eye. however I think I see the you are using the bottom left of all cs systems as 0,0. this would only be accurate on a subset of systems, the rest would be based on the origin lon and origin lat, The other factor that would make for inaccuracy would be the fact that some cs have false north/easting. There are libraries to do these calculations on the correct parameters though. – Brad Nesom Jun 3 '14 at 14:20
  • @BradNesom: This is not a "projection" from lon-lat to XY; it is merely 4-parameter transformation (scale and shift) from "already projected" XY to screen xy. – Martin F Jun 3 '14 at 16:24
  • Mind editing some of the code for readability? Add spaces around operators + - * / and spaces after commas. And encode any variables mentioned in the text within ` (graves?) – Martin F Jun 3 '14 at 16:36
  • lat lon is not what I was referring to. recent edits seem to have changed the meaning of the op question. In the code this must be a very small snippet indeed if you are converting all values to positive and still keeping track of which direction the axis of those values are. It seems there is more to this question not being relayed. What happens if the projected cs is albers? or do you not allow any projections other than your choice? – Brad Nesom Jun 3 '14 at 17:02
  • @BradNesom: I edited the wording slightly so as to match what i see the code trying to do. I don't believe the Q has anything to do with map projections -- just simple conversion from one plane system to another. The OP can confirm though. (I could be wrong.) – Martin F Jun 3 '14 at 17:20
4

To me, your basic approach appears sound yet overly complicated. I'd start with this:

scale_x = (img_right - img_left) / (x_right - x_left)
scale_y = (img_top - img_bottom) / (y_top - y_bottom)
new_x = img_left   + scale_x * (x_in - x_left)
new_y = img_bottom + scale_y * (y_in - y_bottom)

You may need some minor variation due to screen Y coords being in reverse direction, and you may wish to choose only one scale, to reduce distortion.

  • I can't believe how easy your solution turned out to be, especially compared to my original approach (see the new short code in my update). This is something I've struggled with on several occasions. Although I usually could reason my way to applying the relative position of a coordinate in its cs to the screen width or height, it just always seemed to mess up when negative values or coordinate spans got involved. I guess it just boils down to my lack of a basic knowledge in this topic. Anyway, your code worked like a charm, saved me alot of headache, much appreciated! – Karim Bahgat Jun 4 '14 at 8:55
  • the reverse y situation (where geographic and screen coordinates run in opposite directions) seems to be handled simply by the user inputting the YTOP value as being higher than the YBOTTOM value (the reverse of screen coordinates). That way it's flexible and can handle any type of flipped/reverse coordinate system. Works for me at least. I also started thinking about the distortion issue that you mentioned and made a way to constrain both scales so they equal eachother if desired (see update2). – Karim Bahgat Jun 9 '14 at 13:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.