bailofwZ
bailofwZ

Reputation: 143

Drawing rectangle on angled line in Tkinter Python

I have a big project that shows movement of objects. I draw many of shapes according to each other but this one is little bit tricky for me. I spent many days to achieve it but I couldn't draw it correctly. If anyone shows me a small demo, I can do the rest by myself.

I have a line with 2 endpoints. (x1,y1) and (x2,y2) s.t. all 4 parameters may dynamically change with the condition y2 is always greater than y1. In other words, endpoint of the line is always pointing down. I need to slide a rectangle with the given width and height on the drawn line. Sliding position on the angled line is also given by the user. Let's call it as position. Position 0 point is where the left corner of the rectangle touches x1,y1 in the below picture. I drew what I explained above. There are total 7 parameters bolted above.

enter image description here

Sliding rectangle must be always at the right side of the drawn line.

enter image description here

Total, there could be 3 cases. 2 of them are shown above, and I didn't draw vertical line case where x1=x2 since it's quite easy to imagine how it is going to look like.

If anyone shows me how to do it in Tkinter, I would be very appreciated.

Thanks in advance!

Upvotes: 0

Views: 90

Answers (1)

bailofwZ
bailofwZ

Reputation: 143

The code block below does what I asked above.

import tkinter as tk
import math


def draw_line_and_rectangle():
    # Clear the canvas
    canvas.delete("all")

    # Get user inputs for line coordinates
    x1 = float(entry_x1.get())
    y1 = float(entry_y1.get())
    x2 = float(entry_x2.get())
    y2 = float(entry_y2.get())

    # Ensure y2 is greater than y1
    if y2 < y1:
        x1, y1, x2, y2 = x2, y2, x1, y1

    # Draw the line
    canvas.create_line(x1, y1, x2, y2)

    # Get user inputs for rectangle dimensions and position
    width = float(entry_width.get())
    height = float(entry_height.get())
    position = float(entry_position.get())

    # Calculate the angle of the line
    angle_rad = math.atan2(y2 - y1, x2 - x1)

    # Calculate the length of the line
    length = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)

    # Calculate the position of the rectangle's left corner along the line
    dx = position * length

    # Calculate the coordinates of the rectangle's vertices
    rect_angle_rad = angle_rad + math.pi / 2
    rect_top_left_x = x1 - dx * math.cos(angle_rad)
    rect_top_left_y = y1 - dx * math.sin(angle_rad)
    rect_top_right_x = rect_top_left_x + width * math.cos(angle_rad)
    rect_top_right_y = rect_top_left_y + width * math.sin(angle_rad)
    rect_bottom_left_x = rect_top_left_x + height * math.cos(rect_angle_rad)
    rect_bottom_left_y = rect_top_left_y + height * math.sin(rect_angle_rad)
    rect_bottom_right_x = rect_bottom_left_x + width * math.cos(angle_rad)
    rect_bottom_right_y = rect_bottom_left_y + width * math.sin(angle_rad)

    # Calculate the mirrored coordinates of the rectangle
    mirrored_rect_top_left_x = 2 * x1 - rect_top_left_x
    mirrored_rect_top_left_y = 2 * y1 - rect_top_left_y
    mirrored_rect_top_right_x = 2 * x1 - rect_top_right_x
    mirrored_rect_top_right_y = 2 * y1 - rect_top_right_y
    mirrored_rect_bottom_left_x = 2 * x1 - rect_bottom_left_x
    mirrored_rect_bottom_left_y = 2 * y1 - rect_bottom_left_y
    mirrored_rect_bottom_right_x = 2 * x1 - rect_bottom_right_x
    mirrored_rect_bottom_right_y = 2 * y1 - rect_bottom_right_y

    # Draw the mirrored rectangle
    canvas.create_polygon(mirrored_rect_top_left_x, mirrored_rect_top_left_y, mirrored_rect_top_right_x,
                          mirrored_rect_top_right_y,
                          mirrored_rect_bottom_right_x, mirrored_rect_bottom_right_y, mirrored_rect_bottom_left_x,
                          mirrored_rect_bottom_left_y, fill='red')


# Create the main window
root = tk.Tk()
root.geometry("600x600")
root.title("Draw Line and Rectangle")

# Create a canvas
canvas = tk.Canvas(root, width=500, height=500, bg='white')
canvas.grid(row=0, column=0, columnspan=2)

# Entry widgets for line coordinates
label_x1 = tk.Label(root, text="X1:")
label_x1.grid(row=1, column=0)
entry_x1_var = tk.StringVar()
entry_x1_var.set("50")  # Default value
entry_x1 = tk.Entry(root, textvariable=entry_x1_var)
entry_x1.grid(row=1, column=1)

label_y1 = tk.Label(root, text="Y1:")
label_y1.grid(row=2, column=0)
entry_y1_var = tk.StringVar()
entry_y1_var.set("50")  # Default value
entry_y1 = tk.Entry(root, textvariable=entry_y1_var)
entry_y1.grid(row=2, column=1)

label_x2 = tk.Label(root, text="X2:")
label_x2.grid(row=3, column=0)
entry_x2_var = tk.StringVar()
entry_x2_var.set("350")  # Default value
entry_x2 = tk.Entry(root, textvariable=entry_x2_var)
entry_x2.grid(row=3, column=1)

label_y2 = tk.Label(root, text="Y2:")
label_y2.grid(row=4, column=0)
entry_y2_var = tk.StringVar()
entry_y2_var.set("350")  # Default value
entry_y2 = tk.Entry(root, textvariable=entry_y2_var)
entry_y2.grid(row=4, column=1)

# Entry widgets for rectangle dimensions and position
label_width = tk.Label(root, text="Rectangle Width:")
label_width.grid(row=5, column=0)
entry_width_var = tk.StringVar()
entry_width_var.set("60")  # Default value
entry_width = tk.Entry(root, textvariable=entry_width_var)
entry_width.grid(row=5, column=1)

label_height = tk.Label(root, text="Rectangle Height:")
label_height.grid(row=6, column=0)
entry_height_var = tk.StringVar()
entry_height_var.set("30")  # Default value
entry_height = tk.Entry(root, textvariable=entry_height_var)
entry_height.grid(row=6, column=1)

label_position = tk.Label(root, text="Position:")
label_position.grid(row=7, column=0)
entry_position_var = tk.StringVar()
entry_position_var.set("0.3")  # Default value
entry_position = tk.Entry(root, textvariable=entry_position_var)
entry_position.grid(row=7, column=1)

# Button to draw the line and rectangle
button_draw = tk.Button(root, text="Draw Line and Rectangle", command=draw_line_and_rectangle)
button_draw.grid(row=8, column=0, columnspan=2)

root.mainloop()

Upvotes: 1

Related Questions