This repository has been archived on 2025-05-08. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
Fractals/flowsnake_colors.py

152 lines
4.5 KiB
Python

from typing import List
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from vector import *
FS_VECTOR = Vector(1, 0) + Vector(1, -60) + Vector(1, -180) + Vector(1, -120) + Vector(2, 0) + Vector(1, 60)
class Line:
def __init__(self, vector: Vector, variant: bool):
self.vector = vector
self.variant = variant
def flowsnake(self) -> list:
out = []
d = self.vector.distance / FS_VECTOR.distance
a = (self.vector.angle - FS_VECTOR.angle) % 360
if self.variant:
out.append(Line(Vector(d, a), True))
a -= 60
out.append(Line(Vector(d, a), False))
a -= 120
out.append(Line(Vector(d, a), False))
a += 60
out.append(Line(Vector(d, a), self.variant))
a += 120
out.append(Line(Vector(d, a), True))
out.append(Line(Vector(d, a), True))
a += 60
out.append(Line(Vector(d, a), False))
else:
a += 60
out.append(Line(Vector(d, a), True))
a -= 60
out.append(Line(Vector(d, a), False))
out.append(Line(Vector(d, a), False))
a -= 120
out.append(Line(Vector(d, a), self.variant))
a -= 60
out.append(Line(Vector(d, a), True))
a += 120
out.append(Line(Vector(d, a), True))
a += 60
out.append(Line(Vector(d, a), False))
return out
class FlowSnake(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Flow Snake - Iteration 0")
self.setFixedSize(650, 650)
self.iterations = [[Line(Vector(480, FS_VECTOR.angle + 90), True)]]
self.current_iteration = 0
self.points = []
self.prepare_drawing()
for i in range(4):
self.next()
self.show()
def keyPressEvent(self, e: QKeyEvent):
if e.key() == Qt.Key_Q:
self.close()
elif e.key() == Qt.Key_Right:
self.next()
elif e.key() == Qt.Key_Left:
self.prev()
def prev(self):
if self.current_iteration > 0:
self.current_iteration -= 1
self.setWindowTitle(f"Flow Snake - Iteration {self.current_iteration}")
self.repaint()
def next(self):
if self.current_iteration < 7:
self.current_iteration += 1
if len(self.iterations) <= self.current_iteration:
self.iterations.append(self.flowsnake(self.iterations[-1]))
self.prepare_drawing()
self.setWindowTitle(f"Flow Snake - Iteration {self.current_iteration}")
self.repaint()
@staticmethod
def flowsnake(fs: List[Line]) -> List[Line]:
out = []
for line in fs:
out += line.flowsnake()
return out
def prepare_drawing(self):
lines = self.iterations[self.current_iteration]
p = Point(0, 0)
minx, miny = maxx, maxy = p
points = [p]
for line in lines:
p += line.vector.to_point()
minx = min(p.x, minx)
miny = min(p.y, miny)
maxx = max(p.x, maxx)
maxy = max(p.y, maxy)
points.append(p)
midpoint = Point((maxx + minx) / 2, (maxy + miny) / 2)
midpoint = Point(self.width() / 2, self.height() / 2) - midpoint
self.points.append([p + midpoint for p in points])
def paintEvent(self, e: QPaintEvent):
qp = QPainter(self)
col = QColor("#111111")
qp.setPen(col)
qp.setBrush(col)
qp.drawRect(self.rect())
colors = [
0xff0000,
0xffff00,
0x008800,
0x00ffff,
0x0000ff,
]
points = self.points[self.current_iteration]
lines = len(points) - 1
for i, (p1, p2) in enumerate(zip(points[:-1], points[1:])):
p = i / lines
c = p * (len(colors) - 1)
color = int(c)
p = c - int(c)
color1 = [colors[color] >> j & 0xff for j in range(16, -1, -8)]
color2 = [colors[color + 1] >> j & 0xff for j in range(16, -1, -8)]
qp.setPen(QPen(QColor(
round(color1[0] * (1 - p) + color2[0] * p),
round(color1[1] * (1 - p) + color2[1] * p),
round(color1[2] * (1 - p) + color2[2] * p)
), 1))
qp.drawLine(*p1, *p2)
if __name__ == '__main__':
app = QApplication([])
flowsnake = FlowSnake()
app.exec_()