2026年8月24日月曜日

師匠の難題1

 ではいきなりソースコード。

ソースここから

import pyxel

class Bresenham:
    
    def __init__(self):
        self.l_side = 0
        self.s_side = 0
        self.counter = 0
        self.adder = 0

    # 長辺、短辺を入力
    def setup(self,l_side,s_side):
        self.l_side = l_side+1
        self.s_side = s_side+1
        return self.l_side
        
    # 現在の短辺の位置を返し、次の短辺の位置を計算
    def step(self):
        ret = self.adder
        self.counter += self.s_side
        i = self.counter - self.l_side
        if i >= 0:
            self.counter = i
            self.adder += 1
        return ret

class App:

    def __init__(self):
        # 画面サイズ 160x120 で初期化
        pyxel.init(160, 120, title="RollBlt")
        self.add_x = 0
        pyxel.load("yajirushi.pyxres")
        
        pyxel.run(self.update, self.draw)

    def update(self):
        # 処理の都合上制限をかけている
        if pyxel.btn(pyxel.KEY_LEFT):
            self.add_x -= 1
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.add_x += 1
        if self.add_x < 0:
            self.add_x = 0
        if self.add_x > 15:
            self.add_x = 15

    def draw(self):
        # 画面を黒(色番号0)でクリア
        pyxel.cls(0)

        bre = Bresenham()
        rag = bre.setup(l_side=15,s_side=self.add_x)

        for y in range (rag):
            add_x = bre.step()
            for x in range (32):
                pyxel.blt(80+add_x + x, 60 + y, 0, x, y, 1, 1)

App()

ソースここまで

そして実行結果
なんだか、斜めにずれていきます。
今回の主役はこの斜めを作るアルゴリズム…ブレゼンハムアルゴリズムです。
まあ、検索すればいくらでも解説が出てくる古典の描画アルゴリズムですが…
基本、こんな感じ。
カウンター0から、長辺方向(この場合は横)に向けて短辺の数(この場合は3)を足していく。で、カウンターが長辺より大きくなったら、カウンターの値を長辺の数(この場合は5)引いて次の描画の際に1段ずらす…以後繰り返し。

はえー、昔の人は賢いな…と、思うのですが原理は簡単です。
小学生が掛け算を習う際に、掛け算とは一方の数をもう一方の数の分だけ足したものと習います。
短編の数を長辺の数分足しているのですから、長辺で引く部分を除いたカウンターの総和は短辺と長辺をかけたもの(この場合は15)となり、当然、その数は長辺で割り切れて、割った答えは短辺。
カウンターの最終値になるまでに長辺で割り切れる回数は当然短辺と同じ(この場合3回)。
では、その割り切れるタイミングは?
…と考えれば理解が早いと思います。

ただし、このプログラムは穴だらけ
Pyxel 座標系はこんな感じ(右方向がXの正の方向、下方向がYの正の方向)ですが。今回のアルゴリズムは長辺>短辺かつ、どちらもプラス方向に値が加算される前提で組まれています。

※中心から各方向へ延ばしたベクトルのX、Y要素の関係

具体的には45度しかカバーできていません。
次回は、ちゃんとした2次元ベクトル上のブレゼンハムクラスを作って、直線を引くプログラムを書いていきます。

0 件のコメント:

コメントを投稿