From b97737f6702b63304cb7b4c6bcff05e3137323c2 Mon Sep 17 00:00:00 2001 From: julius Date: Sun, 27 Oct 2024 21:43:34 +0100 Subject: [PATCH] add blobs --- background.py | 4 ++-- blob.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ speckles.py | 5 ++++- 3 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 blob.py diff --git a/background.py b/background.py index c160bff..92079e0 100644 --- a/background.py +++ b/background.py @@ -32,10 +32,10 @@ with open("popular.json", "r") as f: palettes += json.load(f) palette = random.choice(palettes) -enabled_markers = "otY+xP*" +enabled_markers = "otY+xP*b" markers = random.choices(enabled_markers, k=random.randint(1, len(enabled_markers))) for i, palette in enumerate(palettes): - colours = ["black"] + palette["colours"] + colours = ["none"] + palette["colours"] b = make_wallpaper( ",".join(colours), fileformat="png", diff --git a/blob.py b/blob.py new file mode 100644 index 0000000..9c85968 --- /dev/null +++ b/blob.py @@ -0,0 +1,57 @@ +import svg +from typing import Iterator, NamedTuple + +import numpy as np + +RGen = np.random.default_rng() + + +class Point(NamedTuple): + x: float + y: float + + +def iter_body_points(size: int) -> Iterator[Point]: + n_points = RGen.integers(3, 12) # how many points do we want? + angle_step = ( + np.pi * 2 / n_points + ) # step used to place each point at equal distances + for point_number in range(1, n_points + 1): + pull = 0.75 * RGen.random() * 0.25 + angle = point_number * angle_step + x = size + np.cos(angle) * size * pull + y = size + np.sin(angle) * size * pull + yield Point(x, y) + + +def spline(points: list[Point], body_tension: int) -> Iterator[svg.PathData]: + """ + https://github.com/georgedoescode/splinejs + """ + yield svg.MoveTo(*points[-1]) + first_point = points[0] + second_point = points[1] + points.insert(0, points[-1]) + points.insert(0, points[-2]) + points.append(first_point) + points.append(second_point) + for p0, p1, p2, p3 in zip(points, points[1:], points[2:], points[3:]): + yield svg.CubicBezier( + x1=p1.x + (p2.x - p0.x) / 6 * body_tension, + y1=p1.y + (p2.y - p0.y) / 6 * body_tension, + x2=p2.x - (p3.x - p1.x) / 6 * body_tension, + y2=p2.y - (p3.y - p1.y) / 6 * body_tension, + x=p2.x, + y=p2.y, + ) + + +def blob(x, y, c, s, body_tension: int = 1) -> svg.Path: + points = list(iter_body_points(s)) + return svg.Path( + d=list(spline(points, body_tension)), + fill=c, + stroke="#000000", + stroke_width=2, + transform=[svg.Translate(x-s, y-s)], + ) diff --git a/speckles.py b/speckles.py index 9b4042c..d0cc3d5 100644 --- a/speckles.py +++ b/speckles.py @@ -1,4 +1,5 @@ import itertools +from blob import blob import io from fastapi.responses import StreamingResponse from pathlib import Path @@ -66,7 +67,7 @@ class Include(svg.Element): return self.text -DEFINED = ".o+tYP-|sSex*" +DEFINED = ".o+tYP-|sSex*b" def markertoSVG(marker, x, y, c, s): @@ -203,6 +204,8 @@ def markertoSVG(marker, x, y, c, s): ) for angle in (0, 60, -60) ] + elif marker == "b": + return blob(x, y, c, np.sqrt(s)*10) else: return svg.Use( href=f"#{marker}",