FloatCanvas - wrapping world projection

by @jehiah on 2006-07-10 17:03UTC
Filed under: All , Articles , Python , Programming , wxPython

… or how to draw a line that crosses the international date line in wxPython

I asked Chris Barker who wrote the FloatCanvas implementation for wxPython about some methods for solving this problem. He gave me a few ideas which got me thinking.

What was happening was I needed to draw a line from california to japan on a map which crossed the intrnational date line. Because the world was plotted from (-180,90) to (180,-90) it just crossed the whole globe. Yup the line went all the way across the world the long way crossing the atlantic instead of just going over the pacific. The problem is that the pacific was split in half and wxPython didn’t know how to draw a straight line across it.

Chris’s idea of having different maps got me thinking. Since FloatCanvas doesn’t really care about the size of the map, and it really doesn’t know anything about latitude and longitude points I decided to extend the map I was plotting on by an extra 360 degrees longitude. When initializing my map i plot my world shape files, then I plot them again while shifting the longitude by -360. This makes my map go from (-540,90) to (180,90). It’s really easier understand with this image which shows two worlds drawn side by side on the same canvas.

Now In my application if I decide that the points i’m plotting would cross the date line, I can pick a different part of the map to draw on. I have the normal -180 to 180 range (in orange) to plot across the atlantic. Now i also have a -360 to 0 range (green) where I can plot across the international date line.

Now I need a method of deciding to plot on the orange world. This is actually simple. I just scan all my longitude points to see if I have points that have longitude < -90 (the red region) and that i also have points with longitude >90 (the blue region).

[python]

def scanPointsForMangle(self,points):
    """ check if there are any lon <-90 and >90. If there are, mangle them!"""
    farWest = False
    farEast = False
    for point in points:
        if point[0] < -90:
            farWest = True
            if farEast:
                return True
        if point[0] > 90:
            farEast = True
            if farWest:
                return True
    return False
[/python]

When this happens I shift the longitude of points where longitude > 0 by -360 so that they move from the yellow to the teal region.

[python]
if scanPointsForMangle([(120,-20),(145,10),(-130,15)])):
    self.mangleEasternHemisphere=-360
    self.mangleWesternHemisphere=0
[/python]

Now I just add a wrapper function around all my calls to draw on the Canvas.

[python]
def mangleSegment(self,segment):
    if self.mangleEasternHemisphere == 0 and self.mangleWesternHemisphere ==0:
        return segment
    r =[]
    for point in segment:
        r.append(self.manglePoint(point))
    return r

def manglePoint(self,point):
    """ this takes a point and will shift the longitude by a defined amount (normally -360)"""
    return point[0]>0 and (point[0]+self.mangleEasternHemisphere,point[1]) or (point[0]+self.mangleWesternHemisphere,point[1])

self.Canvas.AddText(lablel,self.manglePoint((lon,lat)))
self.Canvas.AddPolygon(self.manglePoint([(lon,lat),(lon2,lat2)]))
[/python]

Final note: my function for scanPointsForMangle could be improved, i’ll admit that. But it works, and sometimes thats just as important.

Subscribe via RSS ı Email
Jehiah Czebotar