MetaProgramming at VanPyZ

Just a reminder for Pythonistas in the Vancouver area: The Vancouver Python and Zope user group (VanPyZ) is tomorrow (Tuesday, April 1). Paul Prescod will be talking about metaprogramming in Python. Details and directions are on the VanPyZ site. And, as usual, we’ll be heading out to the pub afterwards for more discussion.

Hope to see you there!

Saving PNG from PyGame

The latest version, 1.8, of PyGame can save PNGs directly from a Surface: pygame.Image.save(mySurface, 'myimagefile.png'). But what if you want to support an older version of PyGame, such as the one available for the N800 or the XO? Well, assuming you have access to the Python Image Library, you can use that:

import Image # from PIL
import pygame

def pygame_to_pil_img(pg_surface):
    imgstr = pygame.image.tostring(pg_surface, 'RGB')
    return Image.fromstring('RGB', pg_surface.get_size(), imgstr)

def pil_to_pygame_img(pil_img):
    imgstr = pil_img.tostring()
    return pygame.image.fromstring(imgstr, pil_img.size, 'RGB')

Once you have a PyGame Image, you can save it to PNG easily: myImage.save('myfilename.png')

I’ve found myself looking for this code snippet more than once, now I can Google for it more readily, and maybe someone else will find it helpful too.

Drawing Hexmaps

The other day, Thomas Guest talked about drawing chessboards, and ended with a challenge. I wanted to answer a different challenge, however. What if, instead of drawing on a rectangular grid, we wanted to draw on a hexagonal grid? The following is my slapdash answer. For real-world use I’d make nice classes and pass more parameters to the methods, but to demonstrate the math I’m just going to use global constants and functions.

Like Thomas’ article, I will show solutions using several different tools, in this case Apple’s Core Graphics, PyGame, Python Imaging Library (PIL), and SVG. All of these solutions will use the same constants and math:

# Constants used by each solution

from math import sin, cos, pi, sqrt
THETA = pi / 3.0 # Angle from one point to the next
HEXES_HIGH = 8 # How many rows of hexes
HEXES_WIDE = 5 # How many hexes in a row
RADIUS = 30 # Size of a hex
HALF_RADIUS = RADIUS / 2.0
HALF_HEX_HEIGHT = sqrt(RADIUS ** 2 - HALF_RADIUS ** 2)
IMAGE_WIDTH = int(RADIUS * (HEXES_WIDE * 3 + .5))
IMAGE_HEIGHT = int(HALF_HEX_HEIGHT * (HEXES_HIGH + 1))

# Functions (generators) used by each solution

def hex_points(x,y):
    '''Given x and y of the origin, return the six points around the origin of RADIUS distance'''
    for i in range(6):
        yield cos(THETA * i) * RADIUS + x, sin(THETA * i) * RADIUS + y

def hex_centres():
    for x in range(HEXES_WIDE):
        for y in range(HEXES_HIGH):
            yield (x * 3 + 1) * RADIUS + RADIUS * 1.5 * (y % 2), (y + 1) * HALF_HEX_HEIGHT

Now, given the above, what does the code look like to draw the hexes? Because each library handles colours slightly differently, we will need a generator for colours (and we will need more than just black and white as the chessboard used, because each hex borders on six others). I haven’t given a lot of thought to optimal colouring schemes: each colour generator simply produces red, yellow, blue, and green in a cycle. Here is the image produced by the Core Graphics solution, followed by the code:

Hex Image 1

def quartz_colours():
    while True:
        yield 1,0,0,1 # red
        yield 1,1,0,1 # yellow
        yield 0,0,1,1 # blue
        yield 0,1,0,1 # green

def quartz_hex():
    '''Requires a Mac with OS 10.4 or better and the Developer Tools installed'''
    import CoreGraphics as cg
    colours = quartz_colours()
    cs = cg.CGColorSpaceCreateDeviceRGB()
    c = cg.CGBitmapContextCreateWithColor(IMAGE_WIDTH, IMAGE_HEIGHT, cs, (0,0,0,.2))
    c.saveGState()
    c.setRGBStrokeColor(0,0,0,0)
    c.setLineWidth(0)
    for x,y in hex_centres():
        c.beginPath()
        c.setRGBFillColor(*colours.next())
        points = list(hex_points(x,y))
        c.moveToPoint(*points[-1])
        [c.addLineToPoint(*pt) for pt in points]
        c.drawPath(cg.kCGPathFill)
    c.restoreGState()
    c.writeToFile("quartz_hexes.png", cg.kCGImageFormatPNG)

Now for some cross-platform examples. Here is the image generated by PyGame, followed by that code:

Hex Image 2

def pygame_colours():
    while True:
        yield 255, 0, 0 # red
        yield 255, 255, 0 # yellow
        yield 0, 0, 255 # blue
        yield 0, 255, 0 # green

def pygame_hex():
    '''Requires PyGame 1.8 or better to save as PNG'''
    import pygame
    pygame.init()
    screen = pygame.display.set_mode((IMAGE_WIDTH, IMAGE_HEIGHT))
    colours = pygame_colours()
    for x,y in hex_centres():
        pygame.draw.polygon(screen, colours.next(), list(hex_points(x,y)))
    pygame.image.save(screen, 'pygame_hexes.png')

When you run the PyGame script, it will actually pop up a window very briefly, draw into the window, save the result, and close the window. I also didn’t get the PyGame script to add transparency for the background, although I think it could be added fairly easily. Now, for the web, here is a solution in SVG, with the image captured by screenshot in Safari, followed by the Python code, and the resulting SVG code:

Hex Image 3

def svg_colours():
    while True:
        yield 'rgb(255, 0, 0)'
        yield 'rgb(255, 255, 0)'
        yield 'rgb(0, 0, 255)'
        yield 'rgb(0, 255, 0)'

def svg_hex():
    out = open('svg_hexes.svg', 'w')
    print >> out, '''<?xml version="1.0" standalone="no"?>
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    <svg width="%spx" height="%spx" version="1.1" xmlns="http://www.w3.org/2000/svg">''' % (IMAGE_WIDTH, IMAGE_HEIGHT)
    colours = svg_colours()
    for pt in hex_centres():
        print >> out, '<polygon fill="%s" stroke-width="0" points="%s" />' % (colours.next(),  ' '.join(["%s,%s" % (x,y) for (x,y) in hex_points(*pt)]))
    print >> out, '</svg>'
    out.close()

And here is the SVG created by the above script: SVG Hexes

Finally, one library which overlaps with the ones used by the Chessboard example: Python Imaging Library.

Hex Image 4

pil_colours = pygame_colours  # same format works, so we'll re-use it

def pil_hex():
    import Image, ImageDraw
    image = Image.new("RGBA", (IMAGE_WIDTH,IMAGE_HEIGHT), (0,0,0,0))
    colours = pil_colours()
    draw = ImageDraw.Draw(image)
    for x,y in hex_centres():
        draw.polygon(list(hex_points(x,y)), fill=colours.next())
    image.save('pil_hexes.png', 'PNG')

That’s it for my examples. Thomas ended with a challenge for displaying chess, and for describing the position. To describe the position, I would use a standard chess notation, such as described here. For my challenge, what other formats would be useful to create hex maps in? POVRay? Flash? Any other examples out there?

The 419 Economy

Hello, my name is Sergio Arragones and I am writing to you for assistance in a matter that will be of great economic benefit to us both.

My late father was VICE PRESIDENT of the large American investment bankerage of Bear Stearns and he managed to put aside over two billion US dollars of bailout money from the puppet government of Mr. George Bush.

Unfortunately, he was killed in a incident of ROAD RAGE when his bullet-proof Mercedes convertible was driven into the bomb barricade of the New York UN Building by the SUV of an off-duty Police Officer.

While my family is still grieving over his tragic death, and attempting to get the suspicious circumstances investigated, I must act quickly to move these funds to your Nation for safekeeping. As a Citizen of the Monarchy of Canada, you may receive these funds for me until I may cross from New York State to the Province of Quebec, at which time you will transfer the funds over to me, keeping 10% (TEN PERCENT) for yourself, along with my Gratitude.

In order for me to transfer the Fund to you, you will need to create a PayPal account for this purpose. Do not use an existing PayPal account, as it may already have been compromised by nefarious hackers and BotNets. Also, you will need to download the Python libraries which allow you to code to PayPal directly. In addition, you will need libraries for Google Checkout the Atom Publishing Protocol.

On a server under your control (the server must be physically located in the Sovereignty of Canada. THIS IS IMPORTANT) you must set up a WSGI server. You may use Django or TurboGears for this, or use the reference WSGI implementation. I recommend you use PYTHON 2.5 or greater as many of the tools you need will be part of the STANDARD LIBRARY.

Once you have the Foundations of a Web2.0 server administered, contact me at the return address of this message and I will give you instructions on how to proceed for the transfer of funds.

My family thanks you.

Sincerly,

Dr. Rev. Sergio Arragones, Esq.
New York, NY
United States of America

Processing Critters



This browser does not have a Java Plug-in.


Get the latest Java Plug-in here.


Source code: sketch_080314a

I’ve been playing around some with Processing, this is the result. As I mentioned in my earlier article, Processing and NodeBox are quite similar. Processing has some more interactivity (better keyboard and mouse handling) built in, and it can do basic 3D. NodeBox has better color handling (gradients) and remarkable libraries (WordNet). But what it really comes down to is that NodeBox is Python (much easier to extend) and Processing is Java (still easier than straight Java, but a lot more code to do basic extensions). Now all we need is a quick-start programming environment like these for Flash (and before you tell me the Adobe Flash tools are for artists–I have used the Flash IDE and it is possibly the worst IDE I’ve ever experienced. Which is odd, because the Flex IDE is one of the best, better than XCode/Interface Builder in some ways).

All of which is the long way to say that I enjoyed making this little animation in Processing, but I’m ready to go back to working in Python now, thank you.

« Previous entries Next Page » Next Page »

google

google

asus