Created
August 17, 2019 15:10
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
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
can you please tell how to implement this , I mean how to scale , rotate