見出し画像

Processing でグラフを描く④ 極座標(螺旋と2次曲線)

Processing でグラフを描く 第4回目になります。
いままでは直交座標系を使って、グラフを描いてきました。今回は「極座標」といわれる別の座標系でグラフを描いていきます。我々は「直交座標系」に慣れているので、初めはとっつきにくいかもしれませんが、慣れたら簡単です。座標系は無数にあり、描きたい図形によって便利な座標系を選べばよいのです。
では早速始めましょう。

極座標を描く

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 = []


def setup():
    global points
    size(SIZE, SIZE)
    # グラフのデータ
    points = []


def draw():
    background(BACKGROUND_COLOR)
    noFill()
    strokeWeight(2)
    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)
    popMatrix()
polar coordinate

極座標を描いてみると、なにか見たことのある図形が現れました。戦争物の映画などに出てくる「レーダー」と同じです。「20時の方向、距離500、敵影発見!」なんてセリフを聞いたことがあると思います。

極座標は自分の位置を基準(原点)として、長さと方角で位置を示します。直感的に位置を捉えられるという特徴があります。戦闘機や艦船の位置表示に使われるのは、そのためです。

直交座標と極座標の相互変換

def draw():
    background(BACKGROUND_COLOR)
    noFill()
    strokeWeight(2)
    stroke(0, 255, 0, 50)
    for i in range(int(SIZE / STEP)):
        line(-2000, i * STEP, 2000, i * STEP)
        line(i * STEP, -2000, i * STEP, 2000)
    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)
    # 直交座標との相互変換
    fill(colors[1][0], colors[1][1], colors[1][2])
    noStroke()
    ellipse(375 * cos(radians(30)), -375 * sin(radians(30)), 10, 10)
    stroke(colors[0][0], colors[0][1], colors[0][2])
    noFill()
    line(0, 0, 375 * cos(radians(30)), -375 * sin(radians(30)))
    stroke(colors[0][0], colors[0][1], colors[0][2], 100)
    line(375 * cos(radians(30)), 0, 375 * cos(radians(30)), -375 * sin(radians(30)))
    line(0, -375 * sin(radians(30)), 375 * cos(radians(30)), -375 * sin(radians(30)))
    arc(0, 0, 110 * 2, 110 * 2, radians(330), radians(360))
    fill(255)
    textSize(40)
    text('y', 10, -200)
    text('x', 330, -10)
    text('r', 150, -100)
    text(u'\u03B8', 110, -20)
    popMatrix()
polar and cartesian

直交座標系と極座標系の相互変換を考えてみます。2次元平面上の位置を表すには2つの値が必要です。直交座標系では「長さ2つ」で、極座標系では「長さと角度」で位置を指定します。
極座標を直交座標に変換

$$
x = r cos(\theta)\\
y = r sin(\theta)
$$

直交座標を極座標に変換

$$
r = \sqrt{x^2 + y^2}\\
tan(\theta) = \frac{y}{x}
$$

アルキメデスの螺旋(らせん)を描く

def setup():
    global points
    size(SIZE, SIZE)
    # グラフのデータ
    points = [
        [archimedean_spiral(i, 1.0 / 2) for i in range(360 * 4)],
        [archimedean_spiral(i, 2.0 / 3) for i in range(360 * 4)],
        [archimedean_spiral(i, 1) for i in range(360 * 4)],
        [archimedean_spiral(i, 3.0 / 2) for i in range(360 * 4)],
        [archimedean_spiral(i, 2) for i in range(360 * 4)],
    ]


def draw():
    background(BACKGROUND_COLOR)
    noFill()
    strokeWeight(2)
    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)
    # グラフを描く
    count = min(frameCount - 1, 360 * 4 - 1)
    for j, p in enumerate(points):
        stroke(colors[j][0], colors[j][1], colors[j][2])
        for i in range(count):
            r1 = p[i]
            x1 = r1 * cos(radians(i))
            y1 = r1 * sin(radians(i))
            r2 = p[i + 1]
            x2 = r2 * cos(radians(i + 1))
            y2 = r2 * sin(radians(i + 1))
            line(x1, -y1, x2, -y2)
        else:
            stroke(colors[0][0], colors[0][1], colors[0][2], 50)
            line(0, 0, 1000 * cos(radians(i)), -1000 * sin(radians(i)))
    popMatrix()


def archimedean_spiral(degree_angle, a):
    return a * radians(degree_angle) * STEP
archimedean_spiral

アルキメデスの螺旋(渦巻線)は、極座標で描くことができる有名な図形です。$${r = a \theta  (a > 0, \theta \geqq 0)}$$ で定義されます。グラフは、a の値を $${\frac{1}{2}, \frac{2}{3}, 1, \frac{3}{2}, 2}$$ に変化させて、5本の線を描きました。

 2次曲線を描く

def setup():
    global points
    size(SIZE, SIZE)
    frameRate(5)
    # グラフのデータ
    for j in range(100):
        points.append(
            [quadratic_curve(i, RADIUS, j * 0.1) for i in range(360)]
        )


def draw():
    background(BACKGROUND_COLOR)
    noFill()
    strokeWeight(2)
    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)
    # グラフを描く
    count1 = min(frameCount - 1, len(points) - 1)
    p = points[count1]
    stroke(colors[0][0], colors[0][1], colors[0][2])
    for i in range(360 - 1):
        r1 = p[i]
        x1 = r1 * cos(radians(i))
        y1 = r1 * sin(radians(i))
        r2 = p[i + 1]
        x2 = r2 * cos(radians(i + 1))
        y2 = r2 * sin(radians(i + 1))
        if abs(r1) < height and abs(r2) < height:
            line(x1, -y1, x2, -y2)
    popMatrix()


def quadratic_curve(i, l, e):
    try:
        return float(l) / (1 + e * cos(radians(i)))
    except ZeroDivisionError:
        return 10**10
quadratic curve

2次曲線とは「円、楕円、放物線、双曲線」の総称です。極座標を使うと、2次曲線を1つの式で表すことができます。一見バラバラなグラフが一つの式で示せるなんて驚きです。これぞ数学の醍醐味といえるでしょう。

$$
r = \frac{l}{ 1 + e cos{\theta}}\\
e = 0 のとき 円\\
0 < e < 1 のとき 楕円\\
e = 1 のとき 放物線\\
1 < e のとき 双曲線
$$

どうも信用できないので、Processing で検証してみました。その結果のグラフを示します。定義通り、「円、楕円、放物線、双曲線」を描くことができました。(定義の中に cos が含まれているため、横向きに移動します。では sin に変えてみたら?)
グラフだと直感的に定義を捉えることができます。ただし厳密に証明するのは数式の変形が必要になります。たとえば、e = 0 のとき、確かに「円」のように見えますが、本当に「円」であるかはわからないですね。
この記事で数式を変形して、定義が正しいことを示すこともできますが、力尽きてしまいました。数式による証明は読者諸氏にお任せすることにいたしましょう。以上で「極座標」を終わります。


前の記事
Processing でグラフを描く③ 円と楕円
次の記事
Processing でグラフを描く⑤ バラ曲線

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


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