How to enlarge and reduce an already drawn lines, using certain buttons?

Viewed 220

Suppose I have the following program made with Tkinter in Python, in which you can click to draw any shape.

import tkinter
canvas = tkinter.Canvas(width=500, height=500, bg='white')
canvas.pack()

line = ()
def draw():
    canvas.delete('all')
    if len(line) >= 4:
        canvas.create_line(line, fill='red', width=2)
def newline(coordinates):
    global line
    line = line + (coordinates.x, coordinates.y)
    draw()
canvas.bind('<Button-1>', newline)

I have tried this for smaller image, but it didn't work.

def reduced():
    line_reduced = ()
    for i in newline:
        line_reduced += (i/2,)
        canvas.delete('all')
        canvas.create_line(line_reduced, fill='red', width=4, tags='foto1')

I would need to add it so that this shape can then be reduced or enlarged using two keys. The image would therefore remain the same (shape), it would only be reduced / enlarged.

I will be grateful for any advice.

1 Answers

If you are trying to scale a bunch of lines on a canvas you could use scale, but then everything new that you add to the canvas would also have to be scaled or it starts getting weird. What you likely really need is math. Specifically this equation N = Scale * (N - Pn) + Pn. Below is a simple drawing interface with the buttons you requested. Primarily it's just a bunch of storing points and creating lines. The part of interest to you is this line:

line[n] = scale * (point - center) + center.

Lines are stored as [x1, y1, x2, y2] in my example code (the beginning and end of a line). line would refer to such a list. line[n] refers to each x and y value in that list as n is incremented. That being said:

line[n] = scale * (point - center) + center is really saying to subtract the center from the point, multiply it by the scale number, and then add the center back in so the scaled point stays it's scaled distance from the center.

Let's run through this one time so you definitely understand.

Chalkboard:

x1     = 100
center = 200
scale  = 2

formula: x1 = scale * (x1 - center) + center
1      : x1 = 2 * (100 - 200) + 200
2      : x1 = 2 * (-100) + 200
3      : x1 = -200 + 200
4      : x1 = 0

The old x1 was 100 away from the center
now x1 is 200 away from the center
x1 is scale times further from the center than it was before

Code:

import tkinter as tk
root = tk.Tk()

canvas = tk.Canvas(root, width=800, height=600, bg='white')
canvas.pack()

#for storing line canvas ids and line coordinates
line_ids, lines = [], [] 

#line properties ~ width and fill
global w, f
w, f = 2, 'red'

#draw a line
def draw(event):
    if event.type is tk.EventType.ButtonPress:
        #store line start coordinate
        lines.append([event.x, event.y])
        #create a dummy line
        line_ids.append(canvas.create_line(*lines[-1], *lines[-1], fill=f, width=w))
    elif event.type is tk.EventType.Motion:
        #keep deleting and redrawing the current line til you release the mouse
        canvas.delete(line_ids.pop())
        line_ids.append(canvas.create_line(*lines[-1], event.x, event.y, fill=f, width=w))
    elif event.type is tk.EventType.ButtonRelease:
        #append the end coordinate to the last line
        lines[-1] += [event.x, event.y]

#add mouse events to canvas for drawing functionality
for event in ['<B1-Motion>', '<Button-1>', '<ButtonRelease-1>']:
    canvas.bind(event, draw) 

#scale lines
def scale_lines(scale): 
    #remove all canvas references to lines   
    canvas.delete("all")
    line_ids = []
    #traverse every line
    for i, line in enumerate(lines):
        #traverse every point in THIS line
        for n, point in enumerate(line):
            #toggle between center x and center y depending if point is an x or y
            center = canvas.winfo_width()/2 if not n%2 else canvas.winfo_height()/2
            #scale this point
            line[n] = scale * (point - center) + center
        #create a new line with scaled points
        line_ids.append(canvas.create_line(*line, fill=f, width=w))    

#increase/decrease buttons    
tk.Button(root, command=lambda: scale_lines(.5), text='decrease').pack(side='left')
tk.Button(root, command=lambda: scale_lines(2), text='increase').pack(side='left')

root.mainloop()
Related