/
karik
/
third
Обзор
Документация
Войти
/
karik
/
third
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
3.py
228 строк
9 KB
karik
upload files
26 окт 2025, 19:41
26 окт 2025, 19:41
8d371ca
Код
Авторство
О чём код?
import tkinter as tk from tkinter import filedialog, messagebox # === Алгоритм ЦДА === def draw_cda(canvas, x1, y1, x2, y2, color="red"): dx = x2 - x1 dy = y2 - y1 steps = int(max(abs(dx), abs(dy))) x_inc = dx / steps y_inc = dy / steps x, y = x1, y1 for _ in range(steps + 1): canvas.create_rectangle(round(x), round(y), round(x)+1, round(y)+1, outline=color) x += x_inc y += y_inc # === Алгоритм Брезенхема (с плавающей точкой) === def draw_bresenham_float(canvas, x1, y1, x2, y2, color="green"): dx = x2 - x1 dy = y2 - y1 sx = 1 if dx > 0 else -1 sy = 1 if dy > 0 else -1 dx = abs(dx) dy = abs(dy) if dx > dy: m = dy / dx y = y1 for i in range(x1, x2 + sx, sx): canvas.create_rectangle(i, round(y), i+1, round(y)+1, outline=color) y += sy * m else: m = dx / dy x = x1 for i in range(y1, y2 + sy, sy): canvas.create_rectangle(round(x), i, round(x)+1, i+1, outline=color) x += sx * m # === Целочисленный алгоритм Брезенхема === def draw_bresenham_int(canvas, x1, y1, x2, y2, color="blue"): dx = abs(x2 - x1) dy = abs(y2 - y1) sx = 1 if x1 < x2 else -1 sy = 1 if y1 < y2 else -1 err = dx - dy while True: canvas.create_rectangle(x1, y1, x1+1, y1+1, outline=color) if x1 == x2 and y1 == y2: break e2 = 2 * err if e2 > -dy: err -= dy x1 += sx if e2 < dx: err += dx y1 += sy # === Алгоритм окружности === def draw_circle(canvas, xc, yc, r, color="black"): x = 0 y = r d = 1 - r circle_points(canvas, xc, yc, x, y, color) while x < y: if d < 0: d += 2 * x + 3 else: d += 2 * (x - y) + 5 y -= 1 x += 1 circle_points(canvas, xc, yc, x, y, color) def circle_points(canvas, xc, yc, x, y, color): for px, py in [ (xc + x, yc + y), (xc - x, yc + y), (xc + x, yc - y), (xc - x, yc - y), (xc + y, yc + x), (xc - y, yc + x), (xc + y, yc - x), (xc - y, yc - x), ]: canvas.create_rectangle(px, py, px+1, py+1, outline=color) # === Универсальная функция для вызова нужного алгоритма === def draw_line_by_algorithm(canvas, x1, y1, x2, y2, algo, color): if algo == "cda": draw_cda(canvas, x1, y1, x2, y2, "red") elif algo == "bres_float": draw_bresenham_float(canvas, x1, y1, x2, y2, "green") elif algo == "bres_int": draw_bresenham_int(canvas, x1, y1, x2, y2, "blue") # === Построение пацифика === def draw_pacifik(canvas, x0, y0, r, algo, color="black"): xc = x0 yc = y0 + r # Окружность draw_circle(canvas, xc, yc, r, color) # Центральный вертикальный отрезок: от верхней точки до нижней draw_line_by_algorithm(canvas, xc, yc - r, xc, yc + r, algo, color) # Наклонные линии: идут вниз от центра angle_offset = int(r * 0.6) y_center = yc + int(r * 0.1) # немного ниже середины y_bottom = yc + r # нижняя точка окружности # Левая и правая ветви (теперь наклонены вниз) draw_line_by_algorithm(canvas, xc, y_center, xc - angle_offset, y_bottom - int(r * 0.2), algo, color) draw_line_by_algorithm(canvas, xc, y_center, xc + angle_offset, y_bottom - int(r * 0.2), algo, color) # === Функция для получения всех пикселей с холста === def get_canvas_pixels(canvas, width, height): # Создаем матрицу для хранения пикселей (0 - белый, 1 - черный) pixels = [[0 for _ in range(width)] for _ in range(height)] # Получаем все элементы на холсте items = canvas.find_all() for item in items: # Получаем координаты элемента coords = canvas.coords(item) if len(coords) >= 4: # У прямоугольника должно быть 4 координаты x1, y1, x2, y2 = int(coords[0]), int(coords[1]), int(coords[2]), int(coords[3]) # Помечаем пиксель как закрашенный (1) if 0 <= x1 < width and 0 <= y1 < height: pixels[y1][x1] = 1 return pixels # === Функция для сохранения в PBM формат === def save_as_pbm(canvas, width, height): try: # Получаем пиксели с холста pixels = get_canvas_pixels(canvas, width, height) # Открываем диалог для выбора файла file_path = filedialog.asksaveasfilename( defaultextension=".pbm", filetypes=[("PBM files", "*.pbm"), ("All files", "*.*")] ) if file_path: with open(file_path, 'w') as f: # Записываем заголовок PBM f.write("P1\n") f.write(f"{width} {height}\n") # Записываем данные пикселей for row in pixels: f.write(" ".join(map(str, row)) + "\n") messagebox.showinfo("Успех", f"Изображение сохранено в {file_path}") except Exception as e: messagebox.showerror("Ошибка", f"Не удалось сохранить файл: {str(e)}") # === Интерфейс === def main(): root = tk.Tk() root.title("Пацифик — сравнение алгоритмов растеризации") canvas_width = 600 canvas_height = 600 canvas = tk.Canvas(root, width=canvas_width, height=canvas_height, bg="white") canvas.pack() tk.Label(root, text="Выберите алгоритм:").pack() algo_var = tk.StringVar(value="cda") tk.Radiobutton(root, text="ЦДА", variable=algo_var, value="cda").pack(anchor="w") tk.Radiobutton(root, text="Брезенхем (float)", variable=algo_var, value="bres_float").pack(anchor="w") tk.Radiobutton(root, text="Брезенхем (int)", variable=algo_var, value="bres_int").pack(anchor="w") # Добавляем поля для ввода x0, y0 и радиуса tk.Label(root, text="Введите x0 (координата центра по X):").pack(anchor="w") x0_entry = tk.Entry(root) x0_entry.pack() x0_entry.insert(0, "300") # Значение по умолчанию tk.Label(root, text="Введите y0 (координата центра по Y):").pack(anchor="w") y0_entry = tk.Entry(root) y0_entry.pack() y0_entry.insert(0, "150") # Значение по умолчанию tk.Label(root, text="Введите радиус r:").pack(anchor="w") radius_entry = tk.Entry(root) radius_entry.pack() radius_entry.insert(0, "120") # Значение по умолчанию # Метка для отображения ошибок error_label = tk.Label(root, text="", fg="red") error_label.pack() def on_draw(): canvas.delete("all") try: # Получаем значения из полей ввода x0 = int(x0_entry.get()) y0 = int(y0_entry.get()) radius = int(radius_entry.get()) # Проверяем if radius <= 0: error_label.config(text="Радиус должен быть положительным!") return if x0 < 0 or x0 > canvas_width or y0 < 0 or y0 > canvas_height: error_label.config(text=f"Координаты x0, y0 должны быть в пределах 0–{canvas_width}!") return if radius > min(x0, y0, canvas_width - x0, canvas_height - y0): error_label.config(text="Радиус слишком большой для холста!") return error_label.config(text="") # Очищаем сообщение об ошибке draw_pacifik(canvas, x0, y0, radius, algo_var.get()) except ValueError: error_label.config(text="Введите корректные числа для x0, y0 и радиуса!") # Фрейм для кнопок button_frame = tk.Frame(root) button_frame.pack(pady=10) tk.Button(button_frame, text="Нарисовать пацифик", command=on_draw).pack(side=tk.LEFT, padx=5) tk.Button(button_frame, text="Сохранить как PBM", command=lambda: save_as_pbm(canvas, canvas_width, canvas_height)).pack(side=tk.LEFT, padx=5) root.mainloop() if __name__ == "__main__": main()