Search code examples
pythonrotationtranslationscalepython-imaging-library

Rotate, scale and translate 2D coordinates?


I'm am working on a project at the moment where I am trying to create a Hilbert curve using the Python Imaging Library. I have created a function which will generate new coordinates for the curve through each iteration and place them into various lists which then I want to be able to move, rotate and scale. I was wondering if anyone could give me some tips or a way to do this as I am completely clueless. Still working on the a lot of the code.

#! usr/bin/python
import Image, ImageDraw
import math

# Set the starting shape
img = Image.new('RGB', (1000, 1000))
draw = ImageDraw.Draw(img)

curve_X = [0, 0, 1, 1]
curve_Y = [0, 1, 1, 0]

combinedCurve = zip(curve_X, curve_Y)
draw.line((combinedCurve), fill=(220, 255, 250))
iterations = 5

# Start the loop
for i in range(0, iterations):
    # Make 4 copies of the curve

    copy1_X = list(curve_X)
    copy1_Y = list(curve_Y)

    copy2_X = list(curve_X)
    copy2_Y = list(curve_Y)

    copy3_X = list(curve_X)
    copy3_Y = list(curve_Y)

    copy4_X = list(curve_X)
    copy4_Y = list(curve_Y)

    # For copy 1, rotate it by 90 degree clockwise
    # Then move it to the bottom left
    # For copy 2, move it to the top left
    # For copy 3, move it to the top right
    # For copy 4, rotate it by 90 degrees anticlockwise
    # Then move it to the bottom right

    # Finally, combine all the copies into a big list
    combinedCurve_X = copy1_X + copy2_X + copy3_X + copy4_X
    combinedCurve_Y = copy1_Y + copy2_Y + copy3_Y + copy4_Y

# Make the initial curve equal to the combined one
curve_X = combinedCurve_X[:]
curve_Y = combinedCurve_Y[:]

# Repeat the loop

# Scale it to fit the canvas
curve_X = [x * xSize for x in curve_X]
curve_Y = [y * ySize for y in curve_Y]
# Draw it with something that connects the dots
curveCoordinates = zip(curve_X, curve_Y)
draw.line((curveCoordinates), fill=(255, 255, 255))

img2=img.rotate(180)
img2.show()

Solution

  • Here is a solution working on matrices (which makes sense for this type of calculations, and in the end, 2D coordinates are matrices with 1 column!),

    Scaling is pretty easy, just have to multiply each element of the matrix by the scale factor:

    scaled = copy.deepcopy(original)
    for i in range(len(scaled[0])):
        scaled[0][i]=scaled[0][i]*scaleFactor
        scaled[1][i]=scaled[1][i]*scaleFactor
    

    Moving is pretty easy to, all you have to do is to add the offset to each element of the matrix, here's a method using matrix multiplication:

    import numpy as np
    # Matrix multiplication
    def mult(matrix1,matrix2):
        # Matrix multiplication
        if len(matrix1[0]) != len(matrix2):
            # Check matrix dimensions
            print 'Matrices must be m*n and n*p to multiply!'
        else:
            # Multiply if correct dimensions
            new_matrix = np.zeros(len(matrix1),len(matrix2[0]))
            for i in range(len(matrix1)):
                for j in range(len(matrix2[0])):
                    for k in range(len(matrix2)):
                        new_matrix[i][j] += matrix1[i][k]*matrix2[k][j]
            return new_matrix
    

    Then create your translation matrix

    import numpy as np
    TranMatrix = np.zeros((3,3))
    TranMatrix[0][0]=1
    TranMatrix[0][2]=Tx
    TranMatrix[1][1]=1
    TranMatrix[1][2]=Ty
    TranMatrix[2][2]=1
    
    translated=mult(TranMatrix, original)
    

    And finally, rotation is a tiny bit trickier (do you know your angle of rotation?):

    import numpy as np
    RotMatrix = np.zeros((3,3))
    RotMatrix[0][0]=cos(Theta)
    RotMatrix[0][1]=-1*sin(Theta)
    RotMatrix[1][0]=sin(Theta)
    RotMatrix[1][1]=cos(Theta)
    RotMatrix[2][2]=1
    
    rotated=mult(RotMatrix, original)
    

    Some further reading on what I've done:

    So basically, it should work if you insert those operations inside your code, multiplying your vectors by the rotation / translation matrices

    EDIT

    I just found this Python library that seems to provide all type of transformations: http://toblerity.org/shapely/index.html