Помощник

Сайт: Информатикс
Курс: 2086 9М Информатика
Книга: Помощник
Напечатано:: Гость
Дата: Суббота, 14 Март 2026, 09:13

1. Python код

import pygame as pg


### Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (127, 127, 127)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
YELLOW = (255, 0, 255)
PURPLE = (255, 255, 0)
CYAN = (0, 255, 255)
###
### DEBUG mode


DEBUG = True


PIXEL_SIZE = 20


###
pg.init()


sizeOfScreen = [800,600] # можно менять


screen = pg.display.set_mode(sizeOfScreen)


if DEBUG:
    def putPixel(pos, color):
        screen.fill(color, ((pos[0]*PIXEL_SIZE, pos[1]*PIXEL_SIZE), (PIXEL_SIZE, PIXEL_SIZE)))
        
    def drawGrid():
        for i in range(PIXEL_SIZE, sizeOfScreen[0], PIXEL_SIZE):
            pg.draw.line(screen, GRAY, (i, 0), (i, sizeOfScreen[1]))
        for i in range(PIXEL_SIZE, sizeOfScreen[1], PIXEL_SIZE):
            pg.draw.line(screen, GRAY, (0, i), (sizeOfScreen[0], i))
    
else:
    def putPixel(pos, color):
        screen.set_at(pos, color)
        
    def drawGrid():
        pass
### BEGIN OF PROGRAM


screen.fill(WHITE)
drawGrid()
putPixel((2,2), BLACK)


running = True


while running:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            running = False
            break
    pg.display.update()


exit()

2. Кривые Безье

Определение кубической кривой Безье:
Пусть даны три точки P0, P1, P2, P3, тогда кривая Безье, построенная по этим трём точкам - это множество точек, получаемые подстановкой 0 ≤ t ≤ 1 в следующую функцию:
(1 - t)P0 + 3(1 - t)2t P1 + 3(1 - t)t2 P2 + t3 P3

Оказывается кривые Безье обладают свойством: их можно разбить на две меньшие кривые Безье, подставив t = 0.5 (точка разбиения).
(А именно, кривые c точками A0, A1, A2, A3 и B0, B1, B2, B3, где
A0 = P0; A1 = P0/2 + P1/2; A2 = P0/4 + 2*P1/4 + P2/4;  A3 = P0/8 + 3*P1/8 + 3*P2/8 + P3/8, аналогично для Bi.
Предлагается показать, что
(1 - t)P0 + 3(1 - t)2t P1 + 3(1 - t)tP2 + tP3 при 0 ≤ t ≤ 0.5 то же и самое, что и
(1 - t)P0 + 3(1 - t)2t (P0 + P1)/2 + 3(1 - t)t2 (P0 + 2*P1 + P2)/4 + t3 (P0 + 3*P1 + 3*P2 + P3)/8 при 0 ≤ t ≤ 1. Для этого можно показать, что
(1 - 2t)P0 + 3(1 - 2t)22t (P0 + P1)/2 + 3(1 - 2t)(2t)2 (P0 + 2*P1 + P2)/4 + (2t)(P0 + 3*P1 + 3*P2 + P3)/8) при 0 ≤ t ≤ 0.5 (случилась замена переменных с t на 2t) равно (1 - t)P0 + 3(1 - t)2t P1 + 3(1 - t)tP2 + tP3 при 0 ≤ t ≤ 0.5 )

Таким образом, отрисовку кривой Безье можно свести к отрисовке двух меньших кривых Безье (которые, в свою очередь, можно свести к отрисовке четырёх ещё меньших и т.д.), а при достаточно близких точках допустимо нарисовать 3 отрезка, проходящие через точки построения.

3. Отрисовка отрезков и окружностей

Для отрисовки отрезков будем пользоваться алгоритмом, который делает следующее:
Выбирает в каждом столбце ту клетку, которая ближе в прямой.

Для определения, какая точка ближе, будем делать следующее (для описания алгоритма будем считать, что dx, dy > 0 и dx > dy, где dx, dy - разница координат начала и конца отрезка. Все остальные случаи описываются симметрично):
1. Начнём с клетки начала отрезка (x_0, y_0), пройдём на 1 клетку по направлению x и рассмотрим пересечение отрезка с прямой, параллельной оси y, проходящей через середину клетки, в которую мы прошли. Заметим, что координата y у пересечения изменилась на dy/dx по сравнению с серединой начальной точки. Таким образом, для того, чтобы понять, какая из двух клеток во втором столбце ближе к отрезку, нужно сравнить dy/dx с 1/2. Далее, пройдя ещё на 1 клетку по направлению x, нужно сравнивать уже 2dy/dx с 1/2
2. В некоторый момент случится так, что k*dy/dx станет больше 1. Тогда это будет означать, что мы достаточно продвинулись по отрезку, и теперь нужно выбирать не между точками с координатами y_0 и y_0 + 1, а между y_0 + 1 и y_0 + 2 (и соотв. сравнивать с 3/2). Можно в таком случае сравнивать k*dy/dx - 1 с 1/2.
Этот алгоритм продолжается, пока мы не окажемся в конечной точке.
3. Идея: предлагается домножить все дробные вычисления на 2*dx, тогда мы получим:
Сначала сравниваем 2*dy с dx, после 4*dy с dx ... когда k*dy становится больше, чем 2*dx, мы вычитаем 2*dx (и смещаемся на 1 по y). Таким образом, все вычисления целочисленные, и не возникает проблемы с накоплением ошибки. (Также предлагается вычесть dx, чтобы сравнение происходило с 0, но в таком случае для вычитания 2*dx нужно сравнивать с dx)

Для окружностей будем делать аналогично, только со следующей оговоркой:
Применим этот алгоритм для одной "восьмой" окружности, а остальные "восьмые" нарисуем симметрично.
На примере восьмой в первой четверти, которая ближе к оси y:
Начнём с верхней клетки и сдвинемся на 1 по оси x. Тогда для определения того, какую из двух клеток нужно отрисовать, будем рассматривать точку на середине общей стороны
(если середины (x_0 + 1; y_0) и (x_0 + 1; y_0 - 1), то серединой общей стороны будет точка (x_0 + 1; y_0 - 1/2) )
и в зависимости от того, находится ли эта точка в окружности, выбирать клетку. Если точка внутри окружности, выбираем нижнюю клетку (и после этого будем сравнивать клетки с координатами y на 1 меньше), если же снаружи, то верхнюю. Определить, находится ли точка снаружи или внутри можно по т. Пифагора (у нас должен быть дан квадрат радиуса окружности для отрисовки). 


СГЛАЖИВАНИЕ

Для сглаживания будем отрисовывать не один пиксель строго чёрным цветом, а два пикселя, но в разные оттенки серого. Удобно рассматривать оттенки серого в контексте интенсивности чёрного: белый цвет (255, 255, 255) будет интенсивности 0%, черный (0, 0, 0)  -- 100%, а цвета (63, 63, 63) и (127, 127, 127) -- 75% и 50% соответственно.
Тогда будем считать, что отношение интенсивностей должно быть обратно пропорционально равно отношению расстояний. К примеру, если отношение расстояний 1:3, то ближний пиксель будет закрашен с интенсивностью 75%, а дальний -- 25%.