реализация
This commit is contained in:
parent
33d2fc169b
commit
236be7bb2a
16
README.md
16
README.md
|
|
@ -1 +1,15 @@
|
||||||
# grad
|
# Градиент, по параметрической кривой, реализованный путём интерполяции линейного оператора
|
||||||
|
## algebra.py:
|
||||||
|
### Vector
|
||||||
|
Реализация векторов, как элементов векторного пространства
|
||||||
|
### Poly
|
||||||
|
Реализация многочленов, как элементов кольца многочленов над полем
|
||||||
|
### Interpol
|
||||||
|
Интерполяция по методу Лагранжа
|
||||||
|
## window.py
|
||||||
|
### Окно Tk
|
||||||
|
- По нажатию ЛКМ отмечает на экране точку
|
||||||
|
- По нажатию space выставляет 5 случайных точек
|
||||||
|
- По нажатию esc очищает холст
|
||||||
|
## grad.py
|
||||||
|
По мажатию Enter выстраивает интерполяционный многочлен по заданным точкам, окрашивая кривую градиентом по случайным цветам в каждой из точек
|
||||||
166
algrebra.py
Normal file
166
algrebra.py
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
from typing import Union, List
|
||||||
|
|
||||||
|
class Vector:
|
||||||
|
def __init__(self, *comps):
|
||||||
|
self.len = len(comps)
|
||||||
|
self.comps = comps
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
if type(self) == type(other):
|
||||||
|
if self.len == other.len:
|
||||||
|
return Vector(*(self.comps[i] + other.comps[i] for i in range(self.len)))
|
||||||
|
else:
|
||||||
|
return "Длины должны совпадать"
|
||||||
|
|
||||||
|
def __sub__(self, other):
|
||||||
|
if type(self) == type(other):
|
||||||
|
if self.len == other.len:
|
||||||
|
return self + (-other)
|
||||||
|
else:
|
||||||
|
return "Длины должны совпадать"
|
||||||
|
|
||||||
|
def __neg__(self):
|
||||||
|
return Vector(*(-self.comps[i] for i in range(self.len)))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '(' + ', '.join(map(str, self.comps)) + ')'
|
||||||
|
|
||||||
|
def __mul__(self, other):
|
||||||
|
if type(other) == Vector:
|
||||||
|
if self.len == other.len:
|
||||||
|
return sum((self.comps[i]*other.comps[i] for i in range(self.len)))
|
||||||
|
else:
|
||||||
|
return "Длины должны совпадать"
|
||||||
|
if type(other) == int:
|
||||||
|
return Vector(*(self.comps[i] * other for i in range(self.len)))
|
||||||
|
|
||||||
|
def __round__(self):
|
||||||
|
return Vector(*(round(self.comps[i]) for i in range(self.len)))
|
||||||
|
|
||||||
|
def tuple(self):
|
||||||
|
return self.comps
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Poly:
|
||||||
|
def __init__(self, coefs: Union[List[int], int]):
|
||||||
|
|
||||||
|
if type(coefs) == int:
|
||||||
|
self.coefs = [coefs]
|
||||||
|
self.deg = 0
|
||||||
|
|
||||||
|
elif type(coefs) == list:
|
||||||
|
self.coefs = coefs
|
||||||
|
self.deg = len(coefs) - 1
|
||||||
|
|
||||||
|
def __neg__(self):
|
||||||
|
coefs = [-a for a in self.coefs]
|
||||||
|
|
||||||
|
return Poly(coefs)
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
if type(other) == int:
|
||||||
|
return self + Poly(other)
|
||||||
|
|
||||||
|
if type(other) == Vector:
|
||||||
|
new_comps = []
|
||||||
|
for com in other.comps:
|
||||||
|
new_comps.append(self + com)
|
||||||
|
|
||||||
|
return Vector(*new_comps)
|
||||||
|
|
||||||
|
if type(other) == Poly:
|
||||||
|
p = self.coefs + [0]*other.deg
|
||||||
|
q = other.coefs + [0]*self.deg
|
||||||
|
|
||||||
|
n = max(self.deg, other.deg)
|
||||||
|
result = [0]*n
|
||||||
|
|
||||||
|
for k in range(n):
|
||||||
|
result[k] = p[k] + q[k]
|
||||||
|
|
||||||
|
return Poly(result)
|
||||||
|
|
||||||
|
def __sub__(self, other):
|
||||||
|
return self + (-other)
|
||||||
|
|
||||||
|
def __mul__(self, other):
|
||||||
|
if type(other) == int:
|
||||||
|
coefs = [other*a for a in self.coefs]
|
||||||
|
|
||||||
|
return Poly(coefs)
|
||||||
|
|
||||||
|
elif type(other) == Vector:
|
||||||
|
new_coms = []
|
||||||
|
|
||||||
|
for com in other.comps:
|
||||||
|
new_coms.append(self * com)
|
||||||
|
|
||||||
|
return Vector(*new_coms)
|
||||||
|
|
||||||
|
elif type(other) == Poly:
|
||||||
|
n = self.deg
|
||||||
|
m = other.deg
|
||||||
|
p = list(self.coefs) + [0] * other.deg
|
||||||
|
q = list(other.coefs) + [0] * self.deg
|
||||||
|
result = [0]*(self.deg + other.deg + 1)
|
||||||
|
|
||||||
|
for k in range(self.deg + other.deg + 1):
|
||||||
|
for l in range(k + 1):
|
||||||
|
result[k] += p[l]*q[k-l]
|
||||||
|
|
||||||
|
return Poly(result)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
res = []
|
||||||
|
for i in range(self.deg+1):
|
||||||
|
if self.coefs[i] == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if i == 0:
|
||||||
|
res.append(f"({self.coefs[i]})")
|
||||||
|
elif i == 1:
|
||||||
|
res.append(f"({self.coefs[i]}*x)")
|
||||||
|
else:
|
||||||
|
res.append(f"({self.coefs[i]}*x^{i})")
|
||||||
|
return ' + '.join(res)
|
||||||
|
|
||||||
|
def value(self, t):
|
||||||
|
res = 0
|
||||||
|
for i in range(self.deg+1):
|
||||||
|
res += self.coefs[i]*(t**i)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def diff(self):
|
||||||
|
if self.deg > 0:
|
||||||
|
coefs = [self.coefs[i] * i for i in range(1, self.deg + 1)]
|
||||||
|
return Poly(coefs)
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def interpol(points: List[tuple]) -> Poly:
|
||||||
|
n = len(points)
|
||||||
|
|
||||||
|
X = tuple(point[0] for point in points)
|
||||||
|
Y = tuple(point[1] for point in points)
|
||||||
|
|
||||||
|
res = Poly([0]*n)
|
||||||
|
|
||||||
|
for i in range(n):
|
||||||
|
iter = Poly([0]*n)
|
||||||
|
iter.coefs[0] = 1
|
||||||
|
|
||||||
|
for j in range(n):
|
||||||
|
if i==j:
|
||||||
|
continue
|
||||||
|
|
||||||
|
dx = 1/(X[i] - X[j])
|
||||||
|
iter = iter * Poly([-X[j]*dx, dx])
|
||||||
|
|
||||||
|
res = res + (iter * Y[i])
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
97
grad.py
97
grad.py
|
|
@ -1,22 +1,81 @@
|
||||||
from vector import Vector
|
from algrebra import *
|
||||||
from typing import Tuple, List
|
from window import window
|
||||||
|
from random import randint
|
||||||
|
|
||||||
def interpol(points: List[Tuple[int]]) -> List[Tuple[int]]:
|
|
||||||
n = len(points)
|
|
||||||
X = tuple(point[0] for point in points)
|
def color_filter(color):
|
||||||
Y = tuple(point[1] for point in points)
|
result = []
|
||||||
graph = []
|
for el in color:
|
||||||
for t in range(points[0][0], points[n-1][0]+1):
|
if (el < 0):
|
||||||
y = 0
|
result.append(0)
|
||||||
for i in range(n):
|
elif (el > 255):
|
||||||
q = Y[i]
|
result.append(255)
|
||||||
for j in range(n):
|
else:
|
||||||
if j != i:
|
result.append(round(el))
|
||||||
q = q * (t-X[j]) / (X[i] - X[j])
|
return tuple(result)
|
||||||
y = y + q
|
|
||||||
graph.append((t, y))
|
|
||||||
return graph
|
def rgb_to_hex(color):
|
||||||
|
r, g, b = color
|
||||||
|
return f'#{r:02x}{g:02x}{b:02x}'
|
||||||
|
|
||||||
|
|
||||||
|
def main(wind):
|
||||||
|
L = interpol(wind.points)
|
||||||
|
dL = L.diff()
|
||||||
|
N = len(wind.points)
|
||||||
|
perp = []
|
||||||
|
|
||||||
|
for p in wind.points:
|
||||||
|
k = dL.value(p[0])
|
||||||
|
if k==0:
|
||||||
|
wind.canvas.create_line(p[0], 0, p[0], wind.height, fill=rgb_to_hex((0, 0, 0)))
|
||||||
|
else:
|
||||||
|
k = -1/k
|
||||||
|
b = p[1] - k*p[0]
|
||||||
|
perp.append(Poly([b, k]))
|
||||||
|
|
||||||
|
colors = [(0, Vector(0, 0, 0))]
|
||||||
|
for i in range(N):
|
||||||
|
colors.append((wind.points[i][0], Vector(randint(0, 255), randint(0, 255), randint(0, 255))))
|
||||||
|
colors.append((width, Vector(255, 255, 255)))
|
||||||
|
|
||||||
|
color_func = interpol(colors).tuple()
|
||||||
|
|
||||||
|
step = 0.5
|
||||||
|
for dx in range(round(width/step)):
|
||||||
|
x=dx*step
|
||||||
|
color = color_filter(comp.value(x) for comp in color_func)
|
||||||
|
print(x, color)
|
||||||
|
"""
|
||||||
|
k = dL.value(x)
|
||||||
|
if k == 0:
|
||||||
|
wind.canvas.create_line(x, L.value(x), x+1, L.value(x+1), fill=rgb_to_hex(color))
|
||||||
|
else:
|
||||||
|
k = -1/k
|
||||||
|
b = L.value(x) - k*x
|
||||||
|
for y in range(width*2):
|
||||||
|
wind.canvas.create_line(y/2, k*y/2+b, y/2+1, k*(y/2+1)+b, fill=rgb_to_hex(color))
|
||||||
|
"""
|
||||||
|
wind.canvas.create_line(x, L.value(x), x+step, L.value(x+step), fill=rgb_to_hex((color)), width=5)
|
||||||
|
|
||||||
|
|
||||||
|
for i in range(N):
|
||||||
|
wind.canvas.create_oval(colors[i][0] - 3, L.value(colors[i][0]) - 3, colors[i][0] + 3, L.value(colors[i][0]) + 3, fill=rgb_to_hex(colors[i][1].tuple()))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
title = 'Huy'
|
||||||
|
width = 1000
|
||||||
|
height = 500
|
||||||
|
wind = window(title, width, height)
|
||||||
|
|
||||||
|
def on_enter_pressed(event):
|
||||||
|
main(wind)
|
||||||
|
|
||||||
|
wind.bind("<Return>", on_enter_pressed)
|
||||||
|
|
||||||
def main(points: List[Tuple[int]], colors: Tuple[Vector]) -> Tuple[int]:
|
wind.mainloop()
|
||||||
return ()
|
|
||||||
43
main.py
43
main.py
|
|
@ -1,43 +0,0 @@
|
||||||
import tkinter as tk
|
|
||||||
from grad import interpol
|
|
||||||
|
|
||||||
def rgb_to_hex(color):
|
|
||||||
r, g, b = color
|
|
||||||
return f'#{r:02x}{g:02x}{b:02x}'
|
|
||||||
|
|
||||||
# Создаем основное окно
|
|
||||||
root = tk.Tk()
|
|
||||||
root.title("Pixel Coloring")
|
|
||||||
|
|
||||||
# Устанавливаем размеры окна
|
|
||||||
width = 400
|
|
||||||
height = 400
|
|
||||||
|
|
||||||
# Создаем холст (Canvas) для рисования
|
|
||||||
canvas = tk.Canvas(root, width=width, height=height)
|
|
||||||
canvas.pack()
|
|
||||||
|
|
||||||
# Массив для хранения координат точек
|
|
||||||
points = []
|
|
||||||
|
|
||||||
# Функция, которая будет вызвана при нажатии Enter
|
|
||||||
def on_enter_pressed(event):
|
|
||||||
graph = interpol(points)
|
|
||||||
for x, y in graph:
|
|
||||||
canvas.create_line(x, y, x+1, y, fill=rgb_to_hex((0, 0, 0)))
|
|
||||||
|
|
||||||
# Функция, которая вызывается при нажатии мыши
|
|
||||||
def on_mouse_click(event):
|
|
||||||
x, y = event.x, event.y
|
|
||||||
points.append((x, y)) # Добавляем координаты в массив
|
|
||||||
print(f"Point added: ({x}, {y})")
|
|
||||||
# Рисуем точку на холсте
|
|
||||||
canvas.create_oval(x - 3, y - 3, x + 3, y + 3, fill="red")
|
|
||||||
|
|
||||||
# Привязываем события
|
|
||||||
canvas.bind("<Button-1>", on_mouse_click) # Левый клик мыши
|
|
||||||
root.bind("<Return>", on_enter_pressed) # Клавиша Enter
|
|
||||||
|
|
||||||
|
|
||||||
# Запускаем главный цикл обработки событий
|
|
||||||
root.mainloop()
|
|
||||||
39
vector.py
39
vector.py
|
|
@ -1,39 +0,0 @@
|
||||||
class Vector():
|
|
||||||
def __init__(self, *comps):
|
|
||||||
self.len = len(comps)
|
|
||||||
self.comps = comps
|
|
||||||
|
|
||||||
def __add__(self, other):
|
|
||||||
if type(self) == type(other):
|
|
||||||
if self.len == other.len:
|
|
||||||
return Vector(*(self.comps[i] + other.comps[i] for i in range(self.len)))
|
|
||||||
else:
|
|
||||||
return "Длины должны совпадать"
|
|
||||||
|
|
||||||
def __sub__(self, other):
|
|
||||||
if type(self) == type(other):
|
|
||||||
if self.len == other.len:
|
|
||||||
return Vector(*(self.comps[i] - other.comps[i] for i in range(self.len)))
|
|
||||||
else:
|
|
||||||
return "Длины должны совпадать"
|
|
||||||
|
|
||||||
def __neg__(self):
|
|
||||||
return Vector(*(-self.comps[i] for i in range(self.len)))
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '(' + ', '.join(map(str, self.comps)) + ')'
|
|
||||||
|
|
||||||
def __mul__(self, other):
|
|
||||||
if type(other) == Vector:
|
|
||||||
if self.len == other.len:
|
|
||||||
return sum((self.comps[i]*other.comps[i] for i in range(self.len)))
|
|
||||||
else:
|
|
||||||
return "Длины должны совпадать"
|
|
||||||
if type(other) == int:
|
|
||||||
return Vector(*(self.comps[i] * other for i in range(self.len)))
|
|
||||||
|
|
||||||
def __round__(self):
|
|
||||||
return Vector(*(round(self.comps[i]) for i in range(self.len)))
|
|
||||||
|
|
||||||
def tuple(self):
|
|
||||||
return self.comps
|
|
||||||
52
window.py
Normal file
52
window.py
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
import tkinter as tk
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
|
||||||
|
def rgb_to_hex(color):
|
||||||
|
r, g, b = color
|
||||||
|
return f'#{r:02x}{g:02x}{b:02x}'
|
||||||
|
|
||||||
|
def window(title, width, height):
|
||||||
|
# Создаем основное окно
|
||||||
|
root = tk.Tk()
|
||||||
|
root.title(title)
|
||||||
|
|
||||||
|
# Устанавливаем размеры окна
|
||||||
|
root.width = width
|
||||||
|
root.height = height
|
||||||
|
|
||||||
|
# Создаем холст (Canvas) для рисования
|
||||||
|
root.canvas = tk.Canvas(root, width=width, height=height)
|
||||||
|
root.canvas.pack()
|
||||||
|
|
||||||
|
# Массив для хранения координат точек
|
||||||
|
root.points = []
|
||||||
|
|
||||||
|
# Функция, которая вызывается при нажатии мыши
|
||||||
|
def on_mouse_click(event):
|
||||||
|
x, y = event.x, event.y
|
||||||
|
root.points.append((x, y)) # Добавляем координаты в массив
|
||||||
|
print(f"Point added: ({x}, {y})")
|
||||||
|
# Рисуем точку на холсте
|
||||||
|
root.canvas.create_oval(x - 3, y - 3, x + 3, y + 3, fill="red")
|
||||||
|
|
||||||
|
def on_esc_pressed(event):
|
||||||
|
root.points = []
|
||||||
|
root.canvas.delete("all")
|
||||||
|
|
||||||
|
def on_space_pressed(event):
|
||||||
|
on_esc_pressed(event)
|
||||||
|
|
||||||
|
for i in range(5):
|
||||||
|
x = randint(round(root.width * 0.2), round(root.width * 0.8))
|
||||||
|
y = randint(round(root.height * 0.2), round(root.height * 0.8))
|
||||||
|
root.points.append((x, y))
|
||||||
|
root.canvas.create_oval(x - 3, y - 3, x + 3, y + 3, fill="red")
|
||||||
|
|
||||||
|
|
||||||
|
# Привязываем события
|
||||||
|
root.canvas.bind("<Button-1>", on_mouse_click) # Левый клик мыши
|
||||||
|
root.bind("<space>", on_space_pressed)
|
||||||
|
root.bind("<Escape>", on_esc_pressed)
|
||||||
|
|
||||||
|
return root
|
||||||
Loading…
Reference in New Issue
Block a user