Skip to content

Commit

Permalink
final version
Browse files Browse the repository at this point in the history
  • Loading branch information
YoC00lig authored Jan 4, 2023
1 parent c9466b5 commit 4bf48fd
Show file tree
Hide file tree
Showing 8 changed files with 10,291 additions and 0 deletions.
2,235 changes: 2,235 additions & 0 deletions Chan.ipynb

Large diffs are not rendered by default.

1,237 changes: 1,237 additions & 0 deletions Graham.ipynb

Large diffs are not rendered by default.

1,167 changes: 1,167 additions & 0 deletions Jarvis.ipynb

Large diffs are not rendered by default.

1,259 changes: 1,259 additions & 0 deletions QuickHull.ipynb

Large diffs are not rendered by default.

1,173 changes: 1,173 additions & 0 deletions UpperAndLower.ipynb

Large diffs are not rendered by default.

1,630 changes: 1,630 additions & 0 deletions divideAndConquer.ipynb

Large diffs are not rendered by default.

328 changes: 328 additions & 0 deletions geometria.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,328 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Narzędzie jest oparte o kilka zewnętrznych bibliotek, które potrzebujemy najpierw zaimportować.\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.collections as mcoll\n",
"import matplotlib.colors as mcolors\n",
"from matplotlib.widgets import Button\n",
"import json as js\n",
"import random\n",
"from math import sqrt\n",
"from copy import deepcopy\n",
"\n",
"# Parametr określający jak blisko (w odsetku całego widocznego zakresu) punktu początkowego \n",
"# wielokąta musimy kliknąć, aby go zamknąć.\n",
"TOLERANCE = 0.15\n",
"\n",
"def dist(point1, point2):\n",
" return np.sqrt(np.power(point1[0] - point2[0], 2) + np.power(point1[1] - point2[1], 2))\n",
"\n",
"# Klasa ta trzyma obecny stan wykresu oraz posiada metody, które mają zostać wykonane\n",
"# po naciśnięciu przycisków.\n",
"class _Button_callback(object):\n",
" def __init__(self, scenes):\n",
" self.i = 0\n",
" self.scenes = scenes\n",
" self.adding_points = False\n",
" self.added_points = []\n",
" self.adding_lines = False\n",
" self.added_lines = []\n",
" self.adding_rects = False\n",
" self.added_rects = []\n",
"\n",
" def set_axes(self, ax):\n",
" self.ax = ax\n",
" \n",
" # Metoda ta obsługuje logikę przejścia do następnej sceny.\n",
" def next(self, event):\n",
" self.i = (self.i + 1) % len(self.scenes)\n",
" self.draw(autoscaling = True)\n",
"\n",
" # Metoda ta obsługuje logikę powrotu do poprzedniej sceny.\n",
" def prev(self, event):\n",
" self.i = (self.i - 1) % len(self.scenes)\n",
" self.draw(autoscaling = True)\n",
" \n",
" # Metoda ta aktywuje funkcję rysowania punktów wyłączając równocześnie rysowanie \n",
" # odcinków i wielokątów.\n",
" def add_point(self, event):\n",
" self.adding_points = not self.adding_points\n",
" self.new_line_point = None\n",
" if self.adding_points:\n",
" self.adding_lines = False\n",
" self.adding_rects = False\n",
" self.added_points.append(PointsCollection([]))\n",
" \n",
" # Metoda ta aktywuje funkcję rysowania odcinków wyłączając równocześnie\n",
" # rysowanie punktów i wielokątów. \n",
" def add_line(self, event): \n",
" self.adding_lines = not self.adding_lines\n",
" self.new_line_point = None\n",
" if self.adding_lines:\n",
" self.adding_points = False\n",
" self.adding_rects = False\n",
" self.added_lines.append(LinesCollection([]))\n",
"\n",
" # Metoda ta aktywuje funkcję rysowania wielokątów wyłączając równocześnie\n",
" # rysowanie punktów i odcinków.\n",
" def add_rect(self, event):\n",
" self.adding_rects = not self.adding_rects\n",
" self.new_line_point = None\n",
" if self.adding_rects:\n",
" self.adding_points = False\n",
" self.adding_lines = False\n",
" self.new_rect()\n",
" \n",
" def new_rect(self):\n",
" self.added_rects.append(LinesCollection([]))\n",
" self.rect_points = []\n",
" \n",
" # Metoda odpowiedzialna za właściwą logikę rysowania nowych elementów. W\n",
" # zależności od włączonego trybu dodaje nowe punkty, początek, koniec odcinka\n",
" # lub poszczególne wierzchołki wielokąta. Istnieje ciekawa logika sprawdzania\n",
" # czy dany punkt jest domykający dla danego wielokąta. Polega ona na tym, że\n",
" # sprawdzamy czy odległość nowego punktu od początkowego jest większa od\n",
" # średniej długości zakresu pomnożonej razy parametr TOLERANCE. \n",
" def on_click(self, event):\n",
" if event.inaxes != self.ax:\n",
" return\n",
" new_point = (event.xdata, event.ydata)\n",
" if self.adding_points:\n",
" self.added_points[-1].add_points([new_point])\n",
" self.draw(autoscaling = False)\n",
" elif self.adding_lines:\n",
" if self.new_line_point is not None:\n",
" self.added_lines[-1].add([self.new_line_point, new_point])\n",
" self.new_line_point = None\n",
" self.draw(autoscaling = False)\n",
" else:\n",
" self.new_line_point = new_point\n",
" elif self.adding_rects:\n",
" if len(self.rect_points) == 0:\n",
" self.rect_points.append(new_point)\n",
" elif len(self.rect_points) == 1:\n",
" self.added_rects[-1].add([self.rect_points[-1], new_point])\n",
" self.rect_points.append(new_point)\n",
" self.draw(autoscaling = False)\n",
" elif len(self.rect_points) > 1:\n",
" if dist(self.rect_points[0], new_point) < (np.mean([self.ax.get_xlim(), self.ax.get_ylim()])*TOLERANCE):\n",
" self.added_rects[-1].add([self.rect_points[-1], self.rect_points[0]])\n",
" self.new_rect()\n",
" else: \n",
" self.added_rects[-1].add([self.rect_points[-1], new_point])\n",
" self.rect_points.append(new_point)\n",
" self.draw(autoscaling = False)\n",
" \n",
" # Metoda odpowiedzialna za narysowanie całego wykresu. Warto zauważyć,\n",
" # że zaczyna się ona od wyczyszczenia jego wcześniejszego stanu. Istnieje w\n",
" # niej nietrywialna logika zarządzania zakresem wykresu, tak żeby, w zależności\n",
" # od ustawionego parametru autoscaling, uniknąć sytuacji, kiedy dodawanie\n",
" # nowych punktów przy brzegu obecnie widzianego zakresu powoduje niekorzystne\n",
" # przeskalowanie.\n",
" def draw(self, autoscaling = True):\n",
" if not autoscaling:\n",
" xlim = self.ax.get_xlim()\n",
" ylim = self.ax.get_ylim()\n",
" self.ax.clear()\n",
" for collection in (self.scenes[self.i].points + self.added_points):\n",
" if len(collection.points) > 0:\n",
" self.ax.scatter(*zip(*(np.array(collection.points))), **collection.kwargs)\n",
" for collection in (self.scenes[self.i].lines + self.added_lines + self.added_rects):\n",
" self.ax.add_collection(collection.get_collection())\n",
" self.ax.autoscale(autoscaling)\n",
" if not autoscaling:\n",
" self.ax.set_xlim(xlim)\n",
" self.ax.set_ylim(ylim)\n",
" plt.draw()\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Klasa Scene odpowiada za przechowywanie elementów, które mają być\n",
"# wyświetlane równocześnie. Konkretnie jest to lista PointsCollection i\n",
"# LinesCollection.\n",
"class Scene:\n",
" def __init__(self, points=[], lines=[]):\n",
" self.points=points\n",
" self.lines=lines\n",
"\n",
"# Klasa PointsCollection gromadzi w sobie punkty jednego typu, a więc takie,\n",
"# które zostaną narysowane w takim samym kolorze i stylu. W konstruktorze\n",
"# przyjmuje listę punktów rozumianych jako pary współrzędnych (x, y). Parametr\n",
"# kwargs jest przekazywany do wywołania funkcji z biblioteki MatPlotLib przez\n",
"# co użytkownik może podawać wszystkie parametry tam zaproponowane. \n",
"class PointsCollection:\n",
" def __init__(self, points, **kwargs):\n",
" self.points = points\n",
" self.kwargs = kwargs\n",
" \n",
" def add_points(self, points):\n",
" self.points = self.points + points\n",
"\n",
"# Klasa LinesCollection podobnie jak jej punktowy odpowiednik gromadzi\n",
"# odcinki tego samego typu. Tworząc ją należy podać listę linii, gdzie każda\n",
"# z nich jest dwuelementową listą punktów – par (x, y). Parametr kwargs jest\n",
"# przekazywany do wywołania funkcji z biblioteki MatPlotLib przez co użytkownik\n",
"# może podawać wszystkie parametry tam zaproponowane.\n",
"class LinesCollection:\n",
" def __init__(self, lines, **kwargs):\n",
" self.lines = lines\n",
" self.kwargs = kwargs\n",
" \n",
" def add(self, line):\n",
" self.lines.append(line)\n",
" \n",
" def get_collection(self):\n",
" return mcoll.LineCollection(self.lines, **self.kwargs)\n",
"\n",
"# Klasa Plot jest najważniejszą klasą w całym programie, ponieważ agreguje\n",
"# wszystkie przygotowane sceny, odpowiada za stworzenie wykresu i przechowuje\n",
"# referencje na przyciski, dzięki czemu nie będą one skasowane podczas tzw.\n",
"# garbage collectingu.\n",
"class Plot:\n",
" def __init__(self, scenes = [Scene()], points = [], lines = [], json = None):\n",
" if json is None:\n",
" self.scenes = scenes\n",
" if points or lines:\n",
" self.scenes[0].points = points\n",
" self.scenes[0].lines = lines\n",
" else:\n",
" self.scenes = [Scene([PointsCollection(pointsCol) for pointsCol in scene[\"points\"]], \n",
" [LinesCollection(linesCol) for linesCol in scene[\"lines\"]]) \n",
" for scene in js.loads(json)]\n",
" \n",
" # Ta metoda ma szczególne znaczenie, ponieważ konfiguruje przyciski i\n",
" # wykonuje tym samym dość skomplikowaną logikę. Zauważmy, że konfigurując każdy\n",
" # przycisk podajemy referencję na metodę obiektu _Button_callback, która\n",
" # zostanie wykonana w momencie naciśnięcia.\n",
" def __configure_buttons(self):\n",
" plt.subplots_adjust(bottom=0.2)\n",
" ax_prev = plt.axes([0.6, 0.05, 0.15, 0.075])\n",
" ax_next = plt.axes([0.76, 0.05, 0.15, 0.075])\n",
" ax_add_point = plt.axes([0.44, 0.05, 0.15, 0.075])\n",
" ax_add_line = plt.axes([0.28, 0.05, 0.15, 0.075])\n",
" ax_add_rect = plt.axes([0.12, 0.05, 0.15, 0.075])\n",
" b_next = Button(ax_next, 'Następny')\n",
" b_next.on_clicked(self.callback.next)\n",
" b_prev = Button(ax_prev, 'Poprzedni')\n",
" b_prev.on_clicked(self.callback.prev)\n",
" b_add_point = Button(ax_add_point, 'Dodaj punkt')\n",
" b_add_point.on_clicked(self.callback.add_point)\n",
" b_add_line = Button(ax_add_line, 'Dodaj linię')\n",
" b_add_line.on_clicked(self.callback.add_line)\n",
" b_add_rect = Button(ax_add_rect, 'Dodaj figurę')\n",
" b_add_rect.on_clicked(self.callback.add_rect)\n",
" return [b_prev, b_next, b_add_point, b_add_line, b_add_rect]\n",
" \n",
" def add_scene(self, scene):\n",
" self.scenes.append(scene)\n",
" \n",
" def add_scenes(self, scenes):\n",
" self.scenes = self.scenes + scenes\n",
"\n",
" # Metoda toJson() odpowiada za zapisanie stanu obiektu do ciągu znaków w\n",
" # formacie JSON.\n",
" def toJson(self):\n",
" return js.dumps([{\"points\": [np.array(pointCol.points).tolist() for pointCol in scene.points], \n",
" \"lines\":[linesCol.lines for linesCol in scene.lines]} \n",
" for scene in self.scenes]) \n",
" \n",
" # Metoda ta zwraca punkty dodane w trakcie rysowania.\n",
" def get_added_points(self):\n",
" if self.callback:\n",
" return self.callback.added_points\n",
" else:\n",
" return None\n",
" \n",
" # Metoda ta zwraca odcinki dodane w trakcie rysowania.\n",
" def get_added_lines(self):\n",
" if self.callback:\n",
" return self.callback.added_lines\n",
" else:\n",
" return None\n",
" \n",
" # Metoda ta zwraca wielokąty dodane w trakcie rysowania.\n",
" def get_added_figure(self):\n",
" if self.callback:\n",
" return self.callback.added_rects\n",
" else:\n",
" return None\n",
" \n",
" # Metoda ta zwraca punkty, odcinki i wielokąty dodane w trakcie rysowania\n",
" # jako scenę.\n",
" def get_added_elements(self):\n",
" if self.callback:\n",
" return Scene(self.callback.added_points, self.callback.added_lines+self.callback.added_rects)\n",
" else:\n",
" return None\n",
" \n",
" # Główna metoda inicjalizująca wyświetlanie wykresu.\n",
" def draw(self):\n",
" plt.close()\n",
" fig = plt.figure()\n",
" self.callback = _Button_callback(self.scenes)\n",
" self.widgets = self.__configure_buttons()\n",
" ax = plt.axes(autoscale_on = False)\n",
" self.callback.set_axes(ax)\n",
" fig.canvas.mpl_connect('button_press_event', self.callback.on_click)\n",
" plt.show()\n",
" self.callback.draw()\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib notebook"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"def load(name): # ładowanie z pliku\n",
" points = []\n",
" with open(name + '.json', 'r') as file:\n",
" points = js.loads(file.read())\n",
" return points"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.12"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
Loading

0 comments on commit 4bf48fd

Please sign in to comment.