Прикреплённый файл «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 из ссылки «[получить]», так как он чисто внутренний и может измениться.
 Все файлы | Выбранные файлы: удалить переместить на страницу скопировать на страницу

Вам нельзя прикреплять файлы к этой странице.