import matplotlib.pyplot as plt import numpy as np class Plot: def __init__(self): self.fig, self.ax = plt.subplots() # Obsługa kliknięć myszą self.cid_click = self.fig.canvas.mpl_connect('button_press_event', self.onclick) self.cid_motion = self.fig.canvas.mpl_connect('motion_notify_event', self.on_mouse_move) self.cid_release = self.fig.canvas.mpl_connect('button_release_event', self.on_release) self.cid_key = self.fig.canvas.mpl_connect('key_press_event', self.on_key_press) # Obsługa klawiatury # Ustawienia wykresu plt.xlim(0, 800) plt.ylim(0, 600) plt.grid() self.line = [] # Linia rysowana przez użytkownika self.controlPoints = [] # Punkty kontrolne krzywej Béziera self.approximation_points = [] # Punkty aproksymacji krzywej self.isDrawing = False # Flaga rysowania self.inputMode = 0 # Tryb wejścia: 0 - rysowanie linii, 1 - dodawanie punktów kontrolnych def on_key_press(self, event): """Przełączanie trybu rysowania i dodawania punktów kontrolnych przy użyciu klawisza 'm'.""" if event.key == 'm': self.inputMode = (self.inputMode + 1) % 2 mode = "Rysowanie linii" if self.inputMode == 0 else "Dodawanie punktów kontrolnych" print(f"Tryb zmieniony na: {mode}") def onclick(self, event): # Tryb rysowania linii if self.inputMode == 0: self.isDrawing = True # Tryb dodawania punktów kontrolnych elif self.inputMode == 1 and len(self.controlPoints) < 15: self.controlPoints.append((event.xdata, event.ydata)) # Automatyczna generacja segmentów krzywej Béziera po dodaniu nowych punktów if len(self.controlPoints) >= 4: self.generate_bezier_segments() self.drawPlot() def on_mouse_move(self, event): if self.isDrawing: self.line.append((event.xdata, event.ydata)) self.drawPlot() def on_release(self, event): # Zakończ rysowanie linii if self.inputMode == 0: self.isDrawing = False def generate_bezier_segments(self): """Tworzy segmenty krzywej Béziera na podstawie punktów kontrolnych.""" self.approximation_points = [] # Dzielenie punktów kontrolnych na segmenty długości 4 (dla krzywej Béziera stopnia 3) for i in range(0, len(self.controlPoints) - 3, 3): segment = self.controlPoints[i:i + 4] t_values = np.linspace(0, 1, num=100) bezier_points = np.array([self.de_casteljau(segment, t) for t in t_values]) self.approximation_points.append(bezier_points) def drawPlot(self): self.ax.clear() # Rysowanie linii narysowanej przez użytkownika if len(self.line) > 1: self.ax.plot(*zip(*self.line), color='red', label='Linia narysowana') # Rysowanie punktów kontrolnych if len(self.controlPoints) > 0: self.ax.scatter(*zip(*self.controlPoints), color='black', label='Punkty kontrolne') # Rysowanie segmentów krzywej Béziera (dodanie etykiety tylko raz) first_segment = True for segment in self.approximation_points: if first_segment: self.ax.plot(segment[:, 0], segment[:, 1], color='blue', label='Krzywa Béziera') first_segment = False else: self.ax.plot(segment[:, 0], segment[:, 1], color='blue') self.ax.legend() self.ax.set_xlim(0, 800) self.ax.set_ylim(0, 600) self.ax.grid() plt.draw() def de_casteljau(self, points, t): """Oblicza punkt na krzywej Béziera za pomocą algorytmu de Casteljau dla danego t.""" points = np.array(points) n = len(points) for r in range(1, n): for i in range(n - r): points[i] = (1 - t) * points[i] + t * points[i + 1] return points[0] def run(self): plt.show() if __name__ == "__main__": plot = Plot() plot.run()