見出し画像

Processing でグラフを描く⑥ バラ曲線とジェネラティブアート

Processing でグラフを描く 第6回目です。
第5回 バラ曲線」を描いてみて楽しかったので、もう少し掘り下げようと考えました。バラ曲線の定義を拡張して、ジェネラティブアート作りに挑戦します。
ジェネラティブアートとは、コンピュータの計算能力を生かした芸術作品のことです。数式や乱数などを使って、無限のバリエーションを生む意外性のある作品が生成(generate)されます。
バラ曲線と組み合わせるとどんな作品が出てくるでしょうか。お楽しみに!(完成コードを公開しているので、Processing3 (Python mode) に貼り付けると、ご自分のパソコンで実行できます。)

バラ曲線(n / m = 1.0 〜 0.1)

BACKGROUND_COLOR = color(0, 44, 77)
colors = [
    [255, 255, 255],  # white
    [255, 127, 0],  # orange
    [255, 0, 255],  # magenta
    [127, 127, 255],  # lightblue
    [255, 255, 0],  # yellow
    [0, 255, 0],  # lime
    [255, 127, 127],  # pink
    [127, 127, 127],  # gray
    [191, 191, 191],  # lightgray
    [0, 255, 255],  # cyan
    [127, 0, 127],  # purple
    [0, 0, 255],  # blue
    [127, 0, 0],  # brown
    [0, 127, 0],  # green
    [255, 0, 0],  # red
    [0, 0, 0],  # black
]
SIZE = 1000
STEP = 50
RADIUS = 300
points = []
sin_wave = [sin(radians(i)) for i in range(360)]


def setup():
    global points
    size(SIZE, SIZE)


def draw():
    background(BACKGROUND_COLOR)
    noFill()
    strokeWeight(1)
    pushMatrix()
    translate(width / 2, height / 2)
    stroke(0, 255, 0, 50)
    for i in range(0, 360, 15):
        line(0, 0, 1000 * cos(radians(i)), 1000 * sin(radians(i)))
    for i in range(1, 1000, STEP):
        ellipse(0, 0, i * 2, i * 2)
    stroke(0, 255, 0)
    line(-2000, 0, 2000, 0)
    line(0, -2000, 0, 2000)
    # グラフを描く
    p_length = len(sin_wave)
    # バラ曲線
    j = min(frameCount + 9, 100)
    p = 10.0 / j
    count1 = 360 * 100
    stroke(colors[0][0], colors[0][1], colors[0][2])
    for i in range(count1):
        r1 = sin_wave[i % p_length] * RADIUS
        x1 = r1 * cos(radians(i) / float(p))
        y1 = r1 * sin(radians(i) / float(p))
        r2 = sin_wave[(i + 1) % p_length] * RADIUS
        x2 = r2 * cos(radians(i + 1) / float(p))
        y2 = r2 * sin(radians(i + 1) / float(p))
        line(x1, -y1, x2, -y2)
    popMatrix()
rose curve m from 1.0 to 10.0

バラ曲線の定義は $${r = a sin{\frac{n}{m}\theta}}$$ で与えられます。$${n / m}$$ の値を $${1 / 1.0}$$ から $${1 / 10.0}$$ まで分母を 0.1刻みで変化させてグラフ化してみました。細胞が分裂を繰り返すような面白い変化ですね。

バラ曲線(n / m = 1.0 〜 10.0)

# p = 10.0 / j
p = j / 10.0
rose curve n from 1.0 to 10.0

コードの変更箇所は、p の値を逆数に定義し直すだけです。$${n / m}$$ の値を 1.0 から 10.0 まで 0.1刻みで変化させてグラフ化してみました。こちらは花びらの枚数が変化する図形が描けました。

拡張バラ曲線の定義

$$
r = a \frac{sin{\frac{n}{m}\theta} + b}{1 + b}  (n > 0, m > 0, a > 0, b \geqq 0)
$$

バラ曲線を定義し直しました。b の値によって、新しいグラフを描くことができます。b = 0 のとき、今まで通りのバラ曲線になるため、バラ曲線の基本形を含んでいます。よってこの新しい定義を「拡張バラ曲線」と名付けます。(この記事の独自定義です。)

def draw():
    background(BACKGROUND_COLOR)
    noFill()
    strokeWeight(1)
    pushMatrix()
    translate(width / 2, height / 2)
    stroke(0, 255, 0, 50)
    for i in range(0, 360, 15):
        line(0, 0, 1000 * cos(radians(i)), 1000 * sin(radians(i)))
    for i in range(1, 1000, STEP):
        ellipse(0, 0, i * 2, i * 2)
    stroke(0, 255, 0)
    line(-2000, 0, 2000, 0)
    line(0, -2000, 0, 2000)
    # グラフを描く
    p_length = len(sin_wave)
    # バラ曲線
    b = min(frameCount - 1, 100) / 10.0
    stroke(colors[0][0], colors[0][1], colors[0][2], 50)
    center_radius = float(b * RADIUS) / (1 + b)
    ellipse(0, 0, center_radius * 2, center_radius * 2)
    j = 80
    # p = 10.0 / j
    # p = j / 10.0
    count1 = 360 * 100
    stroke(colors[0][0], colors[0][1], colors[0][2])
    for i in range(count1):
        # r1 = sin_wave[i % p_length] * RADIUS
        r1 = (sin_wave[i % p_length] + b) * RADIUS / float(1 + b)
        x1 = r1 * cos(radians(i) * p)
        y1 = r1 * sin(radians(i) * p)
        # r2 = sin_wave[(i + 1) % p_length] * RADIUS
        r2 = (sin_wave[(i + 1) % p_length] + b) * RADIUS / float(1 + b)
        x2 = r2 * cos(radians(i + 1) * p)
        y2 = r2 * sin(radians(i + 1) * p)
        line(x1, -y1, x2, -y2)
    popMatrix()
expanded rose curve

b の値を 0 から 10.0 まで 0.1刻みで増加させて、グラフを描きます。b < 1 のとき、8枚の花びらが縮みます。1 < b になると、中央に空間ができます。最後はアメーバみたいな形になりました。

ジェネラティブアート(拡張バラ曲線)

BACKGROUND_COLOR = color(0, 44, 77)
SIZE = 800
STEP = 40
RADIUS = 300
sin_wave = [sin(radians(i)) for i in range(360)]


def setup():
    size(SIZE, SIZE)


def draw():
    colorMode(RGB)
    background(BACKGROUND_COLOR)
    noFill()
    strokeWeight(1)
    pushMatrix()
    translate(width / 2, height / 2)
    p_length = len(sin_wave)
    # バラ曲線
    b = 2 * noise(frameCount * 0.05)
    j = 400 * noise(frameCount * 0.05)
    p = 10.0 / j
    count1 = 360 * 100
    colorMode(HSB, 100)
    for i in range(count1):
        stroke((i / 100.0) % 100, 100, 100)
        r1 = (sin_wave[i % p_length] + b) * RADIUS / float(1 + b)
        x1 = r1 * cos(radians(i) / float(p))
        y1 = r1 * sin(radians(i) / float(p))
        r2 = (sin_wave[(i + 1) % p_length] + b) * RADIUS / float(1 + b)
        x2 = r2 * cos(radians(i + 1) / float(p))
        y2 = r2 * sin(radians(i + 1) / float(p))
        line(x1, -y1, x2, -y2)
    popMatrix()
generative rose curve

拡張バラ曲線を使って、ジェネラティブアート作りに挑戦しました。noise関数を使って、フレームごとに$${b, n / m}$$ の値を少しずつ変化させたバラ曲線を描きます。colorMode を HSB に変更して、色を段階的に変化させる技法を使っています。

ジェネラティブアート(バラ曲線とフーリエ正弦級数)

SIZE = 800
flowers = []


class Flower:
    def __init__(self, a, b, c):
        self.position = [random(-width / 2, width / 2), random(-height / 2, height / 2)]
        self.color_id = int(random(255))
        self.radius = random(50, 150)
        self.points = [fourier_sine_series(i, a, b, c) for i in range(360 * 4)]
        self.rotate_angle = 0
        self.move_angle = random(360)

    def draw(self):
        pushMatrix()
        stroke(self.color_id, 100, 100)
        translate(self.position[0], self.position[1])
        for i in range(len(self.points) - 1):
            r1 = self.points[i] * self.radius
            x1 = r1 * cos(radians(i) + self.rotate_angle)
            y1 = r1 * sin(radians(i) + self.rotate_angle)
            r2 = self.points[i + 1] * self.radius
            x2 = r2 * cos(radians(i + 1) + self.rotate_angle)
            y2 = r2 * sin(radians(i + 1) + self.rotate_angle)
            line(x1, -y1, x2, -y2)
        popMatrix()

    def update(self):
        self.rotate_angle += radians(2) * 300 / self.radius
        self.position[0] += self.radius * sin(radians(self.move_angle)) / 10
        self.position[1] += self.radius * cos(radians(self.move_angle)) / 10
        if self.position[0] + self.radius < -width / 2 or width / 2 < self.position[0] - self.radius or \
                self.position[1] + self.radius < -height / 2 or height / 2 < self.position[1] - self.radius:
            self.position = [random(-250, 250), random(-250, 250)]


def setup():
    size(SIZE, SIZE)
    background(0)

    for _ in range(25):
        a = random(0.25, 0.3)
        b = random(0.12, 0.2)
        c = random(0.07, 0.1)
        # a, b, c = 0, 0, 0
        flowers.append(
            Flower(a, b, c)
        )


def draw():
    colorMode(RGB)
    fill(0, 150)
    rect(0, 0, width, height)
    colorMode(HSB)
    noFill()
    strokeWeight(1)
    pushMatrix()
    translate(width / 2, height / 2)
    for flower in flowers:
        flower.draw()
        flower.update()
    popMatrix()


def fourier_sine_series(i, a, b, c):
    i = radians(i)
    return sin(i * 4) + a * sin(i * 12) + b * sin(i * 20) + c * sin(i * 28)
generative rose curve2

バラ曲線の花びらを変形するため、「フーリエ正弦級数」を利用しました。Flowerクラスから、25個のインスタンスを作成し、回転させながら描画しました。移動して画面から出てしまったらランダムな位置にジャンプするようにしてみました。
結構いい感じになりましたが、もう少し手を加えたいところです。いいアイデアがあればコメントで教えてくださいね。

フーリエ正弦級数について参考にさせていただきました。ありがとうございます。
CinderellaJapan - 花の曲線を描く


前の記事
Processing でグラフを描く⑤ バラ曲線
次の記事
Processing でグラフを描く⑦ フーリエ級数

その他のタイトルはこちら


この記事が気に入ったらサポートをしてみませんか?