Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@the-lost-explorer
Created August 17, 2019 15:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save the-lost-explorer/52663794ec852c4e1cc4a84ae5f8bd69 to your computer and use it in GitHub Desktop.
Save the-lost-explorer/52663794ec852c4e1cc4a84ae5f8bd69 to your computer and use it in GitHub Desktop.
Computer Graphics: Basic 2D transformations in tkinter using matrices (Translation, Rotation and Scaling)
import tkinter as tk
from tkinter import ttk
import numpy as np
LARGE_FONT = ("Verdana", 12)
class TwoDTransformationApp(tk.Tk):
def __init__(self, height = 800, width = 800, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
frame = StartPage(container, self, height, width)
self.frames[StartPage] = frame
frame.grid(row=0, column = 0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller, height, width):
tk.Frame.__init__(self, parent)
self.height = height
self.width = width
self.clicks = []
label = tk.Label(self, text="2D Transforamtions", font=LARGE_FONT)
label.pack(pady =10,padx=10)
self.canvas = tk.Canvas(height=self.height, width=self.width, bg='white')
self.canvas.create_line(0, self.height/2, self.width, self.height/2)
self.canvas.create_line(self.width/2, 0, self.width/2, self.height)
self.make_axes(self.canvas, self.height, self.width)
self.canvas.pack(fill=tk.BOTH, expand=True)
self.left_click_bind = self.canvas.bind("<Button-1>", self.show_point)
self.right_click_bind = self.canvas.bind("<Button-3>", self.make_polygon)
def make_axes(self, canvas, height, width):
for i in range(0, width//2, 50):
#Negative X-axis
canvas.create_line(i, height//2, i, height//2+3)
canvas.create_text(i, height/2+10,fill="black",font="Times 10", text=str(-(width//2 - i)))
#Positive X-axis
canvas.create_line(i+width//2, height//2, i+width//2, height//2+3)
canvas.create_text(i+width//2, height/2+10,fill="black",font="Times 10", text=str((i)))
for i in range(50, height//2, 50):
#Positive Y-axis
canvas.create_line(width//2, i, width//2-5, i)
canvas.create_text(width//2-17, i, fill="black",font="Times 10", text=str((height//2 - i)))
#Negative Y-axis
canvas.create_line(width//2, i+height//2, width//2-5, i+height//2)
canvas.create_text(width//2-17, i+height//2, fill="black",font="Times 10", text=str(-(height//2 - i)))
def show_point(self, event):
self.clicks.append((event.x - 1, event.y - 1))
self.canvas.create_oval(event.x-2, event.y-2, event.x+2, event.y+2, fill="")
pt = (event.x-self.width//2, event.y-self.height//2)
self.canvas.create_text(event.x-4, event.y-10, fill="black", font="Times 10", text="("+str(pt[0])+", "+str(pt[1])+")")
def make_polygon(self, event):
self.canvas.unbind("<Button-1", self.left_click_bind)
self.canvas.unbind("<Button-3", self.right_click_bind)
self.poly = Polygon(self.canvas,self.clicks)
self.poly.generate_polygon()
self.transformation_input()
def transformation_input(self):
while True:
option = input('Please choose the operation you want to perform: \n 1 - Translation \n 2 - Scaling \n 3 - Rotation \n')
if (option == "1"):
self.translate()
elif(option == "2"):
self.scale()
elif (option == "3"):
self.rotate()
else:
print("Please enter correct option!")
def translate(self):
lst = list(map(float,input("Enter the x and y translation distances you desire: ").split()))
self.poly.translate_poly(lst[0],lst[1])
def scale(self):
lst = list(map(float,input("Enter the x and y scaling factors you desire: ").split()))
self.poly.scale_poly(lst[0],lst[1], self.height/2, self.width/2)
def rotate(self):
angle = float(input("Please provide the angle of rotation: "))
angle = angle*np.pi/180
self.poly.rotate_poly(angle, self.height/2, self.width/2)
class Polygon(tk.Canvas):
def __init__(self, canvas, vertices):
self.vertices = vertices
self.canvas = canvas
def generate_polygon(self):
return self.canvas.create_polygon(self.vertices, outline = "black", fill="")
def add_vertex(self,vertex):
self.vertices.append(vertex)
def add_vertices(self,vertices):
self.vertices.append(vertices)
def get_vertices(self):
return self.vertices
def translate_poly(self,tx,ty):
trans = np.asarray([[1, 0, tx],
[0, 1, -ty,],
[0, 0, 1]])
lst = []
for stuff in self.vertices:
lst.append([stuff[0],stuff[1],1])
m_vertices = np.transpose(np.asarray(lst))
output_matrix = np.transpose(trans.dot(m_vertices))
lst = []
for stuff in output_matrix:
lst.append((stuff[0], stuff[1]))
self.vertices = lst
self.generate_polygon()
def rotate_poly(self, theta, xr, yr):
print(xr,yr)
xr = self.vertices[0][0]
yr = self.vertices[0][1]
rotation = np.asarray([[np.cos(theta), -np.sin(theta), xr*(1-np.cos(theta)) + yr*np.sin(theta) ],
[np.sin(theta), np.cos(theta), yr*(1-np.cos(theta)) - xr*np.sin(theta)],
[0, 0, 1]])
lst = []
for stuff in self.vertices:
lst.append([stuff[0],stuff[1],1])
print(self.vertices)
m_vertices = np.transpose(np.asarray(lst))
output_matrix = np.transpose(rotation.dot(m_vertices))
lst = []
for stuff in output_matrix:
lst.append((stuff[0], stuff[1]))
self.vertices = lst
print(self.vertices)
self.generate_polygon()
def scale_poly(self,sx, sy, xr, yr):
xr = self.vertices[0][0]
yr = self.vertices[0][1]
scale = np.asarray([[sx, 0, xr*(1-sx)],
[0, sy, yr*(1-sy)],
[0, 0, 1]])
lst = []
for stuff in self.vertices:
lst.append([stuff[0],stuff[1],1])
print(self.vertices)
m_vertices = np.transpose(np.asarray(lst))
output_matrix = np.transpose(scale.dot(m_vertices))
lst = []
for stuff in output_matrix:
lst.append((stuff[0], stuff[1]))
self.vertices = lst
print(self.vertices)
self.generate_polygon()
app = TwoDTransformationApp(height= 800, width = 800)
app.mainloop()
@Amit2508
Copy link

can you please tell how to implement this , I mean how to scale , rotate

@the-lost-explorer
Copy link
Author

Hey, the above script pops up a window with cartesian axes. You need to left-click on the grid anywhere you want to define the vertices of a polygon. It can have as many points as you want. Once you're done choosing the endpoints, right-click on the grid to create the actual polygon. Once this is done, you'll be asked to choose one of the 3 operations - translate, rotate or scale. Once you choose one of these 3 operations, you need to enter the translation, rotation or scaling factors that you'll be asked to input. @Amit2508

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment