Прикреплённый файл «PolyTk.py»
Загрузка 1 #!/usr/bin/env python3
2 import tkinter as tk
3 from math import ceil
4 try:
5 from src.Perimeter import inside, convex
6 except Exception as E:
7 print(E)
8
9 convex = inside = lambda *x: 0.0
10
11 class ShapeEditorApp:
12 def _center(self, objid):
13 x0, y0, x1, y1 = self.canvas.coords(objid)
14 return (x1 + x0) / 2, (y1 + y0) / 2
15
16 def _oval(self, x, y):
17 return x - self.radius, y - self.radius, x + self.radius, y + self.radius
18
19 def _float(self, xy):
20 return [float(c) for c in xy.split(",")]
21
22 def _load(self, file):
23 with open(file, "rt") as f:
24 dots = [self._float(dot) for dot in f.readline().split()]
25 single = self._float(f.readline())
26 return dots, single
27
28 def __init__(self, root, file=None):
29 self.root = root
30 self.root.title("Shape Editor")
31 self.root.rowconfigure(0, weight=1)
32 self.root.rowconfigure(0, weight=1)
33 self.root.columnconfigure(0, weight=1)
34
35 # Create Canvas widget
36 self.canvas = tk.Canvas(root, bg="linen")
37 self.canvas.grid(column=0, row=0, sticky="NEWS")
38 self.info = tk.StringVar()
39 self.dump = tk.Label(self.root, textvariable=self.info, justify=tk.LEFT)
40 self.dump.grid(column=0, row=1, sticky="NEWS")
41
42 self.dots, self.singledot, self.line, self.closeline, self.moving = [], None, None, None, None
43 self.one = float(self.canvas["height"]) // 100
44 self.width, self.radius = ceil(self.one / 2), self.one * 1.5
45
46 self.canvas.bind("<Button-1>", self.next)
47 self.canvas.bind("<Button-3>", self.next)
48 self.canvas.bind("<Motion>", self.move)
49 self.root.bind("<Any-KeyPress>", self.control)
50
51 self.inspect = False
52
53 if file:
54 dots, (sx, sy) = self._load(file)
55 for x, y in dots:
56 self.next(type("event", (), {"x": x, "y": y, "num": 1}))
57 self.canvas.event_generate("<Button-2>", x=sx, y=sy)
58
59 def control(self, event):
60 # print(event)
61 match event.keysym:
62 case "Escape" | "q":
63 root.quit()
64 case "space":
65 self.canvas.event_generate("<Button-2>", x=event.x, y=event.y)
66 case "Delete" | "BackSpace":
67 if self.dots:
68 self.moving = self.dots[-1]
69
70 def move(self, event):
71 if self.moving:
72 oval = self._oval(event.x, event.y)
73 self.canvas.coords(self.moving, *oval)
74 newline = [self._center(obj) for obj in self.dots]
75 self.canvas.coords(self.line, *newline)
76 self.canvas.coords(self.closeline, *self._center(self.dots[0]), *self._center(self.dots[-1]))
77
78 def has_dot(self, x, y, *sets):
79 res = set(self.canvas.find_overlapping(x, y, x, y)) & set.union(*map(set, sets))
80 return res.pop() if res else None
81
82 def next(self, event):
83 c = self.canvas
84 oval = self._oval(event.x, event.y)
85 if obj := self.has_dot(event.x, event.y, self.dots, {self.singledot}):
86 if self.moving:
87 self.moving = None
88 else:
89 self.moving = obj
90 elif event.num != 1:
91 self.moving = None
92 if self.singledot:
93 c.coords(self.singledot, oval)
94 else:
95 self.singledot = c.create_oval(*oval, fill="firebrick")
96 else:
97 self.moving = None
98 self.dump["wraplength"] = self.root.grid_bbox(0, 0, 1, 1)[2]
99 self.dots.append(c.create_oval(*oval, fill="black"))
100 if len(self.dots) < 2:
101 return
102 (x0, y0), (x1, y1) = self._center(self.dots[0]), self._center(self.dots[-1])
103 if len(self.dots) == 2:
104 self.line = c.create_line(x0, y0, x1, y1, fill="grey", width=self.width)
105 else:
106 c.coords(self.line, *c.coords(self.line), x1, y1)
107 if len(self.dots) == 3:
108 self.closeline = c.create_line(x1, y1, x0, y0, fill="grey66", width=self.width, dash=self.width)
109 if len(self.dots) > 3:
110 c.coords(self.closeline, x1, y1, x0, y0)
111 longstr = " ".join(f"{c[0]},{c[1]}" for c in (self._center(dot) for dot in self.dots))
112 if self.singledot:
113 x, y = self._center(self.singledot)
114 longstr += f"\n{x},{y}"
115 if self.dots:
116 c.itemconfigure(self.line, fill="darkgreen" if convex(map(self._center, self.dots)) else "firebrick")
117 internal = inside(self._center(self.singledot), map(self._center, self.dots))
118 c.itemconfigure(self.singledot, fill="darkgreen" if internal else "firebrick")
119
120 self.info.set(longstr)
121 self.root.clipboard_clear()
122 self.root.clipboard_append(longstr)
123 root.update()
124
125
126 if __name__ == "__main__":
127 import sys
128 root = tk.Tk()
129 app = ShapeEditorApp(root, sys.argv[1] if len(sys.argv) > 1 else None)
130 root.mainloop()
131 print(app.info.get())
Прикреплённые файлы
Для ссылки на прикреплённый файл в тексте страницы напишите attachment:имяфайла, как показано ниже в списке файлов. Не используйте URL из ссылки «[получить]», так как он чисто внутренний и может измениться.Вам нельзя прикреплять файлы к этой странице.
