{ "cells": [ { "cell_type": "markdown", "id": "elementary-emperor", "metadata": {}, "source": [ "Create a GUI using ``tkinter`` to interactively draw points and visualize the **minimum enclosing circle** (as computed in the optimization lecture using ``scipy.optimize.minimize``).\n", "\n", "_Note_: The circle found using ``minimize`` might not be smallest possible, since ``minimize`` is not guaranteed to find the find the minimum. For (more complicated) algorithms guaranteed to find a minimum enclosing circle see https://en.wikipedia.org/wiki/Smallest-circle_problem." ] }, { "cell_type": "code", "execution_count": 31, "id": "periodic-bangladesh", "metadata": {}, "outputs": [], "source": [ "from scipy.optimize import minimize\n", "\n", "def dist(p, q):\n", " return ((p[0] - q[0]) ** 2 + (p[1] - q[1]) ** 2) ** 0.5\n", "\n", "def max_dist(p, S):\n", " return max(dist(p, q) for q in S)\n", "\n", "def minimum_enclosing_circle(points):\n", " '''Find mindste cirkel med scipy minimize - fejler nogle gange !!!'''\n", "\n", " def f(p):\n", " return max_dist(p, points)\n", " \n", " solution = minimize(f, [0, 0])\n", " radius = solution.fun\n", " center = solution.x\n", " \n", " return center, radius" ] }, { "cell_type": "code", "execution_count": 80, "id": "acceptable-privilege", "metadata": {}, "outputs": [], "source": [ "import tkinter as tk\n", "\n", "# Til at opdatere canvasen\n", "\n", "def draw_circle(point, radius=3, fill='white'):\n", " x, y = point\n", " canvas.create_oval(x - radius, y - radius, x + radius, y + radius, fill=fill)\n", "\n", "def redraw():\n", " canvas.delete('all') # fjern alle eksisterende punkter\n", " if len(points) >= 2:\n", " center, radius = minimum_enclosing_circle(points)\n", " draw_circle(center, radius, fill='red')\n", " draw_circle(center, 5, fill='yellow')\n", " info_var.set(f'radius = {radius:.2f}')\n", " else:\n", " info_var.set('Tegn nogle punkter')\n", " for point in points:\n", " draw_circle(point)\n", " \n", "# Håndtering af tryk på taster og knapper på skærmen\n", " \n", "def do_quit(event=None):\n", " root.destroy()\n", " \n", "def clear_all():\n", " points.clear()\n", " redraw()\n", "\n", "def undo(event):\n", " if points:\n", " deleted_points.append(points.pop())\n", " redraw()\n", " \n", "def redo(event):\n", " if deleted_points:\n", " points.append(deleted_points.pop())\n", " redraw()\n", " \n", "# Håndtering af tryk på venstre museknap\n", " \n", "def new_point(event):\n", " global current_point, current_point_moved\n", " \n", " x, y = event.x, event.y\n", " point = (x, y)\n", " \n", " nearest = min(points, \n", " key=lambda p: dist(point, p),\n", " default=None)\n", " if nearest != None and dist(point, nearest) <= 10:\n", " current_point = points.index(nearest)\n", " current_point_moved = False\n", " else: \n", " points.append(point)\n", " current_point = len(points) - 1\n", " current_point_moved = True\n", " redraw()\n", " \n", "def move_point(event):\n", " global current_point_moved \n", " \n", " x, y = event.x, event.y\n", " point = (x,y)\n", " \n", " if current_point != None:\n", " current_point_moved = True\n", " points[current_point] = point\n", " redraw()\n", " \n", "def release_point(event):\n", " global current_point\n", " \n", " if not current_point_moved:\n", " deleted_points.append(points[current_point])\n", " del points[current_point]\n", " redraw()\n", " current_point = None\n", "\n", "# Opret vindue\n", "\n", "root = tk.Tk()\n", "root.title('Mindste omsluttende circel')\n", "\n", "kasse = tk.Frame(root) # Til at indeholde knapperne i bunden af skærmen\n", "quit_button = tk.Button(kasse, text='Quit (Ctrl-q)', command=do_quit)\n", "quit_button.pack(side=tk.LEFT, padx=5, pady=5)\n", "\n", "clear_button = tk.Button(kasse, text='Clear all', command=clear_all)\n", "clear_button.pack(side=tk.LEFT, padx=5, pady=5)\n", "\n", "info_var = tk.StringVar()\n", "#info_label = tk.Label(kasse, text='Tegn nogle punkter', fg='red')\n", "info_label = tk.Label(kasse, textvariable=info_var, fg='red')\n", "info_label.pack(side=tk.RIGHT, padx=5, pady=5)\n", "\n", "kasse.pack(side=tk.BOTTOM, expand=True, fill=tk.X)\n", "\n", "canvas = tk.Canvas(root, width=500, height=400, bg='green')\n", "canvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)\n", " \n", "points = []\n", "deleted_points = []\n", "current_point = None\n", "current_point_moved = False\n", "\n", "canvas.bind('', new_point)\n", "canvas.bind('', move_point)\n", "canvas.bind('', release_point)\n", "\n", "root.bind('', undo)\n", "root.bind('', redo)\n", "root.bind('', do_quit)\n", "\n", "redraw()\n", "tk.mainloop()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.4" } }, "nbformat": 4, "nbformat_minor": 5 }