Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # tk_adjust_polygon.py
- import tkinter as tk
- from tkinter import ttk
- from math import cos, sin, radians, degrees, atan2, hypot, pi
- import os
- HANDLE_RADIUS = 5
- canvas_items = []
- handles = []
- polygon_points = []
- active_handle = 1
- selected_line = 1
- adjust_window = None
- halo = None
- last_updated = 'xy'
- def clear_console():
- os.system('cls' if os.name == 'nt' else 'clear')
- def distance(p1, p2):
- return hypot(p1[0] - p2[0], p1[1] - p2[1])
- def update_polygon():
- flat = [coord for pt in polygon_points for coord in pt]
- canvas.coords(canvas_items[0], *flat)
- for i, h in enumerate(handles):
- x, y = polygon_points[i]
- canvas.coords(h, x - HANDLE_RADIUS, y - HANDLE_RADIUS, x + HANDLE_RADIUS, y + HANDLE_RADIUS)
- if halo and i == selected_line:
- halo_radius = HANDLE_RADIUS + 4
- canvas.coords(halo, x - halo_radius, y - halo_radius, x + halo_radius, y + halo_radius)
- update_sliders_from_selected()
- def on_press(event):
- global active_handle, selected_line, halo
- obj = canvas.find_withtag("current")[0]
- for i, h in enumerate(handles):
- if obj == h:
- selected_line = i
- active_handle = h
- break
- for i, h in enumerate(handles):
- if i == selected_line or i == (selected_line + 1) % len(polygon_points):
- canvas.itemconfig(h, fill='lime')
- else:
- canvas.itemconfig(h, fill='red')
- if not halo:
- halo = canvas.create_oval(0, 0, 0, 0, outline='green', width=2)
- x, y = polygon_points[selected_line]
- r = HANDLE_RADIUS + 4
- canvas.coords(halo, x - r, y - r, x + r, y + r)
- canvas.tag_lower(halo)
- def on_drag(event):
- x, y = event.x, event.y
- polygon_points[selected_line] = (x, y)
- update_polygon()
- def on_release(event):
- update_polygon()
- def create_polygon(n, radius, center, length_override=0):
- for item in canvas_items:
- canvas.delete(item)
- for h in handles:
- canvas.delete(h)
- canvas_items.clear()
- handles.clear()
- polygon_points.clear()
- cx, cy = center
- if length_override > 0:
- angle_step = 2 * pi / n
- polygon_points.append((cx + length_override, cy))
- for i in range(1, n):
- angle = angle_step * i
- next_x = cx + cos(angle) * length_override
- next_y = cy + sin(angle) * length_override
- polygon_points.append((next_x, next_y))
- else:
- for i in range(n):
- angle = 2 * pi * i / n
- x = cx + radius * cos(angle)
- y = cy + radius * sin(angle)
- polygon_points.append((x, y))
- poly = canvas.create_polygon(*[c for pt in polygon_points for c in pt], outline="black", fill="", width=2)
- canvas_items.append(poly)
- for i in range(n):
- h = canvas.create_oval(0, 0, 0, 0, fill='red')
- canvas.tag_bind(h, "<ButtonPress-1>", on_press)
- canvas.tag_bind(h, "<B1-Motion>", on_drag)
- canvas.tag_bind(h, "<ButtonRelease-1>", on_release)
- handles.append(h)
- update_polygon()
- def toggle_adjust_window(event=None):
- global adjust_window, angle_var, length_var, x_var, y_var
- if adjust_window and adjust_window.winfo_exists():
- adjust_window.destroy()
- adjust_window = None
- return
- adjust_window = tk.Toplevel(root)
- adjust_window.title("Adjust Line")
- def update_selected_from_sliders(val=None):
- a = polygon_points[selected_line]
- angle = radians(angle_var.get())
- length = length_var.get()
- dx = cos(angle) * length
- dy = sin(angle) * length
- b = (a[0] + dx, a[1] + dy)
- polygon_points[(selected_line + 1) % len(polygon_points)] = b
- update_polygon()
- def update_selected_from_xy(val=None):
- polygon_points[selected_line] = (x_var.get(), y_var.get())
- update_polygon()
- def reset_polygon():
- create_polygon(reset_sides.get(), 290, (300, 300), length_override=reset_length.get())
- slider_specs = [
- ("Angle (deg)", angle_var, update_selected_from_sliders, 0, 360, 0.1),
- ("Length", length_var, update_selected_from_sliders, 0, 1000, 1),
- ("X Position", x_var, update_selected_from_xy, -300, 900, 1),
- ("Y Position", y_var, update_selected_from_xy, -300, 900, 1),
- ]
- for label_text, variable, command, from_, to, resolution in slider_specs:
- tk.Label(adjust_window, text=label_text, anchor='w').pack(fill='x', padx=5)
- tk.Scale(adjust_window, from_=from_, to=to, resolution=resolution,
- variable=variable, orient='horizontal', length=1000,
- command=command).pack()
- ttk.Separator(adjust_window, orient='horizontal').pack(fill='x', padx=10, pady=5)
- tk.Label(adjust_window, text="RESET POLYGON", fg='red').pack()
- reset_sides = tk.IntVar(value=12)
- reset_length = tk.DoubleVar(value=0)
- tk.Label(adjust_window, text="Number of Sides", fg='red', anchor='w').pack(fill='x', padx=5)
- tk.Scale(adjust_window, from_=3, to=120, variable=reset_sides,
- orient='horizontal', length=1000).pack()
- tk.Label(adjust_window, text="Side Length (0 = radius mode)", fg='red', anchor='w').pack(fill='x', padx=5)
- tk.Scale(adjust_window, from_=0, to=500, resolution=1, variable=reset_length,
- orient='horizontal', length=1000).pack()
- tk.Button(adjust_window, text="Reset", bg='red', fg='white', command=reset_polygon).pack()
- def update_sliders_from_selected():
- start_point = polygon_points[selected_line]
- end_point = polygon_points[(selected_line + 1) % len(polygon_points)]
- current_x, current_y = start_point
- x_var.set(current_x)
- y_var.set(current_y)
- dx = end_point[0] - start_point[0]
- dy = end_point[1] - start_point[1]
- current_angle = degrees(atan2(dy, dx)) % 360
- angle_var.set(current_angle)
- current_length = distance(start_point, end_point)
- length_var.set(current_length)
- def on_spacebar(event=None):
- clear_console()
- min_x = min(x for x, y in polygon_points)
- min_y = min(y for x, y in polygon_points)
- shifted = [(int(x - min_x), int(y - min_y)) for x, y in polygon_points]
- print(f"polygon = {shifted}")
- def adj_angle(delta):
- def _adjust(event=None):
- if angle_var:
- angle_var.set(angle_var.get() + delta)
- update_selected_from_sliders()
- return _adjust
- root = tk.Tk()
- canvas = tk.Canvas(root, width=600, height=600, bg='white')
- canvas.pack()
- angle_var = tk.DoubleVar()
- length_var = tk.DoubleVar()
- x_var = tk.DoubleVar()
- y_var = tk.DoubleVar()
- create_polygon(12, 290, (300, 300))
- canvas.bind_all("<z>", toggle_adjust_window)
- canvas.bind_all("<space>", on_spacebar)
- incr = 0.01
- canvas.bind_all("<Right>", adj_angle(+incr))
- canvas.bind_all("<Left>", adj_angle(-incr))
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement